<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="fr">
	<id>https://fr-wiki.metin2.gameforge.com/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Dexter</id>
	<title>Metin2 Wiki - Contributions de l’utilisateur [fr]</title>
	<link rel="self" type="application/atom+xml" href="https://fr-wiki.metin2.gameforge.com/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Dexter"/>
	<link rel="alternate" type="text/html" href="https://fr-wiki.metin2.gameforge.com/index.php/Sp%C3%A9cial:Contributions/Dexter"/>
	<updated>2026-06-03T01:41:59Z</updated>
	<subtitle>Contributions de l’utilisateur</subtitle>
	<generator>MediaWiki 1.31.5</generator>
	<entry>
		<id>https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Script/Calculator.js&amp;diff=108518</id>
		<title>MediaWiki:Script/Calculator.js</title>
		<link rel="alternate" type="text/html" href="https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Script/Calculator.js&amp;diff=108518"/>
		<updated>2026-04-15T17:59:59Z</updated>

		<summary type="html">&lt;p&gt;Dexter : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;function removeAccent(str) {&lt;br /&gt;
  return str.normalize(&amp;quot;NFD&amp;quot;).replace(/[\u0300-\u036f]/g, &amp;quot;&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function pseudoFormat(str) {&lt;br /&gt;
  return removeAccent(str).replace(/[^A-Za-z0-9 \(\)\+_-]+/g, &amp;quot;&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isValueInArray(value, array) {&lt;br /&gt;
  return array.indexOf(value) !== -1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function splitFirst(value, delimiter) {&lt;br /&gt;
  var parts = value.split(delimiter);&lt;br /&gt;
  var first = parts[0];&lt;br /&gt;
  var rest = parts.slice(1).join(delimiter);&lt;br /&gt;
  return [first, rest];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function copyObject(object) {&lt;br /&gt;
  var copy = {};&lt;br /&gt;
  for (var key in object) {&lt;br /&gt;
    copy[key] = object[key];&lt;br /&gt;
  }&lt;br /&gt;
  return copy;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function compareNumbers(a, b) {&lt;br /&gt;
  return b - a;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isChecked(attribute) {&lt;br /&gt;
  return attribute === &amp;quot;on&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function floorMultiplication(firstFactor, secondFactor) {&lt;br /&gt;
  return Math.floor((firstFactor * secondFactor).toFixed(8));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function truncateNumber(number, precision) {&lt;br /&gt;
  return Math.floor(number * 10 ** precision) / 10 ** precision;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function newChangeEvent() {&lt;br /&gt;
  return new Event(&amp;quot;change&amp;quot;, { bubbles: true });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function openTargetTab(target) {&lt;br /&gt;
  var tabberContainer = target.closest(&amp;quot;.tabber-container&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (!tabberContainer) {&lt;br /&gt;
    return;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var [buttonsContainer, tabsContainer] = tabberContainer.children;&lt;br /&gt;
  var buttons = buttonsContainer.children;&lt;br /&gt;
  var tabs = tabsContainer.children;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; tabs.length; index++) {&lt;br /&gt;
    var tab = tabs[index];&lt;br /&gt;
    if (tab.contains(target) &amp;amp;&amp;amp; !tab.checkVisibility()) {&lt;br /&gt;
      buttons[index].click();&lt;br /&gt;
      break;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function openTargetCollapsible(target) {&lt;br /&gt;
  var collapsible = target.closest(&amp;quot;.improved-collapsible&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (!collapsible) {&lt;br /&gt;
    return;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var span = collapsible.firstElementChild;&lt;br /&gt;
&lt;br /&gt;
  if (!span.classList.contains(&amp;quot;mw-collapsible-toggle-expanded&amp;quot;)) {&lt;br /&gt;
    span.click();&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function editTableResultRow(row, valuesToDisplay, numberFormat) {&lt;br /&gt;
  row.innerHTML = &amp;quot;&amp;quot;;&lt;br /&gt;
  for (var index = 0; index &amp;lt; valuesToDisplay.length; index++) {&lt;br /&gt;
    var cell = row.insertCell();&lt;br /&gt;
    var textContent;&lt;br /&gt;
&lt;br /&gt;
    if (index &amp;gt;= 3) {&lt;br /&gt;
      textContent = numberFormat.format(valuesToDisplay[index]);&lt;br /&gt;
    } else {&lt;br /&gt;
      textContent = valuesToDisplay[index];&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    cell.textContent = textContent;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return row;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addRowToTableResultHistory(&lt;br /&gt;
  tableResultHistory,&lt;br /&gt;
  valuesToDisplay,&lt;br /&gt;
  deleteFightTemplate,&lt;br /&gt;
  numberFormat&lt;br /&gt;
) {&lt;br /&gt;
  var row = tableResultHistory.insertRow();&lt;br /&gt;
  editTableResultRow(row, valuesToDisplay, numberFormat);&lt;br /&gt;
  var cell = row.insertCell();&lt;br /&gt;
  cell.appendChild(deleteFightTemplate.cloneNode(true));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function processSavedDamage(savedDamage, damageWeightedByType, battleValues) {&lt;br /&gt;
  const { damageTypeWeights, attackTypeMapping } = battleValues;&lt;br /&gt;
&lt;br /&gt;
  for (const key in savedDamage) {&lt;br /&gt;
    const [weight, damageByType] = savedDamage[key];&lt;br /&gt;
&lt;br /&gt;
    for (let index = 0; index &amp;lt; 4; index++) {&lt;br /&gt;
      const damageWeighted = damageWeightedByType[attackTypeMapping[index]];&lt;br /&gt;
      const damageByTypeIndex = damageByType[index];&lt;br /&gt;
&lt;br /&gt;
      if (damageByTypeIndex.length === 0) continue;&lt;br /&gt;
&lt;br /&gt;
      const currentWeight =&lt;br /&gt;
        (weight * damageTypeWeights[index]) / damageByTypeIndex.length;&lt;br /&gt;
&lt;br /&gt;
      for (const damage of damageByTypeIndex) {&lt;br /&gt;
        damageWeighted[damage] = (damageWeighted[damage] || 0) + currentWeight;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcMeanDamage(damageWeightedByType, totalCardinal) {&lt;br /&gt;
  var sumDamage = 0;&lt;br /&gt;
&lt;br /&gt;
  for (var damageTypeName in damageWeightedByType) {&lt;br /&gt;
    if (damageTypeName === &amp;quot;miss&amp;quot;) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var damageWeighted = damageWeightedByType[damageTypeName];&lt;br /&gt;
&lt;br /&gt;
    for (var damage in damageWeighted) {&lt;br /&gt;
      sumDamage += damage * damageWeighted[damage];&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return sumDamage / totalCardinal;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function prepareDamageData(damageWeightedByType, attackValues) {&lt;br /&gt;
  const totalCardinal = attackValues.totalCardinal;&lt;br /&gt;
  const scatterDataByType = {};&lt;br /&gt;
  const criticalAttackRange = attackValues.criticalAttackRange;&lt;br /&gt;
&lt;br /&gt;
  let minDamage = Infinity;&lt;br /&gt;
  let maxDamage = 0;&lt;br /&gt;
  let sumDamage = 0;&lt;br /&gt;
&lt;br /&gt;
  let possibleDamageCount = 0;&lt;br /&gt;
  let possibleDamageCountTemp = 0;&lt;br /&gt;
  let uniqueDamageCount = 0;&lt;br /&gt;
&lt;br /&gt;
  for (const damageTypeName in damageWeightedByType) {&lt;br /&gt;
    if (damageTypeName === &amp;quot;miss&amp;quot;) {&lt;br /&gt;
      scatterDataByType.miss = damageWeightedByType.miss;&lt;br /&gt;
      possibleDamageCount++;&lt;br /&gt;
      uniqueDamageCount++;&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
    const damageWeighted = damageWeightedByType[damageTypeName];&lt;br /&gt;
    const scatterData = [];&lt;br /&gt;
&lt;br /&gt;
    scatterDataByType[damageTypeName] = scatterData;&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      (damageTypeName === &amp;quot;criticalHit&amp;quot; ||&lt;br /&gt;
        damageTypeName === &amp;quot;criticalPiercingHit&amp;quot;) &amp;amp;&amp;amp;&lt;br /&gt;
      criticalAttackRange&lt;br /&gt;
    ) {&lt;br /&gt;
      possibleDamageCountTemp =&lt;br /&gt;
        attackValues.possibleDamageCount * criticalAttackRange.length;&lt;br /&gt;
    } else {&lt;br /&gt;
      possibleDamageCountTemp = attackValues.possibleDamageCount;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    for (let damage in damageWeighted) {&lt;br /&gt;
      damage = +damage;&lt;br /&gt;
&lt;br /&gt;
      if (damage &amp;lt; minDamage) {&lt;br /&gt;
        minDamage = damage;&lt;br /&gt;
      }&lt;br /&gt;
      if (damage &amp;gt; maxDamage) {&lt;br /&gt;
        maxDamage = damage;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      const weight = damageWeighted[damage];&lt;br /&gt;
      const probability = weight / totalCardinal;&lt;br /&gt;
&lt;br /&gt;
      sumDamage += damage * weight;&lt;br /&gt;
      damageWeighted[damage] = probability;&lt;br /&gt;
      scatterData.push({ x: damage, y: probability });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    const scatterDataLength = scatterData.length;&lt;br /&gt;
&lt;br /&gt;
    if (!scatterDataLength) {&lt;br /&gt;
      delete scatterDataByType[damageTypeName];&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    possibleDamageCount += possibleDamageCountTemp;&lt;br /&gt;
    uniqueDamageCount += scatterDataLength;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (minDamage === Infinity) {&lt;br /&gt;
    minDamage = 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  attackValues.possibleDamageCount = possibleDamageCount;&lt;br /&gt;
&lt;br /&gt;
  return [&lt;br /&gt;
    sumDamage / totalCardinal,&lt;br /&gt;
    minDamage,&lt;br /&gt;
    maxDamage,&lt;br /&gt;
    scatterDataByType,&lt;br /&gt;
    uniqueDamageCount,&lt;br /&gt;
  ];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function aggregateDamage(scatterData, maxPoints) {&lt;br /&gt;
  const dataLength = scatterData.length;&lt;br /&gt;
  const groupLength = Math.ceil(dataLength / maxPoints);&lt;br /&gt;
  const aggregateScatterData = [];&lt;br /&gt;
  const groupCount = Math.ceil(dataLength / groupLength);&lt;br /&gt;
&lt;br /&gt;
  for (let groupIndex = 0; groupIndex &amp;lt; groupCount; groupIndex++) {&lt;br /&gt;
    const startIndex = groupIndex * groupLength;&lt;br /&gt;
    const endIndex = Math.min(startIndex + groupLength, dataLength);&lt;br /&gt;
&lt;br /&gt;
    let aggregateDamage = 0;&lt;br /&gt;
    let aggregateProbability = 0;&lt;br /&gt;
&lt;br /&gt;
    for (let index = startIndex; index &amp;lt; endIndex; index++) {&lt;br /&gt;
      const { x: damage, y: probability } = scatterData[index];&lt;br /&gt;
      aggregateDamage += damage * probability;&lt;br /&gt;
      aggregateProbability += probability;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    aggregateScatterData.push({&lt;br /&gt;
      x: aggregateDamage / aggregateProbability,&lt;br /&gt;
      y: aggregateProbability,&lt;br /&gt;
    });&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return aggregateScatterData;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addToDamageChart(battle, scatterDataByType) {&lt;br /&gt;
  const { chart, datasetsStyle, maxPoints, reduceChartPointsContainer } =&lt;br /&gt;
    battle.damageChart;&lt;br /&gt;
  const isReducePointsChecked = battle.reduceChartPoints.checked;&lt;br /&gt;
  const datasets = chart.data.datasets;&lt;br /&gt;
&lt;br /&gt;
  let isFirstDataset = true;&lt;br /&gt;
&lt;br /&gt;
  datasets.length = 0;&lt;br /&gt;
&lt;br /&gt;
  for (let index = 0; index &amp;lt; datasetsStyle.length; index++) {&lt;br /&gt;
    const dataset = copyObject(datasetsStyle[index]);&lt;br /&gt;
&lt;br /&gt;
    if (!scatterDataByType.hasOwnProperty(dataset.name)) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    const scatterData = scatterDataByType[dataset.name];&lt;br /&gt;
    const canBeReduced = scatterData.length &amp;gt; 2 * maxPoints;&lt;br /&gt;
&lt;br /&gt;
    dataset.hidden = !isFirstDataset;&lt;br /&gt;
    dataset.canBeReduced = canBeReduced;&lt;br /&gt;
&lt;br /&gt;
    if (canBeReduced &amp;amp;&amp;amp; isReducePointsChecked) {&lt;br /&gt;
      dataset.data = aggregateDamage(scatterData, maxPoints);&lt;br /&gt;
    } else {&lt;br /&gt;
      dataset.data = scatterData;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isFirstDataset) {&lt;br /&gt;
      isFirstDataset = false;&lt;br /&gt;
&lt;br /&gt;
      if (canBeReduced) {&lt;br /&gt;
        showElement(reduceChartPointsContainer);&lt;br /&gt;
&lt;br /&gt;
        if (!isReducePointsChecked) {&lt;br /&gt;
          handleChartAnimations(chart, false);&lt;br /&gt;
        }&lt;br /&gt;
      } else {&lt;br /&gt;
        hideElement(reduceChartPointsContainer);&lt;br /&gt;
        handleChartAnimations(chart, true);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    datasets.push(dataset);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  chart.data.missPercentage = scatterDataByType.miss;&lt;br /&gt;
  chart.update();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addToBonusVariationChart(&lt;br /&gt;
  damageByBonus,&lt;br /&gt;
  augmentationByBonus,&lt;br /&gt;
  xLabel,&lt;br /&gt;
  chart&lt;br /&gt;
) {&lt;br /&gt;
  chart.data.datasets[0].data = damageByBonus;&lt;br /&gt;
  chart.data.datasets[1].data = augmentationByBonus;&lt;br /&gt;
  chart.options.scales.x.title.text = xLabel;&lt;br /&gt;
  chart.update();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleChartAnimations(chart, addAnimations) {&lt;br /&gt;
  chart.options.animation = addAnimations;&lt;br /&gt;
  chart.options.animations.colors = addAnimations;&lt;br /&gt;
  chart.options.animations.x = addAnimations;&lt;br /&gt;
  chart.options.transitions.active.animation.duration = addAnimations * 1000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateDamageChartDescription(battle, uniqueDamageCount) {&lt;br /&gt;
  const {&lt;br /&gt;
    chartDescriptionContainer,&lt;br /&gt;
    uniqueDamageCounters,&lt;br /&gt;
    numberFormats: { default: defaultFormat },&lt;br /&gt;
  } = battle;&lt;br /&gt;
&lt;br /&gt;
  if (uniqueDamageCount &amp;gt; 1) {&lt;br /&gt;
    uniqueDamageCounters.forEach(function (element) {&lt;br /&gt;
      element.textContent = defaultFormat.format(uniqueDamageCount);&lt;br /&gt;
    });&lt;br /&gt;
    showElement(chartDescriptionContainer);&lt;br /&gt;
  } else {&lt;br /&gt;
    hideElement(chartDescriptionContainer);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getMonsterName(monsterVnum) {&lt;br /&gt;
  var monsterAttributes = monsterData[monsterVnum];&lt;br /&gt;
  return monsterAttributes[monsterAttributes.length - 1];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getTranslatedMonsterName(monsterVnum) {&lt;br /&gt;
  return translation.monsters[monsterVnum];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterClass(selectedRace, classChoice, selectValueIsChanged = false) {&lt;br /&gt;
  for (var radioNode of classChoice) {&lt;br /&gt;
    var radioGrandParent = radioNode.parentElement.parentElement;&lt;br /&gt;
&lt;br /&gt;
    if (radioNode.getAttribute(&amp;quot;data-race&amp;quot;) === selectedRace) {&lt;br /&gt;
      if (!selectValueIsChanged) {&lt;br /&gt;
        radioNode.checked = true;&lt;br /&gt;
        selectValueIsChanged = true;&lt;br /&gt;
      }&lt;br /&gt;
      showElement(radioGrandParent);&lt;br /&gt;
    } else {&lt;br /&gt;
      hideElement(radioGrandParent);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterWeapon(&lt;br /&gt;
  selectedRace,&lt;br /&gt;
  weaponElement,&lt;br /&gt;
  weaponCategory,&lt;br /&gt;
  allowedWeaponsPerRace,&lt;br /&gt;
  selectValueIsChanged = false&lt;br /&gt;
) {&lt;br /&gt;
  var allowedWeapons = allowedWeaponsPerRace[selectedRace];&lt;br /&gt;
&lt;br /&gt;
  if (!selectValueIsChanged) {&lt;br /&gt;
    var weaponType = createWeapon(weaponElement.value).type;&lt;br /&gt;
&lt;br /&gt;
    if (!isValueInArray(weaponType, allowedWeapons)) {&lt;br /&gt;
      weaponElement.value = 0;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var children = weaponCategory.children;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; children.length; index++) {&lt;br /&gt;
    var child = children[index];&lt;br /&gt;
&lt;br /&gt;
    if (isValueInArray(index, allowedWeapons)) {&lt;br /&gt;
      showElement(child);&lt;br /&gt;
    } else {&lt;br /&gt;
      hideElement(child);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function changePolymorphValues(characterCreation, monsterVnum, monsterImage) {&lt;br /&gt;
  var { polymorphMonster, polymorphMonsterImage } = characterCreation;&lt;br /&gt;
&lt;br /&gt;
  polymorphMonster.value = monsterVnum;&lt;br /&gt;
  polymorphMonsterImage.value = monsterImage;&lt;br /&gt;
&lt;br /&gt;
  polymorphMonster.dispatchEvent(newChangeEvent());&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function resetImageFromWiki(image) {&lt;br /&gt;
  image.removeAttribute(&amp;quot;srcset&amp;quot;);&lt;br /&gt;
  image.removeAttribute(&amp;quot;data-file-width&amp;quot;);&lt;br /&gt;
  image.removeAttribute(&amp;quot;data-file-height&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleImageFromWiki(image, newSrc) {&lt;br /&gt;
  image.src = newSrc;&lt;br /&gt;
  image.alt = newSrc.split(&amp;quot;/&amp;quot;).pop();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handlePolymorphDisplay(characters, monsterVnum, monsterSrc) {&lt;br /&gt;
  var { translateMonsters, polymorphDisplay } = characters;&lt;br /&gt;
  var oldImage = polymorphDisplay.firstChild;&lt;br /&gt;
  var oldLink = oldImage.nextElementSibling;&lt;br /&gt;
  var monsterName = getMonsterName(monsterVnum);&lt;br /&gt;
  var displayName = translateMonsters&lt;br /&gt;
    ? getTranslatedMonsterName(monsterVnum)&lt;br /&gt;
    : monsterName;&lt;br /&gt;
  var newLink = createWikiLink(monsterName, displayName);&lt;br /&gt;
&lt;br /&gt;
  resetImageFromWiki(oldImage);&lt;br /&gt;
  handleImageFromWiki(oldImage, monsterSrc);&lt;br /&gt;
&lt;br /&gt;
  polymorphDisplay.replaceChild(newLink, oldLink);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createWikiLink(pageName, displayName) {&lt;br /&gt;
  var wikiLink = document.createElement(&amp;quot;a&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  wikiLink.href = mw.util.getUrl(pageName);&lt;br /&gt;
  wikiLink.title = pageName;&lt;br /&gt;
  wikiLink.textContent = displayName || pageName;&lt;br /&gt;
&lt;br /&gt;
  return wikiLink;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSelectedWeapon(weaponCategory) {&lt;br /&gt;
  return weaponCategory.querySelector(&amp;quot;input[type='radio']:checked&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleWeaponDisplay(&lt;br /&gt;
  weaponCategory,&lt;br /&gt;
  weaponDisplay,&lt;br /&gt;
  weaponVnum,&lt;br /&gt;
  newWeapon&lt;br /&gt;
) {&lt;br /&gt;
  var newWeapon = newWeapon || getSelectedWeapon(weaponCategory);&lt;br /&gt;
&lt;br /&gt;
  var newImage = newWeapon.nextElementSibling;&lt;br /&gt;
  var newText = document.createElement(&amp;quot;span&amp;quot;);&lt;br /&gt;
  var oldImage = weaponDisplay.firstChild;&lt;br /&gt;
  var oldText = oldImage.nextElementSibling;&lt;br /&gt;
  var weaponTooltip = newImage.nextElementSibling;&lt;br /&gt;
  var originalWeaponName = weaponTooltip.dataset.o;&lt;br /&gt;
  var weaponName = weaponTooltip.textContent;&lt;br /&gt;
&lt;br /&gt;
  if (weaponVnum == 0) {&lt;br /&gt;
    newText.textContent = weaponName;&lt;br /&gt;
  } else {&lt;br /&gt;
    var weaponLink = createWikiLink(originalWeaponName, weaponName);&lt;br /&gt;
    newText.appendChild(weaponLink);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  weaponDisplay.replaceChild(newImage.cloneNode(), oldImage);&lt;br /&gt;
  weaponDisplay.replaceChild(newText, oldText);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterUpgrade(&lt;br /&gt;
  weaponUpgrade,&lt;br /&gt;
  weaponVnum,&lt;br /&gt;
  randomAttackValue,&lt;br /&gt;
  randomMagicAttackValue&lt;br /&gt;
) {&lt;br /&gt;
  var weapon = createWeapon(weaponVnum);&lt;br /&gt;
  var currentUpgrade = Number(weaponUpgrade.value);&lt;br /&gt;
  var weaponUpgradeChildren = weaponUpgrade.children;&lt;br /&gt;
&lt;br /&gt;
  if (weapon.isSerpent) {&lt;br /&gt;
    showElement(randomAttackValue);&lt;br /&gt;
&lt;br /&gt;
    if (weapon.isMagic) {&lt;br /&gt;
      showElement(randomMagicAttackValue);&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    hideElement(randomAttackValue);&lt;br /&gt;
    hideElement(randomMagicAttackValue);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (weapon.maxUpgrade &amp;lt; 1) {&lt;br /&gt;
    hideElement(weaponUpgrade.parentElement);&lt;br /&gt;
  } else {&lt;br /&gt;
    showElement(weaponUpgrade.parentElement);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (var upgrade = 0; upgrade &amp;lt;= weapon.maxUpgrade; upgrade++) {&lt;br /&gt;
    showElement(weaponUpgradeChildren[upgrade]);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (&lt;br /&gt;
    var upgrade = weapon.maxUpgrade + 1;&lt;br /&gt;
    upgrade &amp;lt; weaponUpgradeChildren.length;&lt;br /&gt;
    upgrade++&lt;br /&gt;
  ) {&lt;br /&gt;
    hideElement(weaponUpgradeChildren[upgrade]);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (currentUpgrade &amp;gt; weapon.maxUpgrade) {&lt;br /&gt;
    weaponUpgrade.value = weapon.maxUpgrade;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterCheckbox(checkbox, element) {&lt;br /&gt;
  if (checkbox.checked) {&lt;br /&gt;
    showElement(element);&lt;br /&gt;
  } else {&lt;br /&gt;
    hideElement(element);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterSkills(selectedClass, skillElementsToFilter) {&lt;br /&gt;
  for (var element of skillElementsToFilter) {&lt;br /&gt;
    if (isValueInArray(selectedClass, element.dataset.class)) {&lt;br /&gt;
      showElement(element);&lt;br /&gt;
    } else {&lt;br /&gt;
      hideElement(element);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterForm(characters, battle) {&lt;br /&gt;
  var { saveButton, characterCreation, toggleSiblings } = characters;&lt;br /&gt;
  var allowedWeaponsPerRace = battle.constants.allowedWeaponsPerRace;&lt;br /&gt;
  var battleChoice = battle.battleChoice;&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;change&amp;quot;, function (event) {&lt;br /&gt;
    var target = event.target;&lt;br /&gt;
    var targetName = target.name;&lt;br /&gt;
&lt;br /&gt;
    saveButtonOrange(saveButton);&lt;br /&gt;
    characters.unsavedChanges = true;&lt;br /&gt;
&lt;br /&gt;
    switch (targetName) {&lt;br /&gt;
      case &amp;quot;race&amp;quot;:&lt;br /&gt;
        var selectedRace = target.value;&lt;br /&gt;
        var classChoice = characterCreation.class;&lt;br /&gt;
        var weaponElement = characterCreation.weapon;&lt;br /&gt;
&lt;br /&gt;
        filterClass(selectedRace, classChoice);&lt;br /&gt;
        filterWeapon(&lt;br /&gt;
          selectedRace,&lt;br /&gt;
          weaponElement,&lt;br /&gt;
          characters.weaponCategory,&lt;br /&gt;
          allowedWeaponsPerRace&lt;br /&gt;
        );&lt;br /&gt;
        handleWeaponDisplay(&lt;br /&gt;
          characters.weaponCategory,&lt;br /&gt;
          characters.weaponDisplay,&lt;br /&gt;
          weaponElement.value&lt;br /&gt;
        );&lt;br /&gt;
        filterUpgrade(&lt;br /&gt;
          characterCreation.weaponUpgrade,&lt;br /&gt;
          weaponElement.value,&lt;br /&gt;
          characters.randomAttackValue,&lt;br /&gt;
          characters.randomMagicAttackValue&lt;br /&gt;
        );&lt;br /&gt;
        filterSkills(classChoice.value, characters.skillElementsToFilter);&lt;br /&gt;
        handleBonusVariationUpdate(&lt;br /&gt;
          characterCreation,&lt;br /&gt;
          characters.bonusVariation,&lt;br /&gt;
          true&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        battleChoice.resetAttackType = true;&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;class&amp;quot;:&lt;br /&gt;
        filterSkills(target.value, characters.skillElementsToFilter);&lt;br /&gt;
        handleBonusVariationUpdate(&lt;br /&gt;
          characterCreation,&lt;br /&gt;
          characters.bonusVariation,&lt;br /&gt;
          true&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        battleChoice.resetAttackType = true;&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;weapon&amp;quot;:&lt;br /&gt;
        var weaponElement = characterCreation.weapon;&lt;br /&gt;
&lt;br /&gt;
        handleWeaponDisplay(&lt;br /&gt;
          characters.weaponCategory,&lt;br /&gt;
          characters.weaponDisplay,&lt;br /&gt;
          weaponElement.value,&lt;br /&gt;
          target&lt;br /&gt;
        );&lt;br /&gt;
        filterUpgrade(&lt;br /&gt;
          characterCreation.weaponUpgrade,&lt;br /&gt;
          target.value,&lt;br /&gt;
          characters.randomAttackValue,&lt;br /&gt;
          characters.randomMagicAttackValue&lt;br /&gt;
        );&lt;br /&gt;
        handleBonusVariationUpdate(&lt;br /&gt;
          characterCreation,&lt;br /&gt;
          characters.bonusVariation&lt;br /&gt;
        );&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;isRiding&amp;quot;:&lt;br /&gt;
        battleChoice.resetAttackType = true;&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;isPolymorph&amp;quot;:&lt;br /&gt;
        battleChoice.resetAttackType = true;&lt;br /&gt;
        break;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (toggleSiblings.hasOwnProperty(targetName)) {&lt;br /&gt;
      filterCheckbox(target, toggleSiblings[targetName]);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      targetName.startsWith(&amp;quot;attackSkill&amp;quot;) ||&lt;br /&gt;
      targetName.startsWith(&amp;quot;horseSkill&amp;quot;)&lt;br /&gt;
    ) {&lt;br /&gt;
      battleChoice.resetAttackType = true;&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addUniquePseudo(characterDataObject, savedCharactersPseudo) {&lt;br /&gt;
  var characterPseudo = String(characterDataObject.name);&lt;br /&gt;
  var originalPseudo = characterPseudo;&lt;br /&gt;
  var count = 0;&lt;br /&gt;
&lt;br /&gt;
  var regex = /(.*)(\d)$/;&lt;br /&gt;
  var match = characterPseudo.match(regex);&lt;br /&gt;
&lt;br /&gt;
  if (match) {&lt;br /&gt;
    originalPseudo = match[1];&lt;br /&gt;
    count = match[2];&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  while (isValueInArray(characterPseudo, savedCharactersPseudo)) {&lt;br /&gt;
    characterPseudo = originalPseudo + count;&lt;br /&gt;
    count++;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  characterDataObject.name = characterPseudo;&lt;br /&gt;
  return [characterDataObject, characterPseudo];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function convertToNumber(value) {&lt;br /&gt;
  var valueNumber = Number(value);&lt;br /&gt;
  return isNaN(valueNumber) ? value : valueNumber;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getLocalStorageValue(key, defaultValue) {&lt;br /&gt;
  var storedValue = localStorage.getItem(key);&lt;br /&gt;
&lt;br /&gt;
  if (storedValue) {&lt;br /&gt;
    return JSON.parse(storedValue);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return defaultValue;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSavedCharacters() {&lt;br /&gt;
  return getLocalStorageValue(&amp;quot;mt2-calc.characters.saved&amp;quot;, {});&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSavedMonsters() {&lt;br /&gt;
  return getLocalStorageValue(&amp;quot;mt2-calc.monsters.saved&amp;quot;, {});&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSavedFights() {&lt;br /&gt;
  return getLocalStorageValue(&amp;quot;mt2-calc.fights.saved&amp;quot;, []);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getLastLang() {&lt;br /&gt;
  return getLocalStorageValue(&amp;quot;mt2-calc.language.last-used&amp;quot;, &amp;quot;&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveToLocalStorage(key, value) {&lt;br /&gt;
  localStorage.setItem(key, JSON.stringify(value));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateSavedCharacters(savedCharacters) {&lt;br /&gt;
  saveToLocalStorage(&amp;quot;mt2-calc.characters.saved&amp;quot;, savedCharacters);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateSavedMonsters(savedMonsters) {&lt;br /&gt;
  saveToLocalStorage(&amp;quot;mt2-calc.monsters.saved&amp;quot;, savedMonsters);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateSavedFights(savedFights) {&lt;br /&gt;
  saveToLocalStorage(&amp;quot;mt2-calc.fights.saved&amp;quot;, savedFights);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateLastLang(lang) {&lt;br /&gt;
  saveToLocalStorage(&amp;quot;mt2-calc.language.last-used&amp;quot;, lang);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveCharacter(&lt;br /&gt;
  savedCharacters,&lt;br /&gt;
  characterCreation,&lt;br /&gt;
  battle,&lt;br /&gt;
  newCharacter,&lt;br /&gt;
  characterDataObject&lt;br /&gt;
) {&lt;br /&gt;
  if (!characterDataObject) {&lt;br /&gt;
    var characterData = new FormData(characterCreation);&lt;br /&gt;
    var characterDataObject = {};&lt;br /&gt;
&lt;br /&gt;
    characterData.forEach(function (value, key) {&lt;br /&gt;
      characterDataObject[key] = convertToNumber(value);&lt;br /&gt;
    });&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var characterPseudo = characterDataObject.name;&lt;br /&gt;
  var { battleChoice } = battle;&lt;br /&gt;
&lt;br /&gt;
  savedCharacters[characterPseudo] = characterDataObject;&lt;br /&gt;
  updateSavedCharacters(savedCharacters);&lt;br /&gt;
&lt;br /&gt;
  if (newCharacter) {&lt;br /&gt;
    addBattleChoice(battleChoice, characterPseudo, characterDataObject);&lt;br /&gt;
  } else {&lt;br /&gt;
    updateBattleChoiceImage(&lt;br /&gt;
      battleChoice,&lt;br /&gt;
      characterPseudo,&lt;br /&gt;
      characterDataObject.race&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (battleChoice.resetAttackType) {&lt;br /&gt;
    if (isCharacterSelected(characterPseudo, battleChoice.attacker.selected)) {&lt;br /&gt;
      filterAttackTypeSelectionCharacter(&lt;br /&gt;
        characterDataObject,&lt;br /&gt;
        battleChoice.attackType&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
    battleChoice.resetAttackType = false;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveButtonGreen(saveButton) {&lt;br /&gt;
  saveButton.classList.remove(&amp;quot;unsaved-character&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveButtonOrange(saveButton) {&lt;br /&gt;
  saveButton.classList.add(&amp;quot;unsaved-character&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function characterCreationListener(characters, battle) {&lt;br /&gt;
  var { characterCreation, saveButton, weaponCategory } = characters;&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;submit&amp;quot;, handleSubmitForm);&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;invalid&amp;quot;, handleInvalidInput, true);&lt;br /&gt;
  document.addEventListener(&amp;quot;keydown&amp;quot;, handleSaveShortcut);&lt;br /&gt;
  weaponCategory.addEventListener(&amp;quot;mouseover&amp;quot;, handleTooltipOverflow);&lt;br /&gt;
&lt;br /&gt;
  function handleSubmitForm(event) {&lt;br /&gt;
    event.preventDefault();&lt;br /&gt;
&lt;br /&gt;
    if (characters.unsavedChanges) {&lt;br /&gt;
      saveCharacter(characters.savedCharacters, characterCreation, battle);&lt;br /&gt;
      saveButtonGreen(saveButton);&lt;br /&gt;
      characters.unsavedChanges = false;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function handleInvalidInput(event) {&lt;br /&gt;
    var target = event.target;&lt;br /&gt;
&lt;br /&gt;
    if (target.checkVisibility()) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var autoCorrectInput = target.closest(&amp;quot;.auto-correct-input&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      autoCorrectInput &amp;amp;&amp;amp;&lt;br /&gt;
      autoCorrectInput.classList.contains(&amp;quot;tabber-noactive&amp;quot;)&lt;br /&gt;
    ) {&lt;br /&gt;
      target.value = target.defaultValue;&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    openTargetTab(target);&lt;br /&gt;
    openTargetCollapsible(target);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function handleSaveShortcut(event) {&lt;br /&gt;
    if (event.ctrlKey &amp;amp;&amp;amp; event.key === &amp;quot;s&amp;quot;) {&lt;br /&gt;
      event.preventDefault();&lt;br /&gt;
      saveButton.click();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function handleTooltipOverflow(event) {&lt;br /&gt;
    var label = event.target.closest(&amp;quot;label&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (label) {&lt;br /&gt;
      var tooltip = label.lastChild;&lt;br /&gt;
&lt;br /&gt;
      if (tooltip.classList.contains(&amp;quot;popContenu&amp;quot;)) {&lt;br /&gt;
        var tooltipRect = tooltip.getBoundingClientRect();&lt;br /&gt;
        var modalRect = weaponCategory.getBoundingClientRect();&lt;br /&gt;
&lt;br /&gt;
        if (tooltipRect.right &amp;gt; modalRect.right) {&lt;br /&gt;
          tooltip.style.left = &amp;quot;-100%&amp;quot;;&lt;br /&gt;
        } else if (tooltipRect.left &amp;lt; modalRect.left) {&lt;br /&gt;
          tooltip.style.left = &amp;quot;200%&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function downloadData(content, type, filename) {&lt;br /&gt;
  var link = document.createElement(&amp;quot;a&amp;quot;);&lt;br /&gt;
  var blob = new Blob([content], { type: type });&lt;br /&gt;
  var blobURL = URL.createObjectURL(blob);&lt;br /&gt;
&lt;br /&gt;
  link.href = blobURL;&lt;br /&gt;
  link.download = filename;&lt;br /&gt;
  document.body.appendChild(link);&lt;br /&gt;
&lt;br /&gt;
  link.click();&lt;br /&gt;
  document.body.removeChild(link);&lt;br /&gt;
  URL.revokeObjectURL(blobURL);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function uploadCharacter(&lt;br /&gt;
  selectedFiles,&lt;br /&gt;
  characters,&lt;br /&gt;
  characterTemplate,&lt;br /&gt;
  charactersContainer,&lt;br /&gt;
  battle&lt;br /&gt;
) {&lt;br /&gt;
  var selectFilesLength = selectedFiles.length;&lt;br /&gt;
  var defaultPseudo = characters.defaultText.pseudo;&lt;br /&gt;
&lt;br /&gt;
  for (var fileIndex = 0; fileIndex &amp;lt; selectFilesLength; fileIndex++) {&lt;br /&gt;
    var selectedFile = selectedFiles[fileIndex];&lt;br /&gt;
&lt;br /&gt;
    if (selectedFile.type === &amp;quot;text/plain&amp;quot;) {&lt;br /&gt;
      var reader = new FileReader();&lt;br /&gt;
      reader.onload = function (e) {&lt;br /&gt;
        var fileContent = e.target.result;&lt;br /&gt;
        try {&lt;br /&gt;
          var characterDataObject = JSON.parse(fileContent);&lt;br /&gt;
&lt;br /&gt;
          if (characterDataObject.hasOwnProperty(&amp;quot;name&amp;quot;)) {&lt;br /&gt;
            var characterPseudo = String(characterDataObject.name);&lt;br /&gt;
&lt;br /&gt;
            hideElement(characters.characterCreation);&lt;br /&gt;
            characterPseudo = validPseudo(characterPseudo, defaultPseudo);&lt;br /&gt;
&lt;br /&gt;
            [characterDataObject, characterPseudo] = addUniquePseudo(&lt;br /&gt;
              characterDataObject,&lt;br /&gt;
              Object.keys(characters.savedCharacters)&lt;br /&gt;
            );&lt;br /&gt;
            var selectedCharacter = handleNewCharacter(&lt;br /&gt;
              characters,&lt;br /&gt;
              characterTemplate,&lt;br /&gt;
              charactersContainer,&lt;br /&gt;
              battle,&lt;br /&gt;
              characterPseudo&lt;br /&gt;
            )[0];&lt;br /&gt;
&lt;br /&gt;
            if (selectFilesLength === 1) {&lt;br /&gt;
              updateForm(&lt;br /&gt;
                characterDataObject,&lt;br /&gt;
                characters.characterCreation,&lt;br /&gt;
                characters,&lt;br /&gt;
                selectedCharacter,&lt;br /&gt;
                battle&lt;br /&gt;
              );&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            saveCharacter(&lt;br /&gt;
              characters.savedCharacters,&lt;br /&gt;
              characters.characterCreation,&lt;br /&gt;
              battle,&lt;br /&gt;
              true,&lt;br /&gt;
              characterDataObject&lt;br /&gt;
            );&lt;br /&gt;
          }&lt;br /&gt;
        } catch (error) {&lt;br /&gt;
          console.warn(error);&lt;br /&gt;
          if (error.name === &amp;quot;TypeError&amp;quot;) {&lt;br /&gt;
            // delete the character&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
      };&lt;br /&gt;
      reader.readAsText(selectedFile);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleUploadCharacter(&lt;br /&gt;
  characters,&lt;br /&gt;
  characterTemplate,&lt;br /&gt;
  charactersContainer,&lt;br /&gt;
  battle&lt;br /&gt;
) {&lt;br /&gt;
  var characterInput = characters.characterInput;&lt;br /&gt;
  var dropZone = characters.dropZone;&lt;br /&gt;
&lt;br /&gt;
  characterInput.accept = &amp;quot;.txt&amp;quot;;&lt;br /&gt;
  characterInput.multiple = true;&lt;br /&gt;
  dropZone.setAttribute(&amp;quot;tabindex&amp;quot;, &amp;quot;0&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  dropZone.addEventListener(&amp;quot;click&amp;quot;, function () {&lt;br /&gt;
    characterInput.click();&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  dropZone.addEventListener(&amp;quot;dragover&amp;quot;, function (event) {&lt;br /&gt;
    event.preventDefault();&lt;br /&gt;
    dropZone.classList.add(&amp;quot;drop-zone--dragover&amp;quot;);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  [&amp;quot;dragleave&amp;quot;, &amp;quot;dragend&amp;quot;].forEach(function (type) {&lt;br /&gt;
    dropZone.addEventListener(type, function () {&lt;br /&gt;
      dropZone.classList.remove(&amp;quot;drop-zone--dragover&amp;quot;);&lt;br /&gt;
    });&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  dropZone.addEventListener(&amp;quot;drop&amp;quot;, function (event) {&lt;br /&gt;
    event.preventDefault();&lt;br /&gt;
    uploadCharacter(&lt;br /&gt;
      event.dataTransfer.files,&lt;br /&gt;
      characters,&lt;br /&gt;
      characterTemplate,&lt;br /&gt;
      charactersContainer,&lt;br /&gt;
      battle&lt;br /&gt;
    );&lt;br /&gt;
    dropZone.classList.remove(&amp;quot;drop-zone--dragover&amp;quot;);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  characterInput.addEventListener(&amp;quot;change&amp;quot;, function (event) {&lt;br /&gt;
    uploadCharacter(&lt;br /&gt;
      event.target.files,&lt;br /&gt;
      characters,&lt;br /&gt;
      characterTemplate,&lt;br /&gt;
      charactersContainer,&lt;br /&gt;
      battle&lt;br /&gt;
    );&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function deleteCharacter(characters, pseudo, element, battle) {&lt;br /&gt;
  delete characters.savedCharacters[pseudo];&lt;br /&gt;
  element.remove();&lt;br /&gt;
&lt;br /&gt;
  updateSavedCharacters(characters.savedCharacters);&lt;br /&gt;
  removeBattleChoice(battle.battleChoice, pseudo, &amp;quot;character&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (&lt;br /&gt;
    !Object.keys(characters.savedCharacters).length ||&lt;br /&gt;
    characters.characterCreation.name.value === pseudo&lt;br /&gt;
  ) {&lt;br /&gt;
    saveButtonGreen(characters.saveButton);&lt;br /&gt;
    characters.unsavedChanges = false;&lt;br /&gt;
    hideElement(characters.characterCreation);&lt;br /&gt;
    showElement(characters.characterCreation.previousElementSibling);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function deleteMonster(characters, battle, monsterVnum) {&lt;br /&gt;
  var monsterElements = characters.monsterElements;&lt;br /&gt;
  var monsterType = characters.savedMonsters[monsterVnum].category;&lt;br /&gt;
&lt;br /&gt;
  if (monsterElements.hasOwnProperty(monsterVnum)) {&lt;br /&gt;
    monsterElements[monsterVnum].remove();&lt;br /&gt;
    delete monsterElements[monsterVnum];&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  delete characters.savedMonsters[monsterVnum];&lt;br /&gt;
&lt;br /&gt;
  updateSavedMonsters(characters.savedMonsters);&lt;br /&gt;
  removeBattleChoice(battle.battleChoice, monsterVnum, monsterType);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleStyle(characters, selectedElement) {&lt;br /&gt;
  var currentCharacter = characters.currentCharacter;&lt;br /&gt;
&lt;br /&gt;
  if (currentCharacter) {&lt;br /&gt;
    currentCharacter.classList.remove(&amp;quot;selected-character&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  selectedElement.classList.add(&amp;quot;selected-character&amp;quot;);&lt;br /&gt;
  characters.currentCharacter = selectedElement;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateForm(&lt;br /&gt;
  formData,&lt;br /&gt;
  characterCreation,&lt;br /&gt;
  characters,&lt;br /&gt;
  selectedElement,&lt;br /&gt;
  battle&lt;br /&gt;
) {&lt;br /&gt;
  saveButtonGreen(characters.saveButton);&lt;br /&gt;
  hideElement(characterCreation.previousElementSibling);&lt;br /&gt;
  showElement(characterCreation);&lt;br /&gt;
  handleStyle(characters, selectedElement);&lt;br /&gt;
&lt;br /&gt;
  characterCreation.reset();&lt;br /&gt;
&lt;br /&gt;
  for (var [name, value] of Object.entries(formData)) {&lt;br /&gt;
    var formElement = characterCreation[name];&lt;br /&gt;
&lt;br /&gt;
    if (!formElement) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (formElement.type === &amp;quot;checkbox&amp;quot;) {&lt;br /&gt;
      if (isChecked(value)) {&lt;br /&gt;
        formElement.checked = true;&lt;br /&gt;
      }&lt;br /&gt;
    } else {&lt;br /&gt;
      formElement.value = value;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  var selectedRace = characterCreation.race.value;&lt;br /&gt;
  var classChoice = characterCreation.class;&lt;br /&gt;
  var weaponElement = characterCreation.weapon;&lt;br /&gt;
&lt;br /&gt;
  filterClass(selectedRace, classChoice, true);&lt;br /&gt;
  filterWeapon(&lt;br /&gt;
    selectedRace,&lt;br /&gt;
    weaponElement,&lt;br /&gt;
    characters.weaponCategory,&lt;br /&gt;
    battle.constants.allowedWeaponsPerRace,&lt;br /&gt;
    true&lt;br /&gt;
  );&lt;br /&gt;
  handlePolymorphDisplay(&lt;br /&gt;
    characters,&lt;br /&gt;
    characterCreation.polymorphMonster.value,&lt;br /&gt;
    characterCreation.polymorphMonsterImage.value&lt;br /&gt;
  );&lt;br /&gt;
  handleWeaponDisplay(&lt;br /&gt;
    characters.weaponCategory,&lt;br /&gt;
    characters.weaponDisplay,&lt;br /&gt;
    weaponElement.value&lt;br /&gt;
  );&lt;br /&gt;
  filterUpgrade(&lt;br /&gt;
    characterCreation.weaponUpgrade,&lt;br /&gt;
    weaponElement.value,&lt;br /&gt;
    characters.randomAttackValue,&lt;br /&gt;
    characters.randomMagicAttackValue&lt;br /&gt;
  );&lt;br /&gt;
  for (var [targetName, sibling] of Object.entries(characters.toggleSiblings)) {&lt;br /&gt;
    filterCheckbox(characterCreation[targetName], sibling);&lt;br /&gt;
  }&lt;br /&gt;
  filterSkills(classChoice.value, characters.skillElementsToFilter);&lt;br /&gt;
  handleBonusVariationUpdate(characterCreation, characters.bonusVariation);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleClickOnCharacter(&lt;br /&gt;
  spanInput,&lt;br /&gt;
  target,&lt;br /&gt;
  characters,&lt;br /&gt;
  characterElement,&lt;br /&gt;
  battle,&lt;br /&gt;
  edition&lt;br /&gt;
) {&lt;br /&gt;
  var displayedPseudo = characters.characterCreation.name.value;&lt;br /&gt;
  var pseudo = spanInput.dataset.name;&lt;br /&gt;
  var { unsavedWarning, deleteWarning } = characters.defaultText;&lt;br /&gt;
&lt;br /&gt;
  if (edition) {&lt;br /&gt;
    if (!characters.unsavedChanges) {&lt;br /&gt;
      updateForm(&lt;br /&gt;
        characters.savedCharacters[pseudo],&lt;br /&gt;
        characters.characterCreation,&lt;br /&gt;
        characters,&lt;br /&gt;
        characterElement,&lt;br /&gt;
        battle&lt;br /&gt;
      );&lt;br /&gt;
    } else if (displayedPseudo === pseudo) {&lt;br /&gt;
      // pass&lt;br /&gt;
    } else {&lt;br /&gt;
      var result = confirm(unsavedWarning);&lt;br /&gt;
&lt;br /&gt;
      if (result) {&lt;br /&gt;
        updateForm(&lt;br /&gt;
          characters.savedCharacters[pseudo],&lt;br /&gt;
          characters.characterCreation,&lt;br /&gt;
          characters,&lt;br /&gt;
          characterElement,&lt;br /&gt;
          battle&lt;br /&gt;
        );&lt;br /&gt;
        characters.unsavedChanges = false;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    if (target.tagName === &amp;quot;path&amp;quot;) {&lt;br /&gt;
      target = target.parentElement;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    switch (target.dataset.icon) {&lt;br /&gt;
      case &amp;quot;duplicate&amp;quot;:&lt;br /&gt;
        if (!characters.unsavedChanges) {&lt;br /&gt;
          addNewCharacter(&lt;br /&gt;
            characters,&lt;br /&gt;
            characters.newCharacterTemplate,&lt;br /&gt;
            characters.charactersContainer,&lt;br /&gt;
            battle,&lt;br /&gt;
            pseudo&lt;br /&gt;
          );&lt;br /&gt;
        } else {&lt;br /&gt;
          var result = confirm(unsavedWarning);&lt;br /&gt;
&lt;br /&gt;
          if (result) {&lt;br /&gt;
            addNewCharacter(&lt;br /&gt;
              characters,&lt;br /&gt;
              characters.newCharacterTemplate,&lt;br /&gt;
              characters.charactersContainer,&lt;br /&gt;
              battle,&lt;br /&gt;
              pseudo&lt;br /&gt;
            );&lt;br /&gt;
            saveButtonGreen(characters.saveButton);&lt;br /&gt;
            characters.unsavedChanges = false;&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
        break;&lt;br /&gt;
&lt;br /&gt;
      case &amp;quot;download&amp;quot;:&lt;br /&gt;
        var character = characters.savedCharacters[pseudo];&lt;br /&gt;
        downloadData(&lt;br /&gt;
          JSON.stringify(character),&lt;br /&gt;
          &amp;quot;text/plain&amp;quot;,&lt;br /&gt;
          character.name + &amp;quot;.txt&amp;quot;&lt;br /&gt;
        );&lt;br /&gt;
        break;&lt;br /&gt;
&lt;br /&gt;
      case &amp;quot;delete&amp;quot;:&lt;br /&gt;
        var result = confirm(deleteWarning.replace(&amp;quot;[[]]&amp;quot;, pseudo));&lt;br /&gt;
        if (result) {&lt;br /&gt;
          deleteCharacter(characters, pseudo, characterElement, battle);&lt;br /&gt;
        }&lt;br /&gt;
        break;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleNewCharacter(&lt;br /&gt;
  characters,&lt;br /&gt;
  characterTemplate,&lt;br /&gt;
  charactersContainer,&lt;br /&gt;
  battle,&lt;br /&gt;
  pseudo&lt;br /&gt;
) {&lt;br /&gt;
  var newCharacterTemplate = characterTemplate.cloneNode(true);&lt;br /&gt;
  var spanInput = newCharacterTemplate.querySelector(&amp;quot;span.input&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  newCharacterTemplate.setAttribute(&amp;quot;tabindex&amp;quot;, &amp;quot;0&amp;quot;);&lt;br /&gt;
  charactersContainer.appendChild(newCharacterTemplate);&lt;br /&gt;
&lt;br /&gt;
  if (pseudo) {&lt;br /&gt;
    spanInput.textContent = pseudo;&lt;br /&gt;
    spanInput.setAttribute(&amp;quot;data-name&amp;quot;, pseudo);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  newCharacterTemplate.addEventListener(&amp;quot;click&amp;quot;, function (event) {&lt;br /&gt;
    var target = event.target;&lt;br /&gt;
&lt;br /&gt;
    if (target.tagName === &amp;quot;path&amp;quot; || target.tagName === &amp;quot;svg&amp;quot;) {&lt;br /&gt;
      handleClickOnCharacter(&lt;br /&gt;
        spanInput,&lt;br /&gt;
        target,&lt;br /&gt;
        characters,&lt;br /&gt;
        newCharacterTemplate,&lt;br /&gt;
        battle&lt;br /&gt;
      );&lt;br /&gt;
    } else {&lt;br /&gt;
      handleClickOnCharacter(&lt;br /&gt;
        spanInput,&lt;br /&gt;
        null,&lt;br /&gt;
        characters,&lt;br /&gt;
        newCharacterTemplate,&lt;br /&gt;
        battle,&lt;br /&gt;
        true&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  newCharacterTemplate.addEventListener(&amp;quot;keydown&amp;quot;, function (event) {&lt;br /&gt;
    if (event.keyCode === 13) {&lt;br /&gt;
      event.target.click();&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  return [newCharacterTemplate, spanInput];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function validPseudo(pseudo, defaultPseudo) {&lt;br /&gt;
  var newPseudo = pseudoFormat(pseudo);&lt;br /&gt;
&lt;br /&gt;
  if (!newPseudo) {&lt;br /&gt;
    return pseudoFormat(defaultPseudo);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return newPseudo;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addNewCharacter(&lt;br /&gt;
  characters,&lt;br /&gt;
  characterTemplate,&lt;br /&gt;
  charactersContainer,&lt;br /&gt;
  battle,&lt;br /&gt;
  pseudoToDuplicate&lt;br /&gt;
) {&lt;br /&gt;
  function editAndSetCharacterPseudoInput(selectedCharacter, spanInput) {&lt;br /&gt;
    var maxPseudoLength = 20;&lt;br /&gt;
    var defaultPseudo = characters.defaultText.pseudo;&lt;br /&gt;
&lt;br /&gt;
    var selection = window.getSelection();&lt;br /&gt;
    var range = document.createRange();&lt;br /&gt;
&lt;br /&gt;
    if (pseudoToDuplicate) {&lt;br /&gt;
      spanInput.textContent = pseudoToDuplicate;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    spanInput.contentEditable = true;&lt;br /&gt;
    spanInput.focus();&lt;br /&gt;
    range.selectNodeContents(spanInput);&lt;br /&gt;
    selection.removeAllRanges();&lt;br /&gt;
    selection.addRange(range);&lt;br /&gt;
&lt;br /&gt;
    function pseudoValidation() {&lt;br /&gt;
      var characterPseudo = validPseudo(spanInput.textContent, defaultPseudo);&lt;br /&gt;
      var characterDataObject = { name: characterPseudo };&lt;br /&gt;
&lt;br /&gt;
      if (pseudoToDuplicate) {&lt;br /&gt;
        characterDataObject = copyObject(&lt;br /&gt;
          characters.savedCharacters[pseudoToDuplicate]&lt;br /&gt;
        );&lt;br /&gt;
        characterDataObject.name = characterPseudo;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      [characterDataObject, characterPseudo] = addUniquePseudo(&lt;br /&gt;
        characterDataObject,&lt;br /&gt;
        Object.keys(characters.savedCharacters)&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      selection.removeAllRanges();&lt;br /&gt;
      spanInput.contentEditable = false;&lt;br /&gt;
      spanInput.textContent = characterPseudo;&lt;br /&gt;
      spanInput.setAttribute(&amp;quot;data-name&amp;quot;, characterPseudo);&lt;br /&gt;
&lt;br /&gt;
      updateForm(&lt;br /&gt;
        characterDataObject,&lt;br /&gt;
        characters.characterCreation,&lt;br /&gt;
        characters,&lt;br /&gt;
        selectedCharacter,&lt;br /&gt;
        battle&lt;br /&gt;
      );&lt;br /&gt;
      saveCharacter(&lt;br /&gt;
        characters.savedCharacters,&lt;br /&gt;
        characters.characterCreation,&lt;br /&gt;
        battle,&lt;br /&gt;
        true&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handleMaxLength(event) {&lt;br /&gt;
      if (spanInput.textContent.length &amp;gt; maxPseudoLength) {&lt;br /&gt;
        spanInput.textContent = spanInput.textContent.slice(0, maxPseudoLength);&lt;br /&gt;
        range.setStart(spanInput.childNodes[0], maxPseudoLength);&lt;br /&gt;
        selection.removeAllRanges();&lt;br /&gt;
        selection.addRange(range);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handleBlur() {&lt;br /&gt;
      spanInput.removeEventListener(&amp;quot;blur&amp;quot;, handleBlur);&lt;br /&gt;
      spanInput.removeEventListener(&amp;quot;input&amp;quot;, handleMaxLength);&lt;br /&gt;
      pseudoValidation();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handleKeyDown(event) {&lt;br /&gt;
      if (event.key === &amp;quot;Enter&amp;quot;) {&lt;br /&gt;
        event.preventDefault();&lt;br /&gt;
&lt;br /&gt;
        spanInput.removeEventListener(&amp;quot;keydown&amp;quot;, handleKeyDown);&lt;br /&gt;
        spanInput.removeEventListener(&amp;quot;blur&amp;quot;, handleBlur);&lt;br /&gt;
        spanInput.removeEventListener(&amp;quot;input&amp;quot;, handleMaxLength);&lt;br /&gt;
&lt;br /&gt;
        pseudoValidation();&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    spanInput.addEventListener(&amp;quot;input&amp;quot;, handleMaxLength);&lt;br /&gt;
    spanInput.addEventListener(&amp;quot;keydown&amp;quot;, handleKeyDown);&lt;br /&gt;
    spanInput.addEventListener(&amp;quot;blur&amp;quot;, handleBlur);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  hideElement(characters.characterCreation);&lt;br /&gt;
  var [selectedCharacter, spanInput] = handleNewCharacter(&lt;br /&gt;
    characters,&lt;br /&gt;
    characterTemplate,&lt;br /&gt;
    charactersContainer,&lt;br /&gt;
    battle&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  editAndSetCharacterPseudoInput(selectedCharacter, spanInput);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleFocus() {&lt;br /&gt;
  var tooltipLinks = document.querySelectorAll(&amp;quot;div.tooltip a&amp;quot;);&lt;br /&gt;
  tooltipLinks.forEach(function (link) {&lt;br /&gt;
    link.setAttribute(&amp;quot;tabindex&amp;quot;, -1);&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function resetBonusVariation(bonusVariation) {&lt;br /&gt;
  function resetInput(input) {&lt;br /&gt;
    input.removeAttribute(&amp;quot;min&amp;quot;);&lt;br /&gt;
    input.removeAttribute(&amp;quot;max&amp;quot;);&lt;br /&gt;
    input.defaultValue = 0;&lt;br /&gt;
    input.value = input.defaultValue;&lt;br /&gt;
  }&lt;br /&gt;
  var { minValue, maxValue, checkbox, container, disabledText, selectedText } =&lt;br /&gt;
    bonusVariation;&lt;br /&gt;
&lt;br /&gt;
  resetInput(minValue);&lt;br /&gt;
  resetInput(maxValue);&lt;br /&gt;
  showElement(disabledText);&lt;br /&gt;
  hideElement(selectedText);&lt;br /&gt;
  hideElement(container);&lt;br /&gt;
  checkbox.checked = false;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleBonusVariationUpdate(&lt;br /&gt;
  characterCreation,&lt;br /&gt;
  bonusVariation,&lt;br /&gt;
  resetSkill&lt;br /&gt;
) {&lt;br /&gt;
  var selectedBonus = characterCreation.bonusVariation.value;&lt;br /&gt;
  var displayName = characterCreation.bonusVariationName.value;&lt;br /&gt;
&lt;br /&gt;
  if (&lt;br /&gt;
    resetSkill &amp;amp;&amp;amp;&lt;br /&gt;
    (selectedBonus.startsWith(&amp;quot;attackSkill&amp;quot;) ||&lt;br /&gt;
      selectedBonus.startsWith(&amp;quot;horseSkill&amp;quot;) ||&lt;br /&gt;
      selectedBonus.startsWith(&amp;quot;skillBonus&amp;quot;))&lt;br /&gt;
  ) {&lt;br /&gt;
    resetBonusVariation(bonusVariation);&lt;br /&gt;
    return;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (&lt;br /&gt;
    characterCreation.hasOwnProperty(selectedBonus) &amp;amp;&amp;amp;&lt;br /&gt;
    selectedBonus != 0 &amp;amp;&amp;amp;&lt;br /&gt;
    displayName != 0&lt;br /&gt;
  ) {&lt;br /&gt;
    handleBonusVariation(&lt;br /&gt;
      characterCreation[selectedBonus],&lt;br /&gt;
      bonusVariation,&lt;br /&gt;
      displayName&lt;br /&gt;
    );&lt;br /&gt;
  } else {&lt;br /&gt;
    resetBonusVariation(bonusVariation);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getTargetContent(targetParent, targetName, isSkill) {&lt;br /&gt;
  var targetContent = &amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  if (targetParent.children.length &amp;lt;= 1) {&lt;br /&gt;
    targetContent = targetParent.textContent;&lt;br /&gt;
  } else if (targetName === &amp;quot;weaponUpgrade&amp;quot;) {&lt;br /&gt;
    targetContent = targetParent.children[1].textContent;&lt;br /&gt;
  } else if (targetName === &amp;quot;level&amp;quot;) {&lt;br /&gt;
    targetContent = targetParent.textContent.replace(&amp;quot;Lv&amp;quot;, &amp;quot;&amp;quot;).trim();&lt;br /&gt;
  } else if (isSkill) {&lt;br /&gt;
    var container = targetParent.children[1];&lt;br /&gt;
&lt;br /&gt;
    for (var index = 0; index &amp;lt; container.children.length; index++) {&lt;br /&gt;
      var element = container.children[index];&lt;br /&gt;
&lt;br /&gt;
      if (element.checkVisibility()) {&lt;br /&gt;
        targetContent += element.textContent;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    for (var index = 1; index &amp;lt; targetParent.children.length; index++) {&lt;br /&gt;
      var element = targetParent.children[index];&lt;br /&gt;
&lt;br /&gt;
      if (element.checkVisibility()) {&lt;br /&gt;
        targetContent += element.textContent;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return targetContent.trim();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleBonusVariation(target, bonusVariation, displayName) {&lt;br /&gt;
  var {&lt;br /&gt;
    minValue,&lt;br /&gt;
    maxValue,&lt;br /&gt;
    checkbox,&lt;br /&gt;
    container,&lt;br /&gt;
    disabledText,&lt;br /&gt;
    selectedText,&lt;br /&gt;
    displaySpan,&lt;br /&gt;
  } = bonusVariation;&lt;br /&gt;
&lt;br /&gt;
  var {&lt;br /&gt;
    min: targetMin,&lt;br /&gt;
    max: targetMax,&lt;br /&gt;
    name: targetName,&lt;br /&gt;
    value: targetValue,&lt;br /&gt;
    parentElement: targetParent,&lt;br /&gt;
    tagName,&lt;br /&gt;
  } = target;&lt;br /&gt;
&lt;br /&gt;
  targetMin = Number(targetMin);&lt;br /&gt;
  targetMax = Number(targetMax);&lt;br /&gt;
  targetValue = Number(targetValue);&lt;br /&gt;
&lt;br /&gt;
  var isSkill = tagName === &amp;quot;SELECT&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  if (isSkill) {&lt;br /&gt;
    var options = target.options;&lt;br /&gt;
&lt;br /&gt;
    targetMin = options[0].value;&lt;br /&gt;
    targetMax = options[options.length - 1].value;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  minValue.min = targetMin;&lt;br /&gt;
  minValue.max = targetMax;&lt;br /&gt;
  minValue.defaultValue = targetMin;&lt;br /&gt;
&lt;br /&gt;
  maxValue.min = targetMin;&lt;br /&gt;
  maxValue.max = targetMax;&lt;br /&gt;
  maxValue.defaultValue = targetMin;&lt;br /&gt;
&lt;br /&gt;
  hideElement(disabledText);&lt;br /&gt;
  showElement(selectedText);&lt;br /&gt;
&lt;br /&gt;
  if (displayName) {&lt;br /&gt;
    minValue.value = Math.min(Math.max(minValue.value, targetMin), targetMax);&lt;br /&gt;
    maxValue.value = Math.max(Math.min(maxValue.value, targetMax), targetMin);&lt;br /&gt;
&lt;br /&gt;
    displaySpan.textContent = displayName;&lt;br /&gt;
  } else {&lt;br /&gt;
    var { input, inputName, tabButton } = bonusVariation;&lt;br /&gt;
    var targetContent = getTargetContent(targetParent, targetName, isSkill);&lt;br /&gt;
&lt;br /&gt;
    input.value = targetName;&lt;br /&gt;
    inputName.value = targetContent;&lt;br /&gt;
    displaySpan.textContent = targetContent;&lt;br /&gt;
&lt;br /&gt;
    minValue.value = Math.max(targetValue - 10, targetMin);&lt;br /&gt;
    maxValue.value = Math.min(targetValue + 10, targetMax);&lt;br /&gt;
&lt;br /&gt;
    showElement(container);&lt;br /&gt;
    checkbox.checked = true;&lt;br /&gt;
&lt;br /&gt;
    tabButton.click();&lt;br /&gt;
    tabButton.scrollIntoView(true);&lt;br /&gt;
&lt;br /&gt;
    input.dispatchEvent(newChangeEvent());&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function characterManagement(characters, battle) {&lt;br /&gt;
  var {&lt;br /&gt;
    newCharacterTemplate: characterTemplate,&lt;br /&gt;
    charactersContainer,&lt;br /&gt;
    addNewCharacterButton,&lt;br /&gt;
    saveButton,&lt;br /&gt;
    characterCreation,&lt;br /&gt;
    bonusVariation,&lt;br /&gt;
    defaultText: { unsavedWarning },&lt;br /&gt;
  } = characters;&lt;br /&gt;
&lt;br /&gt;
  Object.keys(characters.savedCharacters).forEach(function (pseudo) {&lt;br /&gt;
    handleNewCharacter(&lt;br /&gt;
      characters,&lt;br /&gt;
      characterTemplate,&lt;br /&gt;
      charactersContainer,&lt;br /&gt;
      battle,&lt;br /&gt;
      pseudo&lt;br /&gt;
    );&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  addNewCharacterButton.addEventListener(&amp;quot;click&amp;quot;, function (event) {&lt;br /&gt;
    if (!characters.unsavedChanges) {&lt;br /&gt;
      addNewCharacter(&lt;br /&gt;
        characters,&lt;br /&gt;
        characterTemplate,&lt;br /&gt;
        charactersContainer,&lt;br /&gt;
        battle&lt;br /&gt;
      );&lt;br /&gt;
    } else {&lt;br /&gt;
      var result = confirm(unsavedWarning);&lt;br /&gt;
&lt;br /&gt;
      if (result) {&lt;br /&gt;
        addNewCharacter(&lt;br /&gt;
          characters,&lt;br /&gt;
          characterTemplate,&lt;br /&gt;
          charactersContainer,&lt;br /&gt;
          battle&lt;br /&gt;
        );&lt;br /&gt;
        saveButtonGreen(saveButton);&lt;br /&gt;
        characters.unsavedChanges = false;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  handleUploadCharacter(&lt;br /&gt;
    characters,&lt;br /&gt;
    characterTemplate,&lt;br /&gt;
    charactersContainer,&lt;br /&gt;
    battle&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  function handleLongPress(target) {&lt;br /&gt;
    if (target.tagName !== &amp;quot;INPUT&amp;quot; &amp;amp;&amp;amp; target.tagName !== &amp;quot;SELECT&amp;quot;) {&lt;br /&gt;
      target = target.querySelector(&amp;quot;input&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      !target ||&lt;br /&gt;
      (target.type !== &amp;quot;number&amp;quot; &amp;amp;&amp;amp;&lt;br /&gt;
        !target.classList.contains(&amp;quot;skill-select&amp;quot;) &amp;amp;&amp;amp;&lt;br /&gt;
        target.name !== &amp;quot;weaponUpgrade&amp;quot;) ||&lt;br /&gt;
      target.classList.contains(&amp;quot;disabled-variation&amp;quot;)&lt;br /&gt;
    ) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    handleBonusVariation(target, bonusVariation, null);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;click&amp;quot;, function (event) {&lt;br /&gt;
    if (event.shiftKey || event.ctrlKey) {&lt;br /&gt;
      handleLongPress(event.target);&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  var longPressTimer;&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;touchstart&amp;quot;, function (event) {&lt;br /&gt;
    longPressTimer = setTimeout(function () {&lt;br /&gt;
      handleLongPress(event.target);&lt;br /&gt;
    }, 800);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;touchend&amp;quot;, function () {&lt;br /&gt;
    clearTimeout(longPressTimer);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;touchmove&amp;quot;, function () {&lt;br /&gt;
    clearTimeout(longPressTimer);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  filterForm(characters, battle);&lt;br /&gt;
  characterCreationListener(characters, battle);&lt;br /&gt;
  handleFocus();&lt;br /&gt;
&lt;br /&gt;
  window.addEventListener(&amp;quot;beforeunload&amp;quot;, function (event) {&lt;br /&gt;
    if (characters.unsavedChanges) {&lt;br /&gt;
      event.preventDefault();&lt;br /&gt;
      return &amp;quot;&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addMonsterElement(characters, battle, monsterVnum, iframeInfo) {&lt;br /&gt;
  var { monsterTemplate, monstersContainer } = characters;&lt;br /&gt;
  var monsterElement = monsterTemplate.cloneNode(true);&lt;br /&gt;
  var spanInput = monsterElement.querySelector(&amp;quot;span.input&amp;quot;);&lt;br /&gt;
  var deleteSvg = monsterElement.querySelector(&amp;quot;svg&amp;quot;);&lt;br /&gt;
  var monsterName = getMonsterName(monsterVnum);&lt;br /&gt;
  var displayName = characters.translateMonsters&lt;br /&gt;
    ? getTranslatedMonsterName(monsterVnum)&lt;br /&gt;
    : monsterName;&lt;br /&gt;
  var link = createWikiLink(monsterName, displayName);&lt;br /&gt;
&lt;br /&gt;
  monsterElement.setAttribute(&amp;quot;tabindex&amp;quot;, &amp;quot;0&amp;quot;);&lt;br /&gt;
  spanInput.appendChild(link);&lt;br /&gt;
  monstersContainer.appendChild(monsterElement);&lt;br /&gt;
  characters.monsterElements[monsterVnum] = monsterElement;&lt;br /&gt;
&lt;br /&gt;
  deleteSvg.addEventListener(&amp;quot;click&amp;quot;, function () {&lt;br /&gt;
    var monster = characters.savedMonsters[monsterVnum];&lt;br /&gt;
    iframeInfo[monster.category].shouldBeUpdated = true;&lt;br /&gt;
&lt;br /&gt;
    deleteMonster(characters, battle, monsterVnum);&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addNewMonster(&lt;br /&gt;
  characters,&lt;br /&gt;
  battle,&lt;br /&gt;
  monsterVnum,&lt;br /&gt;
  monsterImage,&lt;br /&gt;
  iframeInfo,&lt;br /&gt;
  category&lt;br /&gt;
) {&lt;br /&gt;
  if (isValueInArray(monsterVnum, Object.keys(characters.savedMonsters)))&lt;br /&gt;
    return;&lt;br /&gt;
&lt;br /&gt;
  var newMonster = {&lt;br /&gt;
    image: monsterImage,&lt;br /&gt;
    category: category,&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  characters.savedMonsters[monsterVnum] = newMonster;&lt;br /&gt;
&lt;br /&gt;
  addMonsterElement(characters, battle, monsterVnum, iframeInfo);&lt;br /&gt;
  updateSavedMonsters(characters.savedMonsters);&lt;br /&gt;
  addBattleChoice(battle.battleChoice, monsterVnum, newMonster, true);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function translateiFrame(iframeDoc) {&lt;br /&gt;
  const filterName = iframeDoc.getElementById(&amp;quot;filter-name&amp;quot;);&lt;br /&gt;
  const { general, special } = translation;&lt;br /&gt;
  const translatedPlaceholder = special.placeholder;&lt;br /&gt;
&lt;br /&gt;
  if (filterName &amp;amp;&amp;amp; translatedPlaceholder) {&lt;br /&gt;
    filterName.placeholder = translatedPlaceholder;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (const element of iframeDoc.querySelectorAll(&amp;quot;[data-t]&amp;quot;)) {&lt;br /&gt;
    const translateText = general[element.dataset.t];&lt;br /&gt;
&lt;br /&gt;
    if (translateText) {&lt;br /&gt;
      element.textContent = translateText;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function translateMonsterCard(card, cardNameElement, monsterVnum) {&lt;br /&gt;
  const mapping = translation.mapping;&lt;br /&gt;
  const levelElement = card.querySelector(&amp;quot;[data-level]&amp;quot;);&lt;br /&gt;
  const typeElement = card.querySelector(&amp;quot;[data-type] a&amp;quot;);&lt;br /&gt;
  const damageElements = card.querySelectorAll(&amp;quot;[data-damage] a&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  cardNameElement.textContent = getTranslatedMonsterName(monsterVnum);&lt;br /&gt;
&lt;br /&gt;
  levelElement.textContent = levelElement.textContent.replace(&lt;br /&gt;
    &amp;quot;Boss&amp;quot;,&lt;br /&gt;
    translation.special.boss&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  if (typeElement) {&lt;br /&gt;
    typeElement.textContent = mapping[typeElement.textContent];&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  damageElements.forEach((damageElement) =&amp;gt; {&lt;br /&gt;
    damageElement.textContent = mapping[damageElement.textContent];&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addButtonsToCardsAndTranslate(&lt;br /&gt;
  characters,&lt;br /&gt;
  iframeDoc,&lt;br /&gt;
  iframeInfo,&lt;br /&gt;
  category&lt;br /&gt;
) {&lt;br /&gt;
  const buttonTemplates = characters.monsterButtonTemplates.children[0];&lt;br /&gt;
  const cardToEdit = iframeDoc.getElementById(&amp;quot;cards-container&amp;quot;).children;&lt;br /&gt;
  const { nameToVnum } = iframeInfo;&lt;br /&gt;
  const vnumToButtons = iframeInfo[category].vnumToButtons;&lt;br /&gt;
  const translateMonsters = characters.translateMonsters;&lt;br /&gt;
&lt;br /&gt;
  for (let cardIndex = 0; cardIndex &amp;lt; cardToEdit.length; cardIndex++) {&lt;br /&gt;
    const card = cardToEdit[cardIndex];&lt;br /&gt;
    const cardNameElement = card.querySelector(&amp;quot;[data-name]&amp;quot;).firstChild;&lt;br /&gt;
    const buttonTemplatesClone = buttonTemplates.cloneNode(true);&lt;br /&gt;
    const cardName = cardNameElement.title.replace(/\s/g, &amp;quot; &amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (!nameToVnum.hasOwnProperty(cardName)) {&lt;br /&gt;
      card.style.display = &amp;quot;none&amp;quot;;&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    const monsterVnum = nameToVnum[cardName];&lt;br /&gt;
&lt;br /&gt;
    buttonTemplatesClone.dataset.monsterId = monsterVnum;&lt;br /&gt;
    card.lastElementChild.appendChild(buttonTemplatesClone);&lt;br /&gt;
    vnumToButtons[monsterVnum] = buttonTemplatesClone.children;&lt;br /&gt;
&lt;br /&gt;
    if (translateMonsters) {&lt;br /&gt;
      translateMonsterCard(card, cardNameElement, monsterVnum);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (translateMonsters) {&lt;br /&gt;
    translateiFrame(iframeDoc);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateiFrameButtons(characters, iframeInfo, category) {&lt;br /&gt;
  var addedMonsters = Object.keys(characters.savedMonsters);&lt;br /&gt;
  var { currentiFrameIsMonster } = iframeInfo;&lt;br /&gt;
  var vnumToButtons = iframeInfo[category].vnumToButtons;&lt;br /&gt;
  var isPolymorphModal = category === &amp;quot;monster&amp;quot; &amp;amp;&amp;amp; !currentiFrameIsMonster;&lt;br /&gt;
&lt;br /&gt;
  for (var monsterVnum in vnumToButtons) {&lt;br /&gt;
    var [addButton, deleteButton, selectButton] = vnumToButtons[monsterVnum];&lt;br /&gt;
&lt;br /&gt;
    if (isPolymorphModal) {&lt;br /&gt;
      hideElement(addButton);&lt;br /&gt;
      hideElement(deleteButton);&lt;br /&gt;
      showElement(selectButton);&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isValueInArray(monsterVnum, addedMonsters)) {&lt;br /&gt;
      hideElement(addButton);&lt;br /&gt;
      showElement(deleteButton);&lt;br /&gt;
      hideElement(selectButton);&lt;br /&gt;
    } else {&lt;br /&gt;
      showElement(addButton);&lt;br /&gt;
      hideElement(deleteButton);&lt;br /&gt;
      hideElement(selectButton);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  iframeInfo.lastiFrameIsMonster = currentiFrameIsMonster;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getMonsterImage(buttonsContainer) {&lt;br /&gt;
  var elder = buttonsContainer.parentElement.firstElementChild;&lt;br /&gt;
  var image = elder.querySelector(&amp;quot;img&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (image) {&lt;br /&gt;
    return image.getAttribute(&amp;quot;src&amp;quot;) || &amp;quot;&amp;quot;;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return &amp;quot;&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleiFrame(iframeInfo, category) {&lt;br /&gt;
  var { characters, battle } = iframeInfo;&lt;br /&gt;
  var iframeInfoCategory = iframeInfo[category];&lt;br /&gt;
  var { iframe, pageName, vnumToButtons } = iframeInfoCategory;&lt;br /&gt;
  var loadingAnimation = iframeInfoCategory.iframe.previousElementSibling;&lt;br /&gt;
&lt;br /&gt;
  iframe.src = mw.util.getUrl(pageName);&lt;br /&gt;
&lt;br /&gt;
  window.addEventListener(&amp;quot;message&amp;quot;, function (event) {&lt;br /&gt;
    if (&lt;br /&gt;
      event.origin !== window.origin ||&lt;br /&gt;
      event.data?.type !== &amp;quot;filterReady&amp;quot; ||&lt;br /&gt;
      event.data.category !== category&lt;br /&gt;
    ) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
    var iframeDoc = iframe.contentDocument || iframe.contentWindow.document;&lt;br /&gt;
    var htmlElement = iframeDoc.documentElement;&lt;br /&gt;
    var iframeBody = iframeDoc.body;&lt;br /&gt;
    var content = iframeDoc.getElementById(&amp;quot;show-after-loading&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    htmlElement.setAttribute(&amp;quot;lang&amp;quot;, characters.currentLanguage);&lt;br /&gt;
    iframeBody.firstElementChild.replaceWith(content);&lt;br /&gt;
&lt;br /&gt;
    iframeBody.style.background = &amp;quot;transparent&amp;quot;;&lt;br /&gt;
    iframeBody.style.paddingRight = &amp;quot;10px&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    addButtonsToCardsAndTranslate(characters, iframeDoc, iframeInfo, category);&lt;br /&gt;
    updateiFrameButtons(characters, iframeInfo, category);&lt;br /&gt;
&lt;br /&gt;
    iframeInfoCategory.loadIsFinished = true;&lt;br /&gt;
&lt;br /&gt;
    hideElement(loadingAnimation);&lt;br /&gt;
    showElement(iframe);&lt;br /&gt;
&lt;br /&gt;
    iframeDoc.addEventListener(&amp;quot;click&amp;quot;, handleButtonClick);&lt;br /&gt;
&lt;br /&gt;
    function handleButtonClick(event) {&lt;br /&gt;
      var target = event.target;&lt;br /&gt;
      var link = target.closest(&amp;quot;a&amp;quot;);&lt;br /&gt;
      var buttonsContainer = target.closest(&amp;quot;.handle-monster&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
      if (link) {&lt;br /&gt;
        event.preventDefault();&lt;br /&gt;
        window.open(link.href, &amp;quot;_blank&amp;quot;);&lt;br /&gt;
      } else if (buttonsContainer) {&lt;br /&gt;
        var { monsterId: monsterVnum } = buttonsContainer.dataset;&lt;br /&gt;
&lt;br /&gt;
        // polymorph iframe&lt;br /&gt;
        if (category === &amp;quot;monster&amp;quot; &amp;amp;&amp;amp; !iframeInfo.currentiFrameIsMonster) {&lt;br /&gt;
          var monsterImage = getMonsterImage(buttonsContainer);&lt;br /&gt;
          changePolymorphValues(&lt;br /&gt;
            characters.characterCreation,&lt;br /&gt;
            monsterVnum,&lt;br /&gt;
            monsterImage&lt;br /&gt;
          );&lt;br /&gt;
          handlePolymorphDisplay(characters, monsterVnum, monsterImage);&lt;br /&gt;
          iframe.dispatchEvent(newChangeEvent());&lt;br /&gt;
        } else {&lt;br /&gt;
          var addedMonsters = Object.keys(characters.savedMonsters);&lt;br /&gt;
          var [addButton, deleteButton] = vnumToButtons[monsterVnum];&lt;br /&gt;
&lt;br /&gt;
          if (isValueInArray(monsterVnum, addedMonsters)) {&lt;br /&gt;
            deleteMonster(characters, battle, monsterVnum);&lt;br /&gt;
            showElement(addButton);&lt;br /&gt;
            hideElement(deleteButton);&lt;br /&gt;
          } else {&lt;br /&gt;
            var monsterImage = getMonsterImage(buttonsContainer);&lt;br /&gt;
            addNewMonster(&lt;br /&gt;
              characters,&lt;br /&gt;
              battle,&lt;br /&gt;
              monsterVnum,&lt;br /&gt;
              monsterImage,&lt;br /&gt;
              iframeInfo,&lt;br /&gt;
              category&lt;br /&gt;
            );&lt;br /&gt;
            hideElement(addButton);&lt;br /&gt;
            showElement(deleteButton);&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getNameToVnumMapping() {&lt;br /&gt;
  var nameToVnum = {};&lt;br /&gt;
&lt;br /&gt;
  for (var monsterVnum in monsterData) {&lt;br /&gt;
    nameToVnum[monsterData[monsterVnum][monsterData[monsterVnum].length - 1]] =&lt;br /&gt;
      monsterVnum;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return nameToVnum;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function monsterManagement(characters, battle) {&lt;br /&gt;
  var { monsteriFrame, stoneiFrame } = characters;&lt;br /&gt;
  var monsterVnums = Object.keys(monsterData);&lt;br /&gt;
&lt;br /&gt;
  var iframeInfo = {&lt;br /&gt;
    lastiFrameIsMonster: false,&lt;br /&gt;
    currentiFrameIsMonster: false,&lt;br /&gt;
    characters: characters,&lt;br /&gt;
    battle: battle,&lt;br /&gt;
    nameToVnum: getNameToVnumMapping(),&lt;br /&gt;
    monster: {&lt;br /&gt;
      isLoaded: false,&lt;br /&gt;
      loadIsFinished: false,&lt;br /&gt;
      shouldBeUpdated: false,&lt;br /&gt;
      vnumToButtons: {},&lt;br /&gt;
      pageName: &amp;quot;Monstres&amp;quot;,&lt;br /&gt;
      iframe: monsteriFrame,&lt;br /&gt;
    },&lt;br /&gt;
    stone: {&lt;br /&gt;
      isLoaded: false,&lt;br /&gt;
      loadIsFinished: false,&lt;br /&gt;
      shouldBeUpdated: false,&lt;br /&gt;
      vnumToButtons: {},&lt;br /&gt;
      pageName: &amp;quot;Pierres Metin&amp;quot;,&lt;br /&gt;
      iframe: stoneiFrame,&lt;br /&gt;
    },&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  document.addEventListener(&amp;quot;modalOpen&amp;quot;, function (event) {&lt;br /&gt;
    var modalName = event.detail.name;&lt;br /&gt;
&lt;br /&gt;
    if (modalName === &amp;quot;monster&amp;quot; || modalName === &amp;quot;stone&amp;quot;) {&lt;br /&gt;
      handleModal(event.target, modalName);&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  function handleModal(target, modalName) {&lt;br /&gt;
    var iframeInfoCategory = iframeInfo[modalName];&lt;br /&gt;
&lt;br /&gt;
    if (modalName === &amp;quot;monster&amp;quot;) {&lt;br /&gt;
      var isMonsteriFrame = target.id === &amp;quot;add-new-monster&amp;quot;;&lt;br /&gt;
      iframeInfo.currentiFrameIsMonster = isMonsteriFrame;&lt;br /&gt;
&lt;br /&gt;
      if (&lt;br /&gt;
        iframeInfoCategory.loadIsFinished &amp;amp;&amp;amp;&lt;br /&gt;
        ((isMonsteriFrame &amp;amp;&amp;amp; !iframeInfo.lastiFrameIsMonster) ||&lt;br /&gt;
          (!isMonsteriFrame &amp;amp;&amp;amp; iframeInfo.lastiFrameIsMonster))&lt;br /&gt;
      ) {&lt;br /&gt;
        iframeInfoCategory.shouldBeUpdated = true;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!iframeInfoCategory.isLoaded) {&lt;br /&gt;
      handleiFrame(iframeInfo, modalName);&lt;br /&gt;
      iframeInfoCategory.isLoaded = true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      iframeInfoCategory.loadIsFinished &amp;amp;&amp;amp;&lt;br /&gt;
      iframeInfoCategory.shouldBeUpdated&lt;br /&gt;
    ) {&lt;br /&gt;
      updateiFrameButtons(characters, iframeInfo, modalName);&lt;br /&gt;
      iframeInfoCategory.shouldBeUpdated = false;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  Object.keys(characters.savedMonsters)&lt;br /&gt;
    .slice()&lt;br /&gt;
    .forEach(function (monsterVnum) {&lt;br /&gt;
      if (isValueInArray(monsterVnum, monsterVnums)) {&lt;br /&gt;
        addMonsterElement(characters, battle, monsterVnum, iframeInfo);&lt;br /&gt;
      } else {&lt;br /&gt;
        deleteMonster(characters, battle, monsterVnum);&lt;br /&gt;
      }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function hideAttackType(container, input, attackType) {&lt;br /&gt;
  hideElement(container);&lt;br /&gt;
&lt;br /&gt;
  if (input.checked) {&lt;br /&gt;
    var defaultInput = attackType.defaultInput;&lt;br /&gt;
&lt;br /&gt;
    input.checked = false;&lt;br /&gt;
    defaultInput.checked = true;&lt;br /&gt;
    defaultInput.dispatchEvent(newChangeEvent());&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterAttackTypeSelectionCharacter(attacker, attackType) {&lt;br /&gt;
  var attackerClass = attacker.class;&lt;br /&gt;
  var attackerIsNotPolymorph = !isPolymorph(attacker);&lt;br /&gt;
  var { elements: attackTypeElements } = attackType;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; attackTypeElements.length; index++) {&lt;br /&gt;
    var { container, input, inputClass, inputValue } =&lt;br /&gt;
      attackTypeElements[index];&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      attackerIsNotPolymorph &amp;amp;&amp;amp;&lt;br /&gt;
      attacker[inputValue] &amp;amp;&amp;amp;&lt;br /&gt;
      (attackerClass === inputClass ||&lt;br /&gt;
        (inputValue.startsWith(&amp;quot;horseSkill&amp;quot;) &amp;amp;&amp;amp;&lt;br /&gt;
          isRiding(attacker) &amp;amp;&amp;amp;&lt;br /&gt;
          (!inputClass || isValueInArray(attackerClass, inputClass))))&lt;br /&gt;
    ) {&lt;br /&gt;
      showElement(container);&lt;br /&gt;
    } else {&lt;br /&gt;
      hideAttackType(container, input, attackType);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterAttackTypeSelectionMonster(attackType) {&lt;br /&gt;
  var attackTypeElements = attackType.elements;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; attackTypeElements.length; index++) {&lt;br /&gt;
    var { container, input } = attackTypeElements[index];&lt;br /&gt;
    hideAttackType(container, input, attackType);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function removeBattleElement(battleChoice, nameOrVnum, category, type) {&lt;br /&gt;
  var elements = battleChoice[category][type].elements;&lt;br /&gt;
&lt;br /&gt;
  if (elements.hasOwnProperty(nameOrVnum)) {&lt;br /&gt;
    elements[nameOrVnum].container.remove();&lt;br /&gt;
    delete elements[nameOrVnum];&lt;br /&gt;
    battleChoice[category][type].count--;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function removeBattleChoice(battleChoice, nameOrVnum, type) {&lt;br /&gt;
  battleChoice.categories.forEach(function (category) {&lt;br /&gt;
    if (category === &amp;quot;attacker&amp;quot; &amp;amp;&amp;amp; type === &amp;quot;stone&amp;quot;) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
    var selected = battleChoice[category].selected;&lt;br /&gt;
&lt;br /&gt;
    if (selected) {&lt;br /&gt;
      var { type: selectedType, nameOrVnum: selectedNameOrVnum } =&lt;br /&gt;
        parseTypeAndName(selected);&lt;br /&gt;
&lt;br /&gt;
      if (nameOrVnum === selectedNameOrVnum &amp;amp;&amp;amp; type === selectedType) {&lt;br /&gt;
        resetBattleChoiceButton(battleChoice, category);&lt;br /&gt;
        battleChoice[category].selected = null;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    removeBattleElement(battleChoice, nameOrVnum, category, type);&lt;br /&gt;
    updateBattleChoiceText(battleChoice, category, type);&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addBattleElement(&lt;br /&gt;
  battleChoice,&lt;br /&gt;
  pseudoOrVnum,&lt;br /&gt;
  characterOrMonster,&lt;br /&gt;
  category,&lt;br /&gt;
  isMonster&lt;br /&gt;
) {&lt;br /&gt;
  var { template, raceToImage, translateMonsters } = battleChoice;&lt;br /&gt;
  var battleChoiceCategory = battleChoice[category];&lt;br /&gt;
  var templateClone = template.cloneNode(true);&lt;br /&gt;
  var label = templateClone.firstElementChild;&lt;br /&gt;
  var [input, image, span] = label.children;&lt;br /&gt;
  var imageSrc;&lt;br /&gt;
  var name;&lt;br /&gt;
  var type;&lt;br /&gt;
&lt;br /&gt;
  if (isMonster) {&lt;br /&gt;
    type = characterOrMonster.category;&lt;br /&gt;
&lt;br /&gt;
    if (type === &amp;quot;stone&amp;quot; &amp;amp;&amp;amp; category === &amp;quot;attacker&amp;quot;) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
    imageSrc = characterOrMonster.image;&lt;br /&gt;
    name = translateMonsters&lt;br /&gt;
      ? getTranslatedMonsterName(pseudoOrVnum)&lt;br /&gt;
      : getMonsterName(pseudoOrVnum);&lt;br /&gt;
  } else {&lt;br /&gt;
    type = &amp;quot;character&amp;quot;;&lt;br /&gt;
    imageSrc = raceToImage[characterOrMonster.race];&lt;br /&gt;
    name = pseudoOrVnum;&lt;br /&gt;
    label.classList.add(&amp;quot;notranslate&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var value = type + &amp;quot;-&amp;quot; + pseudoOrVnum;&lt;br /&gt;
  var id = category + &amp;quot;-&amp;quot; + value;&lt;br /&gt;
  var currentBattleChoice = battleChoiceCategory[type];&lt;br /&gt;
&lt;br /&gt;
  label.setAttribute(&amp;quot;for&amp;quot;, id);&lt;br /&gt;
  input.value = value;&lt;br /&gt;
  input.id = id;&lt;br /&gt;
  input.name = category;&lt;br /&gt;
  span.textContent = name;&lt;br /&gt;
&lt;br /&gt;
  handleImageFromWiki(image, imageSrc);&lt;br /&gt;
&lt;br /&gt;
  currentBattleChoice.container.appendChild(templateClone);&lt;br /&gt;
  currentBattleChoice.count++;&lt;br /&gt;
  currentBattleChoice.elements[pseudoOrVnum] = {&lt;br /&gt;
    container: templateClone,&lt;br /&gt;
    image: image,&lt;br /&gt;
    name: name,&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  updateBattleChoiceText(battleChoice, category, type);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addBattleChoice(&lt;br /&gt;
  battleChoice,&lt;br /&gt;
  pseudoOrVnum,&lt;br /&gt;
  characterOrMonster,&lt;br /&gt;
  isMonster = false&lt;br /&gt;
) {&lt;br /&gt;
  addBattleElement(&lt;br /&gt;
    battleChoice,&lt;br /&gt;
    pseudoOrVnum,&lt;br /&gt;
    characterOrMonster,&lt;br /&gt;
    &amp;quot;attacker&amp;quot;,&lt;br /&gt;
    isMonster&lt;br /&gt;
  );&lt;br /&gt;
  addBattleElement(&lt;br /&gt;
    battleChoice,&lt;br /&gt;
    pseudoOrVnum,&lt;br /&gt;
    characterOrMonster,&lt;br /&gt;
    &amp;quot;victim&amp;quot;,&lt;br /&gt;
    isMonster&lt;br /&gt;
  );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateBattleChoiceImage(battleChoice, characterName, newRace) {&lt;br /&gt;
  var imageSrc = battleChoice.raceToImage[newRace];&lt;br /&gt;
&lt;br /&gt;
  battleChoice.categories.forEach(function (category) {&lt;br /&gt;
    handleImageFromWiki(&lt;br /&gt;
      battleChoice[category].character.elements[characterName].image,&lt;br /&gt;
      imageSrc&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    var selected = battleChoice[category].selected;&lt;br /&gt;
&lt;br /&gt;
    if (isCharacterSelected(characterName, selected)) {&lt;br /&gt;
      updateBattleChoiceButton(battleChoice, category, selected);&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateBattleChoiceText(battleChoice, category, type) {&lt;br /&gt;
  var { count, container } = battleChoice[category][type];&lt;br /&gt;
  var parentContainer = container.parentElement;&lt;br /&gt;
&lt;br /&gt;
  if (count === 0) {&lt;br /&gt;
    hideElement(parentContainer);&lt;br /&gt;
    showElement(parentContainer.nextElementSibling);&lt;br /&gt;
  } else if (count === 1) {&lt;br /&gt;
    showElement(parentContainer);&lt;br /&gt;
    hideElement(parentContainer.nextElementSibling);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateBattleChoice(characters, battleChoice) {&lt;br /&gt;
  var templateImage = battleChoice.template.querySelector(&amp;quot;img&amp;quot;);&lt;br /&gt;
  var attackerImage = battleChoice.attacker.buttonContent.querySelector(&amp;quot;img&amp;quot;);&lt;br /&gt;
  var victimImage = battleChoice.victim.buttonContent.querySelector(&amp;quot;img&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  resetImageFromWiki(templateImage);&lt;br /&gt;
  resetImageFromWiki(attackerImage);&lt;br /&gt;
  resetImageFromWiki(victimImage);&lt;br /&gt;
&lt;br /&gt;
  for (var [pseudo, character] of Object.entries(characters.savedCharacters)) {&lt;br /&gt;
    addBattleChoice(battleChoice, pseudo, character);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (var [vnum, monster] of Object.entries(characters.savedMonsters)) {&lt;br /&gt;
    addBattleChoice(battleChoice, vnum, monster, true);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateBattleChoiceButton(battleChoice, category, data) {&lt;br /&gt;
  var battleChoiceCategory = battleChoice[category];&lt;br /&gt;
  var { defaultButtonContent, buttonContent } = battleChoiceCategory;&lt;br /&gt;
  var [buttonImage, buttonSpan] = buttonContent.firstElementChild.children;&lt;br /&gt;
  var { type, nameOrVnum } = parseTypeAndName(data);&lt;br /&gt;
  var { name, image } = battleChoiceCategory[type].elements[nameOrVnum];&lt;br /&gt;
&lt;br /&gt;
  hideElement(defaultButtonContent);&lt;br /&gt;
  showElement(buttonContent);&lt;br /&gt;
&lt;br /&gt;
  buttonSpan.textContent = name;&lt;br /&gt;
  buttonImage.src = image.src;&lt;br /&gt;
  battleChoiceCategory.selected = data;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function resetBattleChoiceButton(battleChoice, category) {&lt;br /&gt;
  var { defaultButtonContent, buttonContent } = battleChoice[category];&lt;br /&gt;
&lt;br /&gt;
  showElement(defaultButtonContent);&lt;br /&gt;
  hideElement(buttonContent);&lt;br /&gt;
&lt;br /&gt;
  if (category === &amp;quot;attacker&amp;quot;) {&lt;br /&gt;
    filterAttackTypeSelectionMonster(battleChoice.attackType);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isPC(character) {&lt;br /&gt;
  if (character.race === 0 || character.race === 1) {&lt;br /&gt;
    return false;&lt;br /&gt;
  }&lt;br /&gt;
  return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isBoss(character) {&lt;br /&gt;
  return character.race === 0 &amp;amp;&amp;amp; character.rank &amp;gt;= 5;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isStone(character) {&lt;br /&gt;
  return character.race === 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isMeleeAttacker(monster) {&lt;br /&gt;
  return monster.attack == 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isRangeAttacker(monster) {&lt;br /&gt;
  return monster.attack == 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isMagicAttacker(monster) {&lt;br /&gt;
  return monster.attack == 2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isMagicClass(character) {&lt;br /&gt;
  return character.race === &amp;quot;shaman&amp;quot; || character.class === &amp;quot;black_magic&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isDispell(character, skillId) {&lt;br /&gt;
  return character.class === &amp;quot;weaponary&amp;quot; &amp;amp;&amp;amp; skillId === 6;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isPolymorph(character) {&lt;br /&gt;
  return isChecked(character.isPolymorph);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isRiding(character) {&lt;br /&gt;
  return isChecked(character.isRiding);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isBow(weaponType) {&lt;br /&gt;
  return weaponType === 2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcAttackFactor(attacker, victim) {&lt;br /&gt;
  function calcCoeffK(dex, level) {&lt;br /&gt;
    return Math.min(90, Math.floor((2 * dex + level) / 3));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var K1 = calcCoeffK(attacker.polymorphDex, attacker.level);&lt;br /&gt;
  var K2 = calcCoeffK(victim.polymorphDex, attacker.level);&lt;br /&gt;
&lt;br /&gt;
  var AR = (K1 + 210) / 300;&lt;br /&gt;
  var ER = (((2 * K2 + 5) / (K2 + 95)) * 3) / 10;&lt;br /&gt;
&lt;br /&gt;
  return truncateNumber(AR - ER, 8);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcMainAttackValue(attacker) {&lt;br /&gt;
  var leadership = 0;&lt;br /&gt;
  var weaponGrowth = 0;&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker)) {&lt;br /&gt;
    weaponGrowth = attacker.weapon.growth;&lt;br /&gt;
    leadership = attacker.leadership;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return 2 * (attacker.level + weaponGrowth) + leadership;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcStatAttackValue(character) {&lt;br /&gt;
  let statAttackValue;&lt;br /&gt;
&lt;br /&gt;
  switch (character.race) {&lt;br /&gt;
    case &amp;quot;warrior&amp;quot;:&lt;br /&gt;
    case &amp;quot;sura&amp;quot;:&lt;br /&gt;
      statAttackValue = 2 * character.str;&lt;br /&gt;
      break;&lt;br /&gt;
    case &amp;quot;ninja&amp;quot;:&lt;br /&gt;
      statAttackValue = Math.floor((1 / 4) * (character.str + 7 * character.dex));&lt;br /&gt;
      break;&lt;br /&gt;
    case &amp;quot;shaman&amp;quot;:&lt;br /&gt;
      statAttackValue = Math.floor((1 / 3) * (5 * character.int + character.dex));&lt;br /&gt;
      break;&lt;br /&gt;
    case &amp;quot;lycan&amp;quot;:&lt;br /&gt;
      statAttackValue = character.vit + 2 * character.dex;&lt;br /&gt;
      break;&lt;br /&gt;
    default:&lt;br /&gt;
      statAttackValue = 2 * character.str;&lt;br /&gt;
      break;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (isPC(character) &amp;amp;&amp;amp; isRiding(character) &amp;amp;&amp;amp; !isPolymorph(character)) {&lt;br /&gt;
    return Math.max(2 * character.str, statAttackValue);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return statAttackValue;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcPvpCriticalAttackRange(minAttackValue, maxAttackValue, growth) {&lt;br /&gt;
  return Array.from(&lt;br /&gt;
    { length: maxAttackValue - minAttackValue + 1 },&lt;br /&gt;
    (_, index) =&amp;gt; (minAttackValue + growth + index) * 2&lt;br /&gt;
  );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcSecondaryAttackValue(attacker, isPlayerVsPlayer) {&lt;br /&gt;
  let attackValueOther = 0;&lt;br /&gt;
&lt;br /&gt;
  let minAttackValue = 0;&lt;br /&gt;
  let maxAttackValue = 0;&lt;br /&gt;
&lt;br /&gt;
  let minAttackValueSlash = 0;&lt;br /&gt;
  let maxAttackValueSlash = 0;&lt;br /&gt;
&lt;br /&gt;
  let type, isSerpent, growth;&lt;br /&gt;
&lt;br /&gt;
  let criticalAttackRange;&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker)) {&lt;br /&gt;
    ({ type, isSerpent, minAttackValue, maxAttackValue, growth } =&lt;br /&gt;
      attacker.weapon);&lt;br /&gt;
&lt;br /&gt;
    if (isSerpent) {&lt;br /&gt;
      minAttackValue = Math.max(0, attacker.minAttackValueRandom - growth);&lt;br /&gt;
      maxAttackValue = Math.max(&lt;br /&gt;
        minAttackValue,&lt;br /&gt;
        attacker.maxAttackValueRandom - growth&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    minAttackValueSlash = Math.min(&lt;br /&gt;
      attacker.minAttackValueSlash,&lt;br /&gt;
      attacker.maxAttackValueSlash&lt;br /&gt;
    );&lt;br /&gt;
    maxAttackValueSlash = Math.max(&lt;br /&gt;
      attacker.minAttackValueSlash,&lt;br /&gt;
      attacker.maxAttackValueSlash&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    attackValueOther += attacker.attackValue;&lt;br /&gt;
&lt;br /&gt;
    if (isBow(type) &amp;amp;&amp;amp; !isPolymorph(attacker)) {&lt;br /&gt;
      attackValueOther += 25;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isPlayerVsPlayer) {&lt;br /&gt;
      criticalAttackRange = calcPvpCriticalAttackRange(&lt;br /&gt;
        minAttackValue,&lt;br /&gt;
        maxAttackValue,&lt;br /&gt;
        growth&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    minAttackValue = attacker.minAttackValue;&lt;br /&gt;
    maxAttackValue = attacker.maxAttackValue;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  minAttackValue += attacker.minAttackValuePolymorph;&lt;br /&gt;
  maxAttackValue += attacker.maxAttackValuePolymorph;&lt;br /&gt;
&lt;br /&gt;
  attackValueOther += attacker.statAttackValue;&lt;br /&gt;
  attackValueOther += attacker.horseAttackValue;&lt;br /&gt;
&lt;br /&gt;
  const weaponInterval = maxAttackValue - minAttackValue + 1;&lt;br /&gt;
  const slashInterval = maxAttackValueSlash - minAttackValueSlash + 1;&lt;br /&gt;
&lt;br /&gt;
  const totalCardinal = weaponInterval * slashInterval * 1_000_000;&lt;br /&gt;
  const minInterval = Math.min(weaponInterval, slashInterval);&lt;br /&gt;
&lt;br /&gt;
  minAttackValue += minAttackValueSlash;&lt;br /&gt;
  maxAttackValue += maxAttackValueSlash;&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    minAttackValue: minAttackValue,&lt;br /&gt;
    maxAttackValue: maxAttackValue,&lt;br /&gt;
    attackValueOther: attackValueOther,&lt;br /&gt;
    totalCardinal: totalCardinal,&lt;br /&gt;
    weights: calcWeights(minAttackValue, maxAttackValue, minInterval),&lt;br /&gt;
    possibleDamageCount: maxAttackValue - minAttackValue + 1,&lt;br /&gt;
    criticalAttackRange: criticalAttackRange,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcMagicAttackValue(attacker, isPlayerVsPlayer) {&lt;br /&gt;
  let minMagicAttackValueSlash = 0;&lt;br /&gt;
  let maxMagicAttackValueSlash = 0;&lt;br /&gt;
&lt;br /&gt;
  let criticalAttackRange;&lt;br /&gt;
&lt;br /&gt;
  let {&lt;br /&gt;
    isSerpent,&lt;br /&gt;
    minMagicAttackValue,&lt;br /&gt;
    maxMagicAttackValue,&lt;br /&gt;
    minAttackValue,&lt;br /&gt;
    maxAttackValue,&lt;br /&gt;
    growth,&lt;br /&gt;
  } = attacker.weapon;&lt;br /&gt;
&lt;br /&gt;
  if (isSerpent) {&lt;br /&gt;
    minMagicAttackValue = Math.max(0, attacker.minMagicAttackValueRandom);&lt;br /&gt;
    maxMagicAttackValue = Math.max(&lt;br /&gt;
      minMagicAttackValue,&lt;br /&gt;
      attacker.maxMagicAttackValueRandom&lt;br /&gt;
    );&lt;br /&gt;
    minAttackValue = Math.max(0, attacker.minAttackValueRandom - growth);&lt;br /&gt;
    maxAttackValue = Math.max(&lt;br /&gt;
      minAttackValue,&lt;br /&gt;
      attacker.maxAttackValueRandom - growth&lt;br /&gt;
    );&lt;br /&gt;
  } else {&lt;br /&gt;
    minMagicAttackValue += growth;&lt;br /&gt;
    maxMagicAttackValue += growth;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (isPlayerVsPlayer) {&lt;br /&gt;
    criticalAttackRange = calcPvpCriticalAttackRange(&lt;br /&gt;
      minAttackValue,&lt;br /&gt;
      maxAttackValue,&lt;br /&gt;
      growth&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  minMagicAttackValueSlash = Math.min(&lt;br /&gt;
    attacker.minMagicAttackValueSlash,&lt;br /&gt;
    attacker.maxMagicAttackValueSlash&lt;br /&gt;
  );&lt;br /&gt;
  maxMagicAttackValueSlash = Math.max(&lt;br /&gt;
    attacker.minMagicAttackValueSlash,&lt;br /&gt;
    attacker.maxMagicAttackValueSlash&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  const weaponInterval = maxMagicAttackValue - minMagicAttackValue + 1;&lt;br /&gt;
  const slashInterval = maxMagicAttackValueSlash - minMagicAttackValueSlash + 1;&lt;br /&gt;
&lt;br /&gt;
  const totalCardinal = weaponInterval * slashInterval * 1_000_000;&lt;br /&gt;
  const minInterval = Math.min(weaponInterval, slashInterval);&lt;br /&gt;
&lt;br /&gt;
  minMagicAttackValue += minMagicAttackValueSlash;&lt;br /&gt;
  maxMagicAttackValue += maxMagicAttackValueSlash;&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    minMagicAttackValue: minMagicAttackValue,&lt;br /&gt;
    maxMagicAttackValue: maxMagicAttackValue,&lt;br /&gt;
    magicAttackValueAugmentation: getMagicAttackValueAugmentation(&lt;br /&gt;
      minMagicAttackValue,&lt;br /&gt;
      maxMagicAttackValue,&lt;br /&gt;
      attacker.magicAttackValue&lt;br /&gt;
    ),&lt;br /&gt;
    totalCardinal: totalCardinal,&lt;br /&gt;
    weights: calcWeights(minMagicAttackValue, maxMagicAttackValue, minInterval),&lt;br /&gt;
    possibleDamageCount: maxMagicAttackValue - minMagicAttackValue + 1,&lt;br /&gt;
    criticalAttackRange: criticalAttackRange,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getPolymorphPower(polymorphPoint, polymorphPowerTable) {&lt;br /&gt;
  return polymorphPowerTable[polymorphPoint];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSkillPower(skillPoint, skillPowerTable) {&lt;br /&gt;
  return skillPowerTable[skillPoint];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getMarriageBonusValue(character, marriageTable, itemName) {&lt;br /&gt;
  let index;&lt;br /&gt;
  const lovePoint = character.lovePoint;&lt;br /&gt;
&lt;br /&gt;
  if (lovePoint &amp;lt; 65) {&lt;br /&gt;
    index = 0;&lt;br /&gt;
  } else if (lovePoint &amp;lt; 80) {&lt;br /&gt;
    index = 1;&lt;br /&gt;
  } else if (lovePoint &amp;lt; 100) {&lt;br /&gt;
    index = 2;&lt;br /&gt;
  } else {&lt;br /&gt;
    index = 3;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return marriageTable[itemName][index];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcDamageWithPrimaryBonuses(damage, bonusValues) {&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.attackValueCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  damage += bonusValues.attackValueMarriage;&lt;br /&gt;
&lt;br /&gt;
  damage = Math.floor(&lt;br /&gt;
    (damage * bonusValues.monsterResistanceMarriageCoeff) / 100&lt;br /&gt;
  );&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.monsterResistanceCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  damage += Math.floor((damage * bonusValues.typeBonusCoeff) / 100);&lt;br /&gt;
  damage +=&lt;br /&gt;
    Math.floor((damage * bonusValues.raceBonusCoeff) / 100) -&lt;br /&gt;
    Math.floor((damage * bonusValues.raceResistanceCoeff) / 100);&lt;br /&gt;
  damage += Math.floor((damage * bonusValues.stoneBonusCoeff) / 100);&lt;br /&gt;
  damage += Math.floor((damage * bonusValues.monsterBonusCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  const elementBonusCoeff = bonusValues.elementBonusCoeff;&lt;br /&gt;
&lt;br /&gt;
  damage +=&lt;br /&gt;
    Math.trunc((damage * elementBonusCoeff[0]) / 10000) +&lt;br /&gt;
    Math.trunc((damage * elementBonusCoeff[1]) / 10000) +&lt;br /&gt;
    Math.trunc((damage * elementBonusCoeff[2]) / 10000) +&lt;br /&gt;
    Math.trunc((damage * elementBonusCoeff[3]) / 10000) +&lt;br /&gt;
    Math.trunc((damage * elementBonusCoeff[4]) / 10000) +&lt;br /&gt;
    Math.trunc((damage * elementBonusCoeff[5]) / 10000);&lt;br /&gt;
&lt;br /&gt;
  damage = Math.floor(damage * bonusValues.damageMultiplier);&lt;br /&gt;
&lt;br /&gt;
  return Math.max(0, damage);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcFinalDamage(&lt;br /&gt;
  finalDamage,&lt;br /&gt;
  damageWithPrimaryBonuses,&lt;br /&gt;
  bonusValues,&lt;br /&gt;
  criticalAttackRange,&lt;br /&gt;
  damageByType&lt;br /&gt;
) {&lt;br /&gt;
  for (let criticalIndex = 0; criticalIndex &amp;lt; 2; criticalIndex++) {&lt;br /&gt;
    if (bonusValues.skipCriticalStep[criticalIndex]) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
    let beforeCriticalDamage = finalDamage;&lt;br /&gt;
    let damageValues = criticalIndex&lt;br /&gt;
      ? criticalAttackRange || [finalDamage]&lt;br /&gt;
      : [0];&lt;br /&gt;
&lt;br /&gt;
    for (let index = 0, len = damageValues.length; index &amp;lt; len; index++) {&lt;br /&gt;
      let afterCriticalDamage = beforeCriticalDamage + damageValues[index];&lt;br /&gt;
&lt;br /&gt;
      for (let piercingIndex = 0; piercingIndex &amp;lt; 2; piercingIndex++) {&lt;br /&gt;
        if (bonusValues.skipPiercingStep[piercingIndex]) {&lt;br /&gt;
          continue;&lt;br /&gt;
        }&lt;br /&gt;
        let damage = afterCriticalDamage;&lt;br /&gt;
&lt;br /&gt;
        if (piercingIndex) {&lt;br /&gt;
          damage += Math.min(&lt;br /&gt;
            bonusValues.defenseBoost,&lt;br /&gt;
            damageWithPrimaryBonuses&lt;br /&gt;
          );&lt;br /&gt;
          damage += Math.floor(&lt;br /&gt;
            (damageWithPrimaryBonuses * bonusValues.extraPiercingHitCoeff) /&lt;br /&gt;
              1000&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        damage = Math.floor((damage * bonusValues.averageDamageCoeff) / 100);&lt;br /&gt;
        damage = Math.floor(&lt;br /&gt;
          (damage * bonusValues.averageDamageResistanceCoeff) / 100&lt;br /&gt;
        );&lt;br /&gt;
        damage = Math.floor((damage * bonusValues.skillDamageCoeff) / 100);&lt;br /&gt;
        damage = Math.floor(&lt;br /&gt;
          (damage * bonusValues.skillDamageResistanceCoeff) / 100&lt;br /&gt;
        );&lt;br /&gt;
        damage = Math.floor((damage * bonusValues.rankBonusCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
        if (bonusValues.useDarkProtection) {&lt;br /&gt;
          const { darkProtectionPoint, darkProtectionSp } = bonusValues;&lt;br /&gt;
&lt;br /&gt;
          const damageReduction = Math.floor(damage / 3);&lt;br /&gt;
          const spAbsorption = Math.floor(&lt;br /&gt;
            (damageReduction * darkProtectionPoint) / 100&lt;br /&gt;
          );&lt;br /&gt;
&lt;br /&gt;
          if (spAbsorption &amp;lt;= darkProtectionSp) {&lt;br /&gt;
            damage -= damageReduction;&lt;br /&gt;
          } else {&lt;br /&gt;
            damage -= Math.floor(&lt;br /&gt;
              (darkProtectionSp * 100) / darkProtectionPoint&lt;br /&gt;
            );&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        damage -= Math.floor(&lt;br /&gt;
          (damage * bonusValues.resistance90PercentHp) / 100&lt;br /&gt;
        );&lt;br /&gt;
        damage = Math.max(0, damage + bonusValues.defensePercent);&lt;br /&gt;
        damage += Math.min(&lt;br /&gt;
          300,&lt;br /&gt;
          Math.floor((damage * bonusValues.damageBonusCoeff) / 100)&lt;br /&gt;
        );&lt;br /&gt;
        damage = Math.floor((damage * bonusValues.empireMalusCoeff) / 10);&lt;br /&gt;
        damage = Math.floor((damage * bonusValues.sungMaStrBonusCoeff) / 10000);&lt;br /&gt;
        damage -= Math.floor(damage * bonusValues.sungmaStrMalusCoeff);&lt;br /&gt;
        damage = Math.floor(&lt;br /&gt;
          (damage * bonusValues.whiteDragonElixirCoeff) / 100&lt;br /&gt;
        );&lt;br /&gt;
        damage = Math.floor(&lt;br /&gt;
          (damage * bonusValues.steelDragonElixirCoeff) / 100&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        damageByType[criticalIndex + 2 * piercingIndex].push(damage);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveFinalDamage(&lt;br /&gt;
  damage,&lt;br /&gt;
  damageWithPrimaryBonuses,&lt;br /&gt;
  bonusValues,&lt;br /&gt;
  criticalAttackRange,&lt;br /&gt;
  damageByType&lt;br /&gt;
) {&lt;br /&gt;
  damage = Math.floor(damage * bonusValues.magicResistanceCoeff);&lt;br /&gt;
  damage = Math.trunc((damage * bonusValues.weaponDefenseCoeff) / 100);&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.tigerStrengthCoeff) / 100);&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.berserkBonusCoeff) / 100);&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.fearBonusCoeff) / 100);&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.blessingBonusCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  calcFinalDamage(&lt;br /&gt;
    damage,&lt;br /&gt;
    damageWithPrimaryBonuses,&lt;br /&gt;
    bonusValues,&lt;br /&gt;
    criticalAttackRange,&lt;br /&gt;
    damageByType&lt;br /&gt;
  );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveFinalSkillDamage(&lt;br /&gt;
  damage,&lt;br /&gt;
  bonusValues,&lt;br /&gt;
  criticalAttackRange,&lt;br /&gt;
  damageByType&lt;br /&gt;
) {&lt;br /&gt;
  damage = Math.floor(damage * bonusValues.magicResistanceCoeff);&lt;br /&gt;
  damage = Math.trunc((damage * bonusValues.weaponDefenseCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  damage -= bonusValues.defense;&lt;br /&gt;
&lt;br /&gt;
  const damageValues =&lt;br /&gt;
    damage &amp;lt;= 2 &amp;amp;&amp;amp; bonusValues.isPhysicalSkill ? [1, 2, 3, 4, 5] : [damage];&lt;br /&gt;
&lt;br /&gt;
  for (const minDamage of damageValues) {&lt;br /&gt;
    damage = floorMultiplication(minDamage, bonusValues.skillWardCoeff);&lt;br /&gt;
    damage = floorMultiplication(damage, bonusValues.skillBonusCoeff);&lt;br /&gt;
&lt;br /&gt;
    const tempDamage = Math.floor(&lt;br /&gt;
      (damage * bonusValues.skillBonusByBonusCoeff) / 100&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    damage = Math.floor(&lt;br /&gt;
      (tempDamage * bonusValues.magicAttackValueCoeff) / 100 + 0.5&lt;br /&gt;
    );&lt;br /&gt;
    damage = Math.floor((damage * bonusValues.tigerStrengthCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
    calcFinalDamage(&lt;br /&gt;
      damage,&lt;br /&gt;
      tempDamage,&lt;br /&gt;
      bonusValues,&lt;br /&gt;
      criticalAttackRange,&lt;br /&gt;
      damageByType&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function computePolymorphPoint(attacker, victim, polymorphPowerTable) {&lt;br /&gt;
  attacker.polymorphDex = attacker.dex;&lt;br /&gt;
  victim.polymorphDex = victim.dex;&lt;br /&gt;
&lt;br /&gt;
  attacker.minAttackValuePolymorph = 0;&lt;br /&gt;
  attacker.maxAttackValuePolymorph = 0;&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker) &amp;amp;&amp;amp; isPolymorph(attacker)) {&lt;br /&gt;
    var polymorphPowerPct =&lt;br /&gt;
      getPolymorphPower(attacker.polymorphPoint, polymorphPowerTable) / 100;&lt;br /&gt;
    var polymorphMonster = createMonster(&lt;br /&gt;
      attacker.polymorphMonster,&lt;br /&gt;
      null,&lt;br /&gt;
      null,&lt;br /&gt;
      true&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    var polymorphStr = floorMultiplication(&lt;br /&gt;
      polymorphPowerPct,&lt;br /&gt;
      polymorphMonster.str&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    attacker.polymorphDex += floorMultiplication(&lt;br /&gt;
      polymorphPowerPct,&lt;br /&gt;
      polymorphMonster.dex&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    attacker.minAttackValuePolymorph = floorMultiplication(&lt;br /&gt;
      polymorphPowerPct,&lt;br /&gt;
      polymorphMonster.minAttackValue&lt;br /&gt;
    );&lt;br /&gt;
    attacker.maxAttackValuePolymorph = floorMultiplication(&lt;br /&gt;
      polymorphPowerPct,&lt;br /&gt;
      polymorphMonster.maxAttackValue&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    if (!attacker.weapon) {&lt;br /&gt;
      attacker.maxAttackValuePolymorph += 1;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    attacker.attackValue = 0;&lt;br /&gt;
&lt;br /&gt;
    if (isMagicClass(attacker)) {&lt;br /&gt;
      attacker.statAttackValue = 2 * (polymorphStr + attacker.int);&lt;br /&gt;
    } else {&lt;br /&gt;
      attacker.statAttackValue = 2 * (polymorphStr + attacker.str);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function computeHorse(attacker) {&lt;br /&gt;
  attacker.horseAttackValue = 0;&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker) &amp;amp;&amp;amp; isRiding(attacker) &amp;amp;&amp;amp; !isPolymorph(attacker)) {&lt;br /&gt;
    var horseConstant = 30;&lt;br /&gt;
&lt;br /&gt;
    if (attacker.class === &amp;quot;weaponary&amp;quot;) {&lt;br /&gt;
      horseConstant = 60;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    attacker.horseAttackValue = floorMultiplication(&lt;br /&gt;
      2 * attacker.level + attacker.statAttackValue,&lt;br /&gt;
      attacker.horsePoint / horseConstant&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getRankBonus(attacker) {&lt;br /&gt;
  if (!isChecked(attacker.lowRank)) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  switch (attacker.rank) {&lt;br /&gt;
    case &amp;quot;aggressive&amp;quot;:&lt;br /&gt;
      return 1;&lt;br /&gt;
    case &amp;quot;fraudulent&amp;quot;:&lt;br /&gt;
      return 2;&lt;br /&gt;
    case &amp;quot;malicious&amp;quot;:&lt;br /&gt;
      return 3;&lt;br /&gt;
    case &amp;quot;cruel&amp;quot;:&lt;br /&gt;
      return 5;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcElementCoeffPvP(elementBonus, mapping, attacker, victim) {&lt;br /&gt;
  var minElementMalus = 0;&lt;br /&gt;
  var maxDifference = 0;&lt;br /&gt;
  var savedElementDifferences = [];&lt;br /&gt;
  var elementBonusIndex = 0;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; elementBonus.length; index++) {&lt;br /&gt;
    if (!attacker[mapping.elementBonus[index]]) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var elementDifference =&lt;br /&gt;
      attacker[mapping.elementBonus[index]] -&lt;br /&gt;
      victim[mapping.elementResistance[index]];&lt;br /&gt;
&lt;br /&gt;
    if (elementDifference &amp;gt;= 0) {&lt;br /&gt;
      elementBonus[elementBonusIndex] = 10 * elementDifference;&lt;br /&gt;
      minElementMalus -= elementDifference;&lt;br /&gt;
      maxDifference = Math.max(maxDifference, elementDifference);&lt;br /&gt;
      elementBonusIndex++;&lt;br /&gt;
    } else {&lt;br /&gt;
      savedElementDifferences.push(elementDifference);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (!savedElementDifferences.length) {&lt;br /&gt;
    return;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  minElementMalus += maxDifference;&lt;br /&gt;
  savedElementDifferences.sort(compareNumbers);&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; savedElementDifferences.length; index++) {&lt;br /&gt;
    var elementDifference = savedElementDifferences[index];&lt;br /&gt;
&lt;br /&gt;
    elementBonus[elementBonusIndex + index] =&lt;br /&gt;
      10 * Math.max(minElementMalus, elementDifference);&lt;br /&gt;
&lt;br /&gt;
    minElementMalus = Math.min(&lt;br /&gt;
      0,&lt;br /&gt;
      Math.max(minElementMalus, minElementMalus - elementDifference)&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcCriticalHitChance(criticalHitPercentage) {&lt;br /&gt;
  if (criticalHitPercentage &amp;lt;= 9) {&lt;br /&gt;
    return Math.floor((criticalHitPercentage + 5) / 5);&lt;br /&gt;
  }&lt;br /&gt;
  return Math.floor((criticalHitPercentage + 5) / 6);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcCriticalSkillChance(criticalHitPercentage) {&lt;br /&gt;
  if (criticalHitPercentage === 0) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  } else if (criticalHitPercentage &amp;lt;= 9) {&lt;br /&gt;
    return Math.floor((criticalHitPercentage + 7) / 3);&lt;br /&gt;
  }&lt;br /&gt;
  return Math.floor((criticalHitPercentage + 5) / 3);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcPiercingSkillChance(piercingHitPercentage) {&lt;br /&gt;
  if (piercingHitPercentage &amp;lt;= 9) {&lt;br /&gt;
    return Math.floor(piercingHitPercentage / 2);&lt;br /&gt;
  }&lt;br /&gt;
  return 5 + Math.floor((piercingHitPercentage - 10) / 4);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function magicResistanceToCoeff(magicResistance) {&lt;br /&gt;
  if (magicResistance) {&lt;br /&gt;
    return 2000 / (6 * magicResistance + 1000) - 1;&lt;br /&gt;
  }&lt;br /&gt;
  return 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createBattleValues(attacker, victim, battle, skillType) {&lt;br /&gt;
  var {&lt;br /&gt;
    mapping,&lt;br /&gt;
    constants: { polymorphPowerTable, skillPowerTable, marriageTable },&lt;br /&gt;
  } = battle;&lt;br /&gt;
  var calcAttackValues;&lt;br /&gt;
&lt;br /&gt;
  var missPercentage = 0;&lt;br /&gt;
  var attackValueMeleeMagic = 0;&lt;br /&gt;
  var attackValueMarriage = 0;&lt;br /&gt;
  var monsterResistanceMarriage = 0;&lt;br /&gt;
  var monsterResistance = 0;&lt;br /&gt;
  var typeBonus = 0;&lt;br /&gt;
  var raceBonus = 0;&lt;br /&gt;
  var raceResistance = 0;&lt;br /&gt;
  var stoneBonus = 0;&lt;br /&gt;
  var monsterBonus = 0;&lt;br /&gt;
  var elementBonus = [0, 0, 0, 0, 0, 0]; // fire, ice, lightning, earth, darkness, wind, order doesn't matter&lt;br /&gt;
  var defenseMarriage = 0;&lt;br /&gt;
  var damageMultiplier = 1;&lt;br /&gt;
  var useDamage = 1;&lt;br /&gt;
  var defense = victim.defense;&lt;br /&gt;
  var defenseBoost = defense;&lt;br /&gt;
  var magicResistance = 0;&lt;br /&gt;
  var magicPenetration = 0;&lt;br /&gt;
  var weaponDefense = 0;&lt;br /&gt;
  var tigerStrength = 0;&lt;br /&gt;
  var berserkBonus = 0;&lt;br /&gt;
  var blessingBonus = 0;&lt;br /&gt;
  var fearBonus = 0;&lt;br /&gt;
  var magicAttackValueMeleeMagic = 0;&lt;br /&gt;
  var criticalHitPercentage = attacker.criticalHit;&lt;br /&gt;
  var isPlayerVsPlayer = false;&lt;br /&gt;
  var piercingHitPercentage = attacker.piercingHit;&lt;br /&gt;
  var extraPiercingHitPercentage = Math.max(0, piercingHitPercentage - 100);&lt;br /&gt;
  var averageDamage = 0;&lt;br /&gt;
  var averageDamageResistance = 0;&lt;br /&gt;
  var skillDamage = 0;&lt;br /&gt;
  var skillDamageResistance = 0;&lt;br /&gt;
  var rankBonus = 0;&lt;br /&gt;
  var useDarkProtection = false;&lt;br /&gt;
  var darkProtectionPoint = 0;&lt;br /&gt;
  var resistance90PercentHp = 0;&lt;br /&gt;
  var defensePercent = 0;&lt;br /&gt;
  var damageBonus = 0;&lt;br /&gt;
  var empireMalus = 0;&lt;br /&gt;
  var sungMaStrBonus = 0;&lt;br /&gt;
  var sungmaStrMalus = 0;&lt;br /&gt;
  var whiteDragonElixir = 0;&lt;br /&gt;
  var steelDragonElixir = 0;&lt;br /&gt;
&lt;br /&gt;
  attacker.statAttackValue = calcStatAttackValue(attacker);&lt;br /&gt;
&lt;br /&gt;
  computePolymorphPoint(attacker, victim, polymorphPowerTable);&lt;br /&gt;
  computeHorse(attacker);&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker)) {&lt;br /&gt;
    if (weaponData.hasOwnProperty(attacker.weapon)) {&lt;br /&gt;
      attacker.weapon = createWeapon(attacker.weapon);&lt;br /&gt;
    } else {&lt;br /&gt;
      attacker.weapon = createWeapon(0);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    attacker.weapon.getValues(attacker.weaponUpgrade);&lt;br /&gt;
&lt;br /&gt;
    attackValueMeleeMagic =&lt;br /&gt;
      attacker.attackValuePercent + Math.min(100, attacker.attackMeleeMagic);&lt;br /&gt;
&lt;br /&gt;
    var weaponType = attacker.weapon.type;&lt;br /&gt;
&lt;br /&gt;
    if (skillType &amp;amp;&amp;amp; attacker.class === &amp;quot;archery&amp;quot;) {&lt;br /&gt;
      if (weaponType !== 2) {&lt;br /&gt;
        useDamage = 0;&lt;br /&gt;
        weaponType = 2;&lt;br /&gt;
      }&lt;br /&gt;
      defense = 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var weaponDefenseName = mapping.defenseWeapon[weaponType];&lt;br /&gt;
    var weaponDefenseBreakName = mapping.breakWeapon[weaponType];&lt;br /&gt;
&lt;br /&gt;
    if (victim.hasOwnProperty(weaponDefenseName)) {&lt;br /&gt;
      weaponDefense = victim[weaponDefenseName];&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isChecked(attacker.whiteDragonElixir)) {&lt;br /&gt;
      whiteDragonElixir = 10;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    magicPenetration = attacker.magicPenetration;&lt;br /&gt;
&lt;br /&gt;
    if (isPC(victim)) {&lt;br /&gt;
      isPlayerVsPlayer = true;&lt;br /&gt;
&lt;br /&gt;
      if (!skillType) {&lt;br /&gt;
        if (weaponType === 2 &amp;amp;&amp;amp; !isPolymorph(attacker)) {&lt;br /&gt;
          missPercentage = victim.arrowBlock;&lt;br /&gt;
        } else {&lt;br /&gt;
          missPercentage = victim.meleeBlock;&lt;br /&gt;
        }&lt;br /&gt;
        missPercentage +=&lt;br /&gt;
          victim.meleeArrowBlock -&lt;br /&gt;
          (missPercentage * victim.meleeArrowBlock) / 100;&lt;br /&gt;
&lt;br /&gt;
        criticalHitPercentage = calcCriticalHitChance(criticalHitPercentage);&lt;br /&gt;
        berserkBonus = calcBerserkBonus(skillPowerTable, victim);&lt;br /&gt;
        blessingBonus = calcBlessingBonus(skillPowerTable, victim);&lt;br /&gt;
        fearBonus = calcFearBonus(skillPowerTable, victim);&lt;br /&gt;
        averageDamageResistance = victim.averageDamageResistance;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      typeBonus = Math.max(1, attacker.humanBonus - victim.humanResistance);&lt;br /&gt;
      raceBonus = attacker[mapping.raceBonus[victim.race]];&lt;br /&gt;
      raceResistance = victim[mapping.raceResistance[attacker.race]];&lt;br /&gt;
&lt;br /&gt;
      calcElementCoeffPvP(elementBonus, mapping, attacker, victim);&lt;br /&gt;
&lt;br /&gt;
      if (weaponType !== 2 &amp;amp;&amp;amp; attacker.hasOwnProperty(weaponDefenseBreakName)) {&lt;br /&gt;
        weaponDefense -= attacker[weaponDefenseBreakName];&lt;br /&gt;
      }&lt;br /&gt;
    } else {&lt;br /&gt;
      if (isChecked(attacker.isMarried)) {&lt;br /&gt;
        if (isChecked(attacker.loveNecklace)) {&lt;br /&gt;
          attackValueMarriage = getMarriageBonusValue(&lt;br /&gt;
            attacker,&lt;br /&gt;
            marriageTable,&lt;br /&gt;
            &amp;quot;loveNecklace&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isChecked(attacker.loveEarrings)) {&lt;br /&gt;
          criticalHitPercentage += getMarriageBonusValue(&lt;br /&gt;
            attacker,&lt;br /&gt;
            marriageTable,&lt;br /&gt;
            &amp;quot;loveEarrings&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isChecked(attacker.harmonyEarrings)) {&lt;br /&gt;
          piercingHitPercentage += getMarriageBonusValue(&lt;br /&gt;
            attacker,&lt;br /&gt;
            marriageTable,&lt;br /&gt;
            &amp;quot;harmonyEarrings&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (isChecked(attacker.tigerStrength)) {&lt;br /&gt;
        tigerStrength = 40;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      for (var index = 0; index &amp;lt; elementBonus.length; index++) {&lt;br /&gt;
        var elementBonusName = mapping.elementBonus[index];&lt;br /&gt;
        var elementResistanceName = mapping.elementResistance[index];&lt;br /&gt;
&lt;br /&gt;
        if (attacker[elementBonusName] &amp;amp;&amp;amp; victim[elementBonusName]) {&lt;br /&gt;
          elementBonus[index] =&lt;br /&gt;
            50 * (attacker[elementBonusName] - victim[elementResistanceName]);&lt;br /&gt;
        } else {&lt;br /&gt;
          elementBonus[index] = 5 * attacker[elementBonusName];&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      var victimType = victim.type;&lt;br /&gt;
&lt;br /&gt;
      if (victimType !== -1) {&lt;br /&gt;
        typeBonus = attacker[mapping.typeFlag[victimType]];&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      monsterBonus = attacker.monsterBonus;&lt;br /&gt;
&lt;br /&gt;
      if (isStone(victim)) {&lt;br /&gt;
        stoneBonus = attacker.stoneBonus;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (isBoss(victim)) {&lt;br /&gt;
        if (skillType) {&lt;br /&gt;
          skillDamage += attacker.skillBossDamage;&lt;br /&gt;
        } else {&lt;br /&gt;
          averageDamage += attacker.bossDamage;&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (isChecked(attacker.onYohara)) {&lt;br /&gt;
        var sungmaStrDifference = attacker.sungmaStr - attacker.sungmaStrMalus;&lt;br /&gt;
&lt;br /&gt;
        if (sungmaStrDifference &amp;gt;= 0) {&lt;br /&gt;
          sungMaStrBonus = sungmaStrDifference;&lt;br /&gt;
        } else {&lt;br /&gt;
          sungmaStrMalus = 0.5;&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (skillType) {&lt;br /&gt;
      skillDamage += attacker.skillDamage;&lt;br /&gt;
    } else {&lt;br /&gt;
      averageDamage += attacker.averageDamage;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    rankBonus = getRankBonus(attacker);&lt;br /&gt;
    damageBonus = attacker.damageBonus;&lt;br /&gt;
&lt;br /&gt;
    if (isChecked(attacker.empireMalus)) {&lt;br /&gt;
      empireMalus = 1;&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    if (isPC(victim)) {&lt;br /&gt;
      if (isChecked(victim.isMarried)) {&lt;br /&gt;
        if (isChecked(victim.harmonyBracelet)) {&lt;br /&gt;
          monsterResistanceMarriage = getMarriageBonusValue(&lt;br /&gt;
            victim,&lt;br /&gt;
            marriageTable,&lt;br /&gt;
            &amp;quot;harmonyBracelet&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isChecked(victim.harmonyNecklace) &amp;amp;&amp;amp; !skillType) {&lt;br /&gt;
          defenseMarriage = getMarriageBonusValue(&lt;br /&gt;
            victim,&lt;br /&gt;
            marriageTable,&lt;br /&gt;
            &amp;quot;harmonyNecklace&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      monsterResistance = victim.monsterResistance;&lt;br /&gt;
&lt;br /&gt;
      for (var index = 0; index &amp;lt; elementBonus.length; index++) {&lt;br /&gt;
        var elementBonusName = mapping.elementBonus[index];&lt;br /&gt;
        var elementResistanceName = mapping.elementResistance[index];&lt;br /&gt;
&lt;br /&gt;
        if (attacker[elementBonusName]) {&lt;br /&gt;
          elementBonus[index] =&lt;br /&gt;
            80 * (attacker[elementBonusName] - victim[elementResistanceName]);&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (!skillType) {&lt;br /&gt;
        if (isMeleeAttacker(attacker)) {&lt;br /&gt;
          missPercentage = victim.meleeBlock;&lt;br /&gt;
          averageDamageResistance = victim.averageDamageResistance;&lt;br /&gt;
          berserkBonus = calcBerserkBonus(skillPowerTable, victim);&lt;br /&gt;
          blessingBonus = calcBlessingBonus(skillPowerTable, victim);&lt;br /&gt;
          fearBonus = calcFearBonus(skillPowerTable, victim);&lt;br /&gt;
        } else if (isRangeAttacker(attacker)) {&lt;br /&gt;
          missPercentage = victim.arrowBlock;&lt;br /&gt;
          weaponDefense = victim.arrowDefense;&lt;br /&gt;
          averageDamageResistance = victim.averageDamageResistance;&lt;br /&gt;
          berserkBonus = calcBerserkBonus(skillPowerTable, victim);&lt;br /&gt;
          blessingBonus = calcBlessingBonus(skillPowerTable, victim);&lt;br /&gt;
          fearBonus = calcFearBonus(skillPowerTable, victim);&lt;br /&gt;
        } else if (isMagicAttacker(attacker)) {&lt;br /&gt;
          missPercentage = victim.arrowBlock;&lt;br /&gt;
          skillDamageResistance = victim.skillDamageResistance;&lt;br /&gt;
          magicResistance = victim.magicResistance;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        missPercentage +=&lt;br /&gt;
          victim.meleeArrowBlock -&lt;br /&gt;
          (missPercentage * victim.meleeArrowBlock) / 100;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    typeBonus = 1;&lt;br /&gt;
    damageMultiplier = attacker.damageMultiplier;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillType) {&lt;br /&gt;
    criticalHitPercentage = calcCriticalSkillChance(criticalHitPercentage);&lt;br /&gt;
    piercingHitPercentage = calcPiercingSkillChance(piercingHitPercentage);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (isPC(victim)) {&lt;br /&gt;
    if (!skillType &amp;amp;&amp;amp; isChecked(victim.biologist70)) {&lt;br /&gt;
      defenseBoost = Math.floor((defenseBoost * 110) / 100);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    criticalHitPercentage = Math.max(&lt;br /&gt;
      0,&lt;br /&gt;
      criticalHitPercentage - victim.criticalHitResistance&lt;br /&gt;
    );&lt;br /&gt;
    piercingHitPercentage = Math.max(&lt;br /&gt;
      0,&lt;br /&gt;
      piercingHitPercentage - victim.piercingHitResistance&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    if (skillType) {&lt;br /&gt;
      skillDamageResistance = victim.skillDamageResistance;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      victim.useDarkProtection &amp;amp;&amp;amp;&lt;br /&gt;
      victim.class === &amp;quot;black_magic&amp;quot; &amp;amp;&amp;amp;&lt;br /&gt;
      victim.skillDarkProtection&lt;br /&gt;
    ) {&lt;br /&gt;
      useDarkProtection = true;&lt;br /&gt;
      darkProtectionPoint = calcDarkProtectionPoint(skillPowerTable, victim);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    resistance90PercentHp = victim.resistance90PercentHp || 0;&lt;br /&gt;
&lt;br /&gt;
    if (isMagicClass(victim)) {&lt;br /&gt;
      defensePercent = (-2 * victim.magicDefense * victim.defensePercent) / 100;&lt;br /&gt;
    } else {&lt;br /&gt;
      defensePercent = (-2 * defenseBoost * victim.defensePercent) / 100;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isChecked(victim.steelDragonElixir)) {&lt;br /&gt;
      steelDragonElixir = 10;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillType === &amp;quot;magic&amp;quot;) {&lt;br /&gt;
    attackValueMeleeMagic = 0;&lt;br /&gt;
    magicAttackValueMeleeMagic =&lt;br /&gt;
      attacker.attackMagic + Math.min(100, attacker.attackMeleeMagic);&lt;br /&gt;
    attackValueMarriage = 0;&lt;br /&gt;
    defense = 0;&lt;br /&gt;
    magicResistance = victim.magicResistance;&lt;br /&gt;
&lt;br /&gt;
    if (magicResistance &amp;gt; 0 &amp;amp;&amp;amp; magicPenetration) {&lt;br /&gt;
      magicResistance = Math.floor(&lt;br /&gt;
        magicResistance * (1 - magicPenetration / 120) + 0.5&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    weaponDefense = 0;&lt;br /&gt;
    calcAttackValues = calcMagicAttackValue;&lt;br /&gt;
&lt;br /&gt;
    if (isDispell(attacker, 6)) {&lt;br /&gt;
      typeBonus = 0;&lt;br /&gt;
      raceBonus = 0;&lt;br /&gt;
      raceResistance = 0;&lt;br /&gt;
      stoneBonus = 0;&lt;br /&gt;
      monsterBonus = 0;&lt;br /&gt;
      for (var index = 0; index &amp;lt; elementBonus.length; index++) {&lt;br /&gt;
        elementBonus[index] = 0;&lt;br /&gt;
      }&lt;br /&gt;
      magicResistance = 0;&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    calcAttackValues = calcSecondaryAttackValue;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  missPercentage = Math.min(100, missPercentage);&lt;br /&gt;
  criticalHitPercentage = Math.min(criticalHitPercentage, 100);&lt;br /&gt;
  piercingHitPercentage = Math.min(piercingHitPercentage, 100);&lt;br /&gt;
&lt;br /&gt;
  const bonusValues = {&lt;br /&gt;
    missPercentage: missPercentage,&lt;br /&gt;
    skipCriticalStep: [&lt;br /&gt;
      !Boolean(100 - criticalHitPercentage),&lt;br /&gt;
      !Boolean(criticalHitPercentage),&lt;br /&gt;
    ],&lt;br /&gt;
    skipPiercingStep: [&lt;br /&gt;
      !Boolean(100 - piercingHitPercentage),&lt;br /&gt;
      !Boolean(piercingHitPercentage),&lt;br /&gt;
    ],&lt;br /&gt;
    isPhysicalSkill: skillType === &amp;quot;physical&amp;quot; &amp;amp;&amp;amp; attacker.class !== &amp;quot;archery&amp;quot;,&lt;br /&gt;
    weaponBonusCoeff: 1,&lt;br /&gt;
    attackValueCoeff: 100 + attackValueMeleeMagic,&lt;br /&gt;
    attackValueMarriage: attackValueMarriage,&lt;br /&gt;
    monsterResistanceMarriageCoeff: 100 - monsterResistanceMarriage,&lt;br /&gt;
    monsterResistanceCoeff: 100 - monsterResistance,&lt;br /&gt;
    typeBonusCoeff: typeBonus,&lt;br /&gt;
    raceBonusCoeff: raceBonus,&lt;br /&gt;
    raceResistanceCoeff: raceResistance,&lt;br /&gt;
    stoneBonusCoeff: stoneBonus,&lt;br /&gt;
    monsterBonusCoeff: monsterBonus,&lt;br /&gt;
    elementBonusCoeff: elementBonus,&lt;br /&gt;
    damageMultiplier: damageMultiplier,&lt;br /&gt;
    useDamage: useDamage,&lt;br /&gt;
    defense: defense,&lt;br /&gt;
    defenseBoost: defenseBoost,&lt;br /&gt;
    defenseMarriage: defenseMarriage,&lt;br /&gt;
    tigerStrengthCoeff: 100 + tigerStrength,&lt;br /&gt;
    magicResistanceCoeff: magicResistanceToCoeff(magicResistance),&lt;br /&gt;
    weaponDefenseCoeff: 100 - weaponDefense,&lt;br /&gt;
    berserkBonusCoeff: 100 + berserkBonus,&lt;br /&gt;
    blessingBonusCoeff: 100 - blessingBonus,&lt;br /&gt;
    fearBonusCoeff: 100 - fearBonus,&lt;br /&gt;
    magicAttackValueCoeff: 100 + magicAttackValueMeleeMagic,&lt;br /&gt;
    extraPiercingHitCoeff: 5 * extraPiercingHitPercentage,&lt;br /&gt;
    averageDamageCoeff: 100 + averageDamage,&lt;br /&gt;
    averageDamageResistanceCoeff: 100 - Math.min(99, averageDamageResistance),&lt;br /&gt;
    skillDamageCoeff: 100 + skillDamage,&lt;br /&gt;
    skillDamageResistanceCoeff: 100 - Math.min(99, skillDamageResistance),&lt;br /&gt;
    useDarkProtection: useDarkProtection,&lt;br /&gt;
    darkProtectionPoint: darkProtectionPoint,&lt;br /&gt;
    darkProtectionSp: victim.darkProtectionSp,&lt;br /&gt;
    rankBonusCoeff: 100 + rankBonus,&lt;br /&gt;
    resistance90PercentHp: resistance90PercentHp,&lt;br /&gt;
    defensePercent: Math.floor(defensePercent),&lt;br /&gt;
    damageBonusCoeff: Math.min(20, damageBonus),&lt;br /&gt;
    empireMalusCoeff: 10 - empireMalus,&lt;br /&gt;
    sungMaStrBonusCoeff: 10000 + sungMaStrBonus,&lt;br /&gt;
    sungmaStrMalusCoeff: sungmaStrMalus,&lt;br /&gt;
    whiteDragonElixirCoeff: 100 + whiteDragonElixir,&lt;br /&gt;
    steelDragonElixirCoeff: 100 - steelDragonElixir,&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  const damageTypeWeights = [&lt;br /&gt;
    (100 - criticalHitPercentage) *&lt;br /&gt;
      (100 - piercingHitPercentage) *&lt;br /&gt;
      (100 - missPercentage),&lt;br /&gt;
    criticalHitPercentage *&lt;br /&gt;
      (100 - piercingHitPercentage) *&lt;br /&gt;
      (100 - missPercentage),&lt;br /&gt;
    (100 - criticalHitPercentage) *&lt;br /&gt;
      piercingHitPercentage *&lt;br /&gt;
      (100 - missPercentage),&lt;br /&gt;
    criticalHitPercentage * piercingHitPercentage * (100 - missPercentage),&lt;br /&gt;
  ];&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    attacker: attacker,&lt;br /&gt;
    victim: victim,&lt;br /&gt;
    attackFactor: calcAttackFactor(attacker, victim),&lt;br /&gt;
    mainAttackValue: calcMainAttackValue(attacker),&lt;br /&gt;
    attackValues: calcAttackValues(attacker, isPlayerVsPlayer),&lt;br /&gt;
    bonusValues: bonusValues,&lt;br /&gt;
    damageTypeWeights: damageTypeWeights,&lt;br /&gt;
    attackTypeMapping: mapping.attackType,&lt;br /&gt;
    damageWeightedByType: {&lt;br /&gt;
      normalHit: {},&lt;br /&gt;
      criticalHit: {},&lt;br /&gt;
      piercingHit: {},&lt;br /&gt;
      criticalPiercingHit: {},&lt;br /&gt;
    },&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateBattleValues(battleValues, skillFormula, skillInfo) {&lt;br /&gt;
  var weaponBonus = skillInfo.adjust || 0;&lt;br /&gt;
  var skillWard = 0;&lt;br /&gt;
  var skillBonus = 0;&lt;br /&gt;
  var skillBonusByBonus = 0;&lt;br /&gt;
  var { attacker: attacker, bonusValues: bonusValues } = battleValues;&lt;br /&gt;
  var {&lt;br /&gt;
    range: [minVariation, maxVariation],&lt;br /&gt;
  } = skillInfo;&lt;br /&gt;
  var variationLength = maxVariation - minVariation + 1;&lt;br /&gt;
&lt;br /&gt;
  if (skillInfo.hasOwnProperty(&amp;quot;weaponBonus&amp;quot;)) {&lt;br /&gt;
    var [weaponType, weaponBonusValue] = skillInfo.weaponBonus;&lt;br /&gt;
&lt;br /&gt;
    if (weaponType === attacker.weapon.type) {&lt;br /&gt;
      weaponBonus += weaponBonusValue;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillInfo.skillBonus) {&lt;br /&gt;
    skillBonus = skillInfo.skillBonus;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillInfo.skillWard) {&lt;br /&gt;
    skillWard = skillInfo.skillWard;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillInfo.skillBonusByBonus) {&lt;br /&gt;
    skillBonusByBonus = skillInfo.skillBonusByBonus;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillInfo.removeWeaponReduction) {&lt;br /&gt;
    bonusValues.weaponDefenseCoeff = 100;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  bonusValues.weaponBonusCoeff = 100 + weaponBonus;&lt;br /&gt;
  bonusValues.skillWardCoeff = 1 - skillWard / 100;&lt;br /&gt;
  bonusValues.skillBonusCoeff = 1 + skillBonus / 100;&lt;br /&gt;
  bonusValues.skillBonusByBonusCoeff = 100 + skillBonusByBonus;&lt;br /&gt;
&lt;br /&gt;
  battleValues.skillFormula = skillFormula;&lt;br /&gt;
  battleValues.skillRange = skillInfo.range;&lt;br /&gt;
  battleValues.attackValues.totalCardinal *= variationLength;&lt;br /&gt;
  battleValues.attackValues.possibleDamageCount *= variationLength;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcWeights(minValue, maxValue, minInterval) {&lt;br /&gt;
  var firstWeightLimit = minValue + minInterval - 1;&lt;br /&gt;
  var lastWeightsLimit = maxValue - minInterval + 1;&lt;br /&gt;
  var weights = [];&lt;br /&gt;
&lt;br /&gt;
  for (var value = minValue; value &amp;lt; firstWeightLimit; value++) {&lt;br /&gt;
    weights.push(value - minValue + 1);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (var value = firstWeightLimit; value &amp;lt;= lastWeightsLimit; value++) {&lt;br /&gt;
    weights.push(minInterval);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (var value = lastWeightsLimit + 1; value &amp;lt;= maxValue; value++) {&lt;br /&gt;
    weights.push(maxValue - value + 1);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return weights;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcBerserkBonus(skillPowerTable, victim) {&lt;br /&gt;
  if (!isChecked(victim.useBerserk) || victim.class !== &amp;quot;body&amp;quot;) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  const skillPower = getSkillPower(victim.skillBerserk, skillPowerTable);&lt;br /&gt;
&lt;br /&gt;
  if (!skillPower) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  const berserkBonus = Math.floor(skillPower * 25);&lt;br /&gt;
&lt;br /&gt;
  return berserkBonus;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcBlessingBonus(skillPowerTable, victim) {&lt;br /&gt;
  if (!isChecked(victim.isBlessed)) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  const int = victim.intBlessing;&lt;br /&gt;
  const dex = victim.dexBlessing;&lt;br /&gt;
  const skillPower = getSkillPower(victim.skillBlessing, skillPowerTable);&lt;br /&gt;
&lt;br /&gt;
  if (!skillPower) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  let blessingBonus = floorMultiplication(&lt;br /&gt;
    ((int * 0.3 + 5) * (2 * skillPower + 0.5) + 0.3 * dex) / (skillPower + 2.3),&lt;br /&gt;
    1&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  if (victim.class === &amp;quot;dragon&amp;quot; &amp;amp;&amp;amp; isChecked(victim.blessingOnself)) {&lt;br /&gt;
    blessingBonus = floorMultiplication(blessingBonus, 1.1);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return blessingBonus;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcFearBonus(skillPowerTable, victim) {&lt;br /&gt;
  if (!isChecked(victim.useFear) || victim.class !== &amp;quot;weaponary&amp;quot;) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  const skillPower = getSkillPower(victim.skillFear, skillPowerTable);&lt;br /&gt;
&lt;br /&gt;
  if (!skillPower) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  const fearBonus = 5 + Math.floor(skillPower * 20);&lt;br /&gt;
&lt;br /&gt;
  return fearBonus;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcDarkProtectionPoint(skillPowerTable, victim) {&lt;br /&gt;
  const skillPower = getSkillPower(victim.skillDarkProtection, skillPowerTable);&lt;br /&gt;
&lt;br /&gt;
  return floorMultiplication(100 - victim.int * 0.84 * skillPower, 1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcStealthBonus(skillPowerTable, attacker) {&lt;br /&gt;
  if (!isChecked(attacker.useStealth)) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  const skillPower = getSkillPower(attacker.skillStealth, skillPowerTable);&lt;br /&gt;
&lt;br /&gt;
  if (!skillPower) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  const stealthBonus = skillPower * 50;&lt;br /&gt;
&lt;br /&gt;
  return stealthBonus;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSkillFormula(battle, skillId, battleValues, removeSkillVariation) {&lt;br /&gt;
  var { attacker, victim, attackFactor } = battleValues;&lt;br /&gt;
  var skillPowerTable = battle.constants.skillPowerTable;&lt;br /&gt;
&lt;br /&gt;
  var skillFormula;&lt;br /&gt;
  var skillInfo = { range: [0, 0] };&lt;br /&gt;
&lt;br /&gt;
  var { class: attackerClass, level: lv, vit, str, int, dex } = attacker;&lt;br /&gt;
&lt;br /&gt;
  if (skillId &amp;lt;= 9) {&lt;br /&gt;
    var skillPower = getSkillPower(&lt;br /&gt;
      attacker[&amp;quot;attackSkill&amp;quot; + skillId],&lt;br /&gt;
      skillPowerTable&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    var improvedBySkillBonus = false;&lt;br /&gt;
    var improvedByBonus = false;&lt;br /&gt;
&lt;br /&gt;
    if (attackerClass === &amp;quot;body&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Triple lacération&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.1 * atk + (0.5 * atk + 1.5 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Moulinet à l'épée&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              3 * atk + (0.8 * atk + 5 * str + 3 * dex + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Accélération&lt;br /&gt;
        case 5:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * atk + (atk + dex * 3 + str * 7 + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Volonté de vivre&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              (3 * atk + (atk + 1.5 * str) * skillPower) * 1.07,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          break;&lt;br /&gt;
        // Tremblement de terre&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              3 * atk +&lt;br /&gt;
                (0.9 * atk + variation + 5 * str + 3 * dex + lv) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;mental&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Attaque de l'esprit&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2.3 * atk + (4 * atk + 4 * str + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Attaque de la paume&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2.3 * atk + (3 * atk + 4 * str + 3 * vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Charge&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * atk + (2 * atk + 2 * dex + 2 * vit + 4 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          break;&lt;br /&gt;
        // Coup d'épée&lt;br /&gt;
        case 5:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * atk + (atk + 3 * dex + 5 * str + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Orbe de l'épée&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              (2 * atk + (2 * atk + 2 * dex + 2 * vit + 4 * str) * skillPower) *&lt;br /&gt;
                1.1,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          break;&lt;br /&gt;
        // Tremblement de terre&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              3 * atk +&lt;br /&gt;
                (0.9 * atk + variation + 5 * str + 3 * dex + lv) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;blade_fight&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Embuscade&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk + (1.2 * atk + variation + 4 * dex + 4 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [1, 50];&lt;br /&gt;
          skillInfo.range = [500, 700];&lt;br /&gt;
          skillInfo.adjust = calcStealthBonus(skillPowerTable, attacker);&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Attaque rapide&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk + (1.6 * atk + variation + 7 * dex + 7 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [1, 35];&lt;br /&gt;
          skillInfo.range = [200, 300];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Dague filante&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * atk + (0.5 * atk + 9 * dex + 7 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Brume empoisonnée&lt;br /&gt;
        case 5:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * lv + (atk + 3 * str + 18 * dex) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Poison insidieux&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              (2 * lv + (atk + 3 * str + 18 * dex) * skillPower) * 1.1,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          break;&lt;br /&gt;
        // Étoiles brillantes&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk + (1.7 * atk + variation + 6 * dex + 5 * lv) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;archery&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Tir à répétition&lt;br /&gt;
        // case 1:&lt;br /&gt;
        //   skillFormula = function (atk) {&lt;br /&gt;
        //     return floorMultiplication(&lt;br /&gt;
        //       atk + 0.2 * atk * Math.floor(2 + 6 * skillPower) + (0.8 * atk + 8 * dex * attackFactor + 2 * int) * skillPower,&lt;br /&gt;
        //       1&lt;br /&gt;
        //     );&lt;br /&gt;
        //   };&lt;br /&gt;
        //   improvedByBonus = true;&lt;br /&gt;
        //   break;&lt;br /&gt;
        // Pluie de flèches&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk + (1.7 * atk + 5 * dex + str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Flèche de feu&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.5 * atk + (2.6 * atk + 0.9 * int + variation) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [100, 300];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Foulée de plume&lt;br /&gt;
        case 4:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              (3 * dex + 200 + 2 * str + 2 * int) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.removeWeaponReduction = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Flèche empoisonnée&lt;br /&gt;
        case 5:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk +&lt;br /&gt;
                (1.4 * atk + variation + 7 * dex + 4 * str + 4 * int) *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [100, 200];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Coup étincelant&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              (atk +&lt;br /&gt;
                (1.2 * atk + variation + 6 * dex + 3 * str + 3 * int) *&lt;br /&gt;
                  skillPower) *&lt;br /&gt;
                1.2,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [100, 200];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Tir tempête&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.9 * atk + (2.6 * atk + variation) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;weaponary&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Toucher brûlant&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk +&lt;br /&gt;
                2 * lv +&lt;br /&gt;
                2 * int +&lt;br /&gt;
                (2 * atk + 4 * str + 14 * int) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Tourbillon du dragon&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.1 * atk +&lt;br /&gt;
                2 * lv +&lt;br /&gt;
                2 * int +&lt;br /&gt;
                (1.5 * atk + str + 12 * int) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Contre-sort&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              40 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                2 * int +&lt;br /&gt;
                (10 * int + 7 * mav + variation) * attackFactor * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [50, 100];&lt;br /&gt;
          break;&lt;br /&gt;
        // Coup démoniaque&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.9 * atk + (2.6 * atk + variation) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;black_magic&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Attaque des ténèbres&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              40 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                2 * int +&lt;br /&gt;
                (13 * int + 6 * mav + variation) * attackFactor * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [50, 100];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Attaque de flammes&lt;br /&gt;
        // case 2:&lt;br /&gt;
        //   skillFormula = function (mav, variation) {&lt;br /&gt;
        //     return floorMultiplication(&lt;br /&gt;
        //       5 * lv + 2 * int + (7 * int + 8 * mav + 4 * str + 2 * vit + variation) * skillPower,&lt;br /&gt;
        //       1&lt;br /&gt;
        //     );&lt;br /&gt;
        //   };&lt;br /&gt;
        //   skillInfo.range = [180, 100];&lt;br /&gt;
        //   improvedByBonus = true;&lt;br /&gt;
        //   break;&lt;br /&gt;
        // Esprit de flammes&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              30 +&lt;br /&gt;
                2 * lv +&lt;br /&gt;
                2 * int +&lt;br /&gt;
                (7 * int + 6 * mav + variation) * attackFactor * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [200, 500];&lt;br /&gt;
          break;&lt;br /&gt;
        // Frappe de l'esprit&lt;br /&gt;
        // case 5:&lt;br /&gt;
        //   skillFormula = function (mav, variation) {&lt;br /&gt;
        //     return floorMultiplication(&lt;br /&gt;
        //       40 + 2 * lv + 2 * int + (2 * vit + 2 * dex + 13 * int + 6 * mav + variation) * attackFactor * skillPower,&lt;br /&gt;
        //       1&lt;br /&gt;
        //     );&lt;br /&gt;
        //   };&lt;br /&gt;
        //   skillInfo.range = [180, 200];&lt;br /&gt;
        //   break;&lt;br /&gt;
        // Orbe des ténèbres&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (mav) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              120 +&lt;br /&gt;
                6 * lv +&lt;br /&gt;
                (5 * vit + 5 * dex + 29 * int + 9 * mav) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Vague mortelle&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              120 +&lt;br /&gt;
                6 * lv +&lt;br /&gt;
                (5 * vit + 5 * dex + 30 * int + variation + 9 * mav) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;dragon&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Talisman volant&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (mav) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              70 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                (18 * int + 7 * str + 5 * mav + 50) * attackFactor * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [4, 10];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Dragon chassant&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (mav) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              60 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                (16 * int + 6 * dex + 6 * mav + 120) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [4, 10];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Rugissement du dragon&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (mav) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              70 +&lt;br /&gt;
                3 * lv +&lt;br /&gt;
                (20 * int + 3 * str + 10 * mav + 100) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [4, 10];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Météore&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              120 +&lt;br /&gt;
                6 * lv +&lt;br /&gt;
                (5 * vit + 5 * dex + 30 * int + variation + 9 * mav) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;heal&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Jet de foudre&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              60 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                (8 * int + 2 * dex + 8 * mav + variation) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [6, 10];&lt;br /&gt;
          skillInfo.range = [5 * int, 15 * int];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Invocation de foudre&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              40 +&lt;br /&gt;
                4 * lv +&lt;br /&gt;
                (13 * int + 2 * str + 10 * mav + variation) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [6, 10];&lt;br /&gt;
          skillInfo.range = [5 * int, 16 * int];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Griffe de foudre&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              50 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                (8 * int + 2 * str + 8 * mav + variation) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 800];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;lycan&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Déchiqueter&lt;br /&gt;
        // case 1:&lt;br /&gt;
        //   skillFormula = function (atk) {&lt;br /&gt;
        //     return floorMultiplication(&lt;br /&gt;
        //       1.1 * atk + (0.3 * atk + 1.5 * str) * skillPower,&lt;br /&gt;
        //       1&lt;br /&gt;
        //     );&lt;br /&gt;
        //   };&lt;br /&gt;
        //   skillInfo.weaponBonus = [5, 54];&lt;br /&gt;
        //   improvedByBonus = true;&lt;br /&gt;
        //   break;&lt;br /&gt;
        // Souffle de loup&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * atk + (atk + 3 * dex + 5 * str + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [5, 35];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Bond de loup&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk + (1.6 * atk + 200 + 7 * dex + 7 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [5, 35];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Griffe de loup&lt;br /&gt;
        case 4:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              3 * atk + (0.8 * atk + 6 * str + 2 * dex + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Tempête cinglante&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.8 * atk +&lt;br /&gt;
                (atk + 6 * dex + variation + 3 * str + lv) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
    if (improvedBySkillBonus) {&lt;br /&gt;
      skillInfo.skillBonus =&lt;br /&gt;
        16 * getSkillPower(attacker.skillBonus, skillPowerTable);&lt;br /&gt;
&lt;br /&gt;
      var skillWardChoice = victim.skillWardChoice;&lt;br /&gt;
&lt;br /&gt;
      if (skillWardChoice &amp;amp;&amp;amp; skillWardChoice === attackerClass) {&lt;br /&gt;
        skillInfo.skillWard =&lt;br /&gt;
          24 * getSkillPower(victim.skillWard, skillPowerTable);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (improvedByBonus) {&lt;br /&gt;
      skillInfo.skillBonusByBonus = attacker[&amp;quot;skillBonus&amp;quot; + skillId];&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (removeSkillVariation) {&lt;br /&gt;
      var averageVariation = (skillInfo.range[0] + skillInfo.range[0]) / 2;&lt;br /&gt;
      skillInfo.range = [averageVariation, averageVariation];&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    var skillPower = getSkillPower(&lt;br /&gt;
      attacker[&amp;quot;horseSkill&amp;quot; + skillId],&lt;br /&gt;
      skillPowerTable&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    switch (skillId) {&lt;br /&gt;
      // Combat équestre&lt;br /&gt;
      case 137:&lt;br /&gt;
        skillFormula = function (atk) {&lt;br /&gt;
          return floorMultiplication(atk + 2 * atk * skillPower, 1);&lt;br /&gt;
        };&lt;br /&gt;
        break;&lt;br /&gt;
      // Charge à cheval&lt;br /&gt;
      case 138:&lt;br /&gt;
        skillFormula = function (atk) {&lt;br /&gt;
          return floorMultiplication(&lt;br /&gt;
            2.4 * (200 + 1.5 * lv) + 600 * skillPower,&lt;br /&gt;
            1&lt;br /&gt;
          );&lt;br /&gt;
        };&lt;br /&gt;
        break;&lt;br /&gt;
      // Vague de Pouvoir&lt;br /&gt;
      case 139:&lt;br /&gt;
        skillFormula = function (atk) {&lt;br /&gt;
          return floorMultiplication(&lt;br /&gt;
            2 * (200 + 1.5 * lv) + 600 * skillPower,&lt;br /&gt;
            1&lt;br /&gt;
          );&lt;br /&gt;
        };&lt;br /&gt;
        break;&lt;br /&gt;
      // Grêle de flèches&lt;br /&gt;
      case 140:&lt;br /&gt;
        skillFormula = function (atk) {&lt;br /&gt;
          return floorMultiplication(atk + 2 * atk * skillPower, 1);&lt;br /&gt;
        };&lt;br /&gt;
        break;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  updateBattleValues(battleValues, skillFormula, skillInfo);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcMagicAttackValueAugmentation(&lt;br /&gt;
  magicAttackValueWeapon,&lt;br /&gt;
  magicAttackValueBonus&lt;br /&gt;
) {&lt;br /&gt;
  if (magicAttackValueBonus) {&lt;br /&gt;
    return Math.max(&lt;br /&gt;
      1,&lt;br /&gt;
      0.0025056 *&lt;br /&gt;
        magicAttackValueBonus ** 0.602338 *&lt;br /&gt;
        magicAttackValueWeapon ** 1.20476&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
  return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getMagicAttackValueAugmentation(&lt;br /&gt;
  minMagicAttackValue,&lt;br /&gt;
  maxMagicAttackValue,&lt;br /&gt;
  magicAttackValueBonus&lt;br /&gt;
) {&lt;br /&gt;
  var magicAttackValueAugmentation = [];&lt;br /&gt;
&lt;br /&gt;
  for (&lt;br /&gt;
    var magicAttackValue = minMagicAttackValue;&lt;br /&gt;
    magicAttackValue &amp;lt;= maxMagicAttackValue;&lt;br /&gt;
    magicAttackValue++&lt;br /&gt;
  ) {&lt;br /&gt;
    magicAttackValueAugmentation.push(&lt;br /&gt;
      calcMagicAttackValueAugmentation(magicAttackValue, magicAttackValueBonus)&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return magicAttackValueAugmentation;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcPhysicalDamage(battleValues) {&lt;br /&gt;
  const {&lt;br /&gt;
    attackFactor,&lt;br /&gt;
    mainAttackValue,&lt;br /&gt;
    attackValues: {&lt;br /&gt;
      minAttackValue,&lt;br /&gt;
      maxAttackValue,&lt;br /&gt;
      attackValueOther,&lt;br /&gt;
      weights,&lt;br /&gt;
      criticalAttackRange,&lt;br /&gt;
    },&lt;br /&gt;
    bonusValues,&lt;br /&gt;
    damageWeightedByType,&lt;br /&gt;
  } = battleValues;&lt;br /&gt;
&lt;br /&gt;
  const savedDamage = {};&lt;br /&gt;
&lt;br /&gt;
  if (bonusValues.missPercentage) {&lt;br /&gt;
    damageWeightedByType.miss = bonusValues.missPercentage / 100;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (&lt;br /&gt;
    let attackValue = minAttackValue;&lt;br /&gt;
    attackValue &amp;lt;= maxAttackValue;&lt;br /&gt;
    attackValue++&lt;br /&gt;
  ) {&lt;br /&gt;
    const weight = weights[attackValue - minAttackValue];&lt;br /&gt;
    const damageByType = [[], [], [], []];&lt;br /&gt;
    const currentDamageInfo = [weight, damageByType];&lt;br /&gt;
&lt;br /&gt;
    const secondaryAttackValue = 2 * attackValue + attackValueOther;&lt;br /&gt;
    const rawDamage =&lt;br /&gt;
      mainAttackValue + floorMultiplication(attackFactor, secondaryAttackValue);&lt;br /&gt;
&lt;br /&gt;
    const damageWithPrimaryBonuses = calcDamageWithPrimaryBonuses(&lt;br /&gt;
      rawDamage,&lt;br /&gt;
      bonusValues&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    const damageAfterDefense =&lt;br /&gt;
      damageWithPrimaryBonuses -&lt;br /&gt;
      bonusValues.defenseBoost -&lt;br /&gt;
      bonusValues.defenseMarriage;&lt;br /&gt;
&lt;br /&gt;
    const damageValues =&lt;br /&gt;
      damageAfterDefense &amp;lt;= 2 ? [1, 2, 3, 4, 5] : [damageAfterDefense];&lt;br /&gt;
&lt;br /&gt;
    for (const damage of damageValues) {&lt;br /&gt;
      saveFinalDamage(&lt;br /&gt;
        damage,&lt;br /&gt;
        damageWithPrimaryBonuses,&lt;br /&gt;
        bonusValues,&lt;br /&gt;
        criticalAttackRange,&lt;br /&gt;
        damageByType&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    savedDamage[attackValue] = currentDamageInfo;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  processSavedDamage(savedDamage, damageWeightedByType, battleValues);&lt;br /&gt;
&lt;br /&gt;
  return damageWeightedByType;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcPhysicalSkillDamage(battleValues) {&lt;br /&gt;
  const {&lt;br /&gt;
    attackFactor,&lt;br /&gt;
    mainAttackValue,&lt;br /&gt;
    attackValues: {&lt;br /&gt;
      minAttackValue,&lt;br /&gt;
      maxAttackValue,&lt;br /&gt;
      attackValueOther,&lt;br /&gt;
      weights,&lt;br /&gt;
      criticalAttackRange,&lt;br /&gt;
    },&lt;br /&gt;
    bonusValues,&lt;br /&gt;
    damageWeightedByType,&lt;br /&gt;
    skillFormula,&lt;br /&gt;
    skillRange: [minVariation, maxVariation],&lt;br /&gt;
  } = battleValues;&lt;br /&gt;
&lt;br /&gt;
  const savedDamage = {};&lt;br /&gt;
&lt;br /&gt;
  for (&lt;br /&gt;
    let attackValue = minAttackValue;&lt;br /&gt;
    attackValue &amp;lt;= maxAttackValue;&lt;br /&gt;
    attackValue++&lt;br /&gt;
  ) {&lt;br /&gt;
    const weight = weights[attackValue - minAttackValue];&lt;br /&gt;
&lt;br /&gt;
    const secondaryAttackValue = 2 * attackValue + attackValueOther;&lt;br /&gt;
    const rawDamage =&lt;br /&gt;
      mainAttackValue + floorMultiplication(attackFactor, secondaryAttackValue);&lt;br /&gt;
&lt;br /&gt;
    const damageWithPrimaryBonuses = calcDamageWithPrimaryBonuses(&lt;br /&gt;
      rawDamage,&lt;br /&gt;
      bonusValues&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    const damageValues =&lt;br /&gt;
      damageWithPrimaryBonuses &amp;lt;= 2&lt;br /&gt;
        ? [1, 2, 3, 4, 5]&lt;br /&gt;
        : [damageWithPrimaryBonuses];&lt;br /&gt;
    const weightByDamage = weight / damageValues.length;&lt;br /&gt;
&lt;br /&gt;
    for (let variation = minVariation; variation &amp;lt;= maxVariation; variation++) {&lt;br /&gt;
      for (const damage of damageValues) {&lt;br /&gt;
        const damageWithFormula = skillFormula(&lt;br /&gt;
          damage * bonusValues.useDamage,&lt;br /&gt;
          variation&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        let damageKey = damageWithFormula;&lt;br /&gt;
&lt;br /&gt;
        if (damageWithPrimaryBonuses &amp;lt; bonusValues.defenseBoost) {&lt;br /&gt;
          damageKey = `${damageWithFormula}_${damageWithPrimaryBonuses}`;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        const entry = savedDamage[damageKey];&lt;br /&gt;
&lt;br /&gt;
        if (entry) {&lt;br /&gt;
          entry[0] += weightByDamage;&lt;br /&gt;
          continue;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        const damageByType = [[], [], [], []];&lt;br /&gt;
        const currentDamageInfo = [weightByDamage, damageByType];&lt;br /&gt;
&lt;br /&gt;
        const finalDamage = Math.floor(&lt;br /&gt;
          (damageWithFormula * bonusValues.weaponBonusCoeff) / 100&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        saveFinalSkillDamage(&lt;br /&gt;
          finalDamage,&lt;br /&gt;
          bonusValues,&lt;br /&gt;
          criticalAttackRange,&lt;br /&gt;
          damageByType&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        savedDamage[damageKey] = currentDamageInfo;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  processSavedDamage(savedDamage, damageWeightedByType, battleValues);&lt;br /&gt;
&lt;br /&gt;
  return damageWeightedByType;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcMagicSkillDamage(battleValues) {&lt;br /&gt;
  const {&lt;br /&gt;
    attackValues: {&lt;br /&gt;
      minMagicAttackValue,&lt;br /&gt;
      maxMagicAttackValue,&lt;br /&gt;
      magicAttackValueAugmentation,&lt;br /&gt;
      weights,&lt;br /&gt;
      criticalAttackRange,&lt;br /&gt;
    },&lt;br /&gt;
    bonusValues,&lt;br /&gt;
    damageWeightedByType,&lt;br /&gt;
    skillFormula,&lt;br /&gt;
    skillRange: [minVariation, maxVariation],&lt;br /&gt;
  } = battleValues;&lt;br /&gt;
&lt;br /&gt;
  const savedDamage = {};&lt;br /&gt;
&lt;br /&gt;
  for (&lt;br /&gt;
    let magicAttackValue = minMagicAttackValue;&lt;br /&gt;
    magicAttackValue &amp;lt;= maxMagicAttackValue;&lt;br /&gt;
    magicAttackValue++&lt;br /&gt;
  ) {&lt;br /&gt;
    const index = magicAttackValue - minMagicAttackValue;&lt;br /&gt;
    const weight = weights[index];&lt;br /&gt;
&lt;br /&gt;
    for (let variation = minVariation; variation &amp;lt;= maxVariation; variation++) {&lt;br /&gt;
      const rawDamage = skillFormula(&lt;br /&gt;
        magicAttackValue + magicAttackValueAugmentation[index],&lt;br /&gt;
        variation&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      const entry = savedDamage[rawDamage];&lt;br /&gt;
&lt;br /&gt;
      if (entry) {&lt;br /&gt;
        entry[0] += weight;&lt;br /&gt;
        continue;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      const damageByType = [[], [], [], []];&lt;br /&gt;
      const currentDamageInfo = [weight, damageByType];&lt;br /&gt;
&lt;br /&gt;
      let damageWithPrimaryBonuses = Math.floor(&lt;br /&gt;
        (rawDamage * bonusValues.weaponBonusCoeff) / 100&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      damageWithPrimaryBonuses = calcDamageWithPrimaryBonuses(&lt;br /&gt;
        damageWithPrimaryBonuses,&lt;br /&gt;
        bonusValues&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      const damageValues =&lt;br /&gt;
        damageWithPrimaryBonuses &amp;lt;= 2&lt;br /&gt;
          ? [1, 2, 3, 4, 5]&lt;br /&gt;
          : [damageWithPrimaryBonuses];&lt;br /&gt;
&lt;br /&gt;
      for (const damage of damageValues) {&lt;br /&gt;
        saveFinalSkillDamage(&lt;br /&gt;
          damage,&lt;br /&gt;
          bonusValues,&lt;br /&gt;
          criticalAttackRange,&lt;br /&gt;
          damageByType&lt;br /&gt;
        );&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      savedDamage[rawDamage] = currentDamageInfo;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  processSavedDamage(savedDamage, damageWeightedByType, battleValues);&lt;br /&gt;
&lt;br /&gt;
  return damageWeightedByType;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcDamage(&lt;br /&gt;
  attacker,&lt;br /&gt;
  victim,&lt;br /&gt;
  attackType,&lt;br /&gt;
  battle,&lt;br /&gt;
  removeSkillVariation&lt;br /&gt;
) {&lt;br /&gt;
  var damageCalculator, skillId, skillType;&lt;br /&gt;
&lt;br /&gt;
  if (attackType === &amp;quot;physical&amp;quot;) {&lt;br /&gt;
    damageCalculator = calcPhysicalDamage;&lt;br /&gt;
  } else if (attackType.startsWith(&amp;quot;attackSkill&amp;quot;)) {&lt;br /&gt;
    skillId = Number(attackType.split(&amp;quot;attackSkill&amp;quot;)[1]);&lt;br /&gt;
&lt;br /&gt;
    if (isMagicClass(attacker) || isDispell(attacker, skillId)) {&lt;br /&gt;
      skillType = &amp;quot;magic&amp;quot;;&lt;br /&gt;
      damageCalculator = calcMagicSkillDamage;&lt;br /&gt;
    } else {&lt;br /&gt;
      skillType = &amp;quot;physical&amp;quot;;&lt;br /&gt;
      damageCalculator = calcPhysicalSkillDamage;&lt;br /&gt;
    }&lt;br /&gt;
  } else if (attackType.startsWith(&amp;quot;horseSkill&amp;quot;)) {&lt;br /&gt;
    skillType = &amp;quot;physical&amp;quot;;&lt;br /&gt;
    skillId = Number(attackType.split(&amp;quot;horseSkill&amp;quot;)[1]);&lt;br /&gt;
    damageCalculator = calcPhysicalSkillDamage;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var battleValues = createBattleValues(attacker, victim, battle, skillType);&lt;br /&gt;
&lt;br /&gt;
  if (skillId) {&lt;br /&gt;
    getSkillFormula(battle, skillId, battleValues, removeSkillVariation);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    damageWeightedByType: damageCalculator(battleValues),&lt;br /&gt;
    attackValues: battleValues.attackValues,&lt;br /&gt;
    skillType: skillType,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function damageWithoutVariation(&lt;br /&gt;
  attacker,&lt;br /&gt;
  victim,&lt;br /&gt;
  attackType,&lt;br /&gt;
  battle,&lt;br /&gt;
  characters&lt;br /&gt;
) {&lt;br /&gt;
  var startDamageTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
  var { damageWeightedByType, attackValues, skillType } = calcDamage(&lt;br /&gt;
    attacker,&lt;br /&gt;
    victim,&lt;br /&gt;
    attackType,&lt;br /&gt;
    battle&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  var endDamageTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
  displayResults(&lt;br /&gt;
    attackValues,&lt;br /&gt;
    damageWeightedByType,&lt;br /&gt;
    battle,&lt;br /&gt;
    attacker.name,&lt;br /&gt;
    victim.name&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  var endDisplayTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
  displayFightInfo(&lt;br /&gt;
    attackValues.possibleDamageCount,&lt;br /&gt;
    endDamageTime - startDamageTime,&lt;br /&gt;
    endDisplayTime - endDamageTime,&lt;br /&gt;
    battle&lt;br /&gt;
  );&lt;br /&gt;
  addPotentialErrorInformation(&lt;br /&gt;
    battle.errorInformation,&lt;br /&gt;
    attacker,&lt;br /&gt;
    victim,&lt;br /&gt;
    skillType,&lt;br /&gt;
    characters&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  hideElement(battle.bonusVariationResultContainer);&lt;br /&gt;
  showElement(battle.fightResultTitle);&lt;br /&gt;
  showElement(battle.fightResultContainer);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function damageWithVariation(&lt;br /&gt;
  attacker,&lt;br /&gt;
  victim,&lt;br /&gt;
  attackType,&lt;br /&gt;
  battle,&lt;br /&gt;
  entity,&lt;br /&gt;
  entityVariation&lt;br /&gt;
) {&lt;br /&gt;
  var startTime = performance.now();&lt;br /&gt;
  var damageByBonus = [];&lt;br /&gt;
  var augmentationByBonus = [];&lt;br /&gt;
  var {&lt;br /&gt;
    bonusVariationMinValue: minVariation,&lt;br /&gt;
    bonusVariationMaxValue: maxVariation,&lt;br /&gt;
  } = entity;&lt;br /&gt;
  var step = Math.ceil((maxVariation - minVariation + 1) / 500);&lt;br /&gt;
  var simulationCount = 0;&lt;br /&gt;
  var simulationTime;&lt;br /&gt;
  var firstDamage = 1;&lt;br /&gt;
&lt;br /&gt;
  for (&lt;br /&gt;
    var bonusValue = minVariation;&lt;br /&gt;
    bonusValue &amp;lt;= maxVariation;&lt;br /&gt;
    bonusValue += step&lt;br /&gt;
  ) {&lt;br /&gt;
    entity[entityVariation] = bonusValue;&lt;br /&gt;
&lt;br /&gt;
    var {&lt;br /&gt;
      damageWeightedByType,&lt;br /&gt;
      attackValues: { totalCardinal },&lt;br /&gt;
    } = calcDamage(&lt;br /&gt;
      copyObject(attacker),&lt;br /&gt;
      copyObject(victim),&lt;br /&gt;
      attackType,&lt;br /&gt;
      battle,&lt;br /&gt;
      true&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    var meanDamage = calcMeanDamage(damageWeightedByType, totalCardinal);&lt;br /&gt;
&lt;br /&gt;
    if (bonusValue === minVariation) {&lt;br /&gt;
      firstDamage = Math.max(meanDamage, 1e-3);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    damageByBonus.push({ x: bonusValue, y: meanDamage });&lt;br /&gt;
    augmentationByBonus.push({&lt;br /&gt;
      x: bonusValue,&lt;br /&gt;
      y: meanDamage / firstDamage - 1,&lt;br /&gt;
    });&lt;br /&gt;
    simulationCount++;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var endTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
  battle.damageByBonus = damageByBonus.concat(entityVariation);&lt;br /&gt;
&lt;br /&gt;
  addToBonusVariationChart(&lt;br /&gt;
    damageByBonus,&lt;br /&gt;
    augmentationByBonus,&lt;br /&gt;
    entity.bonusVariationName,&lt;br /&gt;
    battle.bonusVariationChart&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  simulationCount = battle.numberFormats.default.format(simulationCount);&lt;br /&gt;
  simulationTime = battle.numberFormats.second.format(&lt;br /&gt;
    (endTime - startTime) / 1000&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  battle.simulationCounter.textContent = simulationCount;&lt;br /&gt;
  battle.simulationTime.textContent = simulationTime;&lt;br /&gt;
&lt;br /&gt;
  hideElement(battle.fightResultContainer);&lt;br /&gt;
  showElement(battle.fightResultTitle);&lt;br /&gt;
  showElement(battle.bonusVariationResultContainer);&lt;br /&gt;
&lt;br /&gt;
  if (&lt;br /&gt;
    isChecked(attacker.useBonusVariation) &amp;amp;&amp;amp;&lt;br /&gt;
    isChecked(victim.useBonusVariation)&lt;br /&gt;
  ) {&lt;br /&gt;
    showElement(battle.errorInformation[&amp;quot;attacker-victim-variation&amp;quot;]);&lt;br /&gt;
  } else {&lt;br /&gt;
    hideElement(battle.errorInformation[&amp;quot;attacker-victim-variation&amp;quot;]);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function changeMonsterValues(monster, instance, attacker) {&lt;br /&gt;
  switch (instance) {&lt;br /&gt;
    case &amp;quot;SungMahiTower&amp;quot;:&lt;br /&gt;
      var sungMahiFloor = 1;&lt;br /&gt;
      var sungMahiStep = 1;&lt;br /&gt;
      var rawDefense = 120;&lt;br /&gt;
&lt;br /&gt;
      if (isPC(attacker)) {&lt;br /&gt;
        sungMahiFloor = attacker.sungMahiFloor;&lt;br /&gt;
        sungMahiStep = attacker.sungMahiStep;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (monster.rank === 5) {&lt;br /&gt;
        monster.level = 121;&lt;br /&gt;
        monster.dex = 75;&lt;br /&gt;
        rawDefense += 1;&lt;br /&gt;
      } else if (monster.rank === 6) {&lt;br /&gt;
        monster.level = 123;&lt;br /&gt;
        monster.dex = 75;&lt;br /&gt;
        rawDefense += 1;&lt;br /&gt;
      } else {&lt;br /&gt;
        monster.level = 120;&lt;br /&gt;
        monster.dex = 68;&lt;br /&gt;
      }&lt;br /&gt;
      monster.vit = 100;&lt;br /&gt;
      monster.rawDefense = rawDefense + (sungMahiStep - 1) * 6;&lt;br /&gt;
      monster.fistDefense = 0;&lt;br /&gt;
      monster.swordDefense = 0;&lt;br /&gt;
      monster.twoHandedSwordDefense = 0;&lt;br /&gt;
      monster.daggerDefense = 0;&lt;br /&gt;
      monster.bellDefense = 0;&lt;br /&gt;
      monster.fanDefense = 0;&lt;br /&gt;
      monster.arrowDefense = 0;&lt;br /&gt;
      monster.clawDefense = 0;&lt;br /&gt;
      monster.magicResistance = 0;&lt;br /&gt;
      monster.fireResistance = -20;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  switch (monster.vnum) {&lt;br /&gt;
    // Alastor&lt;br /&gt;
    case 6790:&lt;br /&gt;
      monster.iceResistance = 0;&lt;br /&gt;
      monster.iceBonus = 0;&lt;br /&gt;
      monster.lightningResistance = -10;&lt;br /&gt;
      monster.lightningBonus = 65;&lt;br /&gt;
      break;&lt;br /&gt;
&lt;br /&gt;
    // Zodiac boss&lt;br /&gt;
    case 2752:&lt;br /&gt;
    case 2762:&lt;br /&gt;
    case 2772:&lt;br /&gt;
    case 2782:&lt;br /&gt;
    case 2792:&lt;br /&gt;
    case 2802:&lt;br /&gt;
    case 2812:&lt;br /&gt;
    case 2822:&lt;br /&gt;
    case 2832:&lt;br /&gt;
    case 2842:&lt;br /&gt;
    case 2852:&lt;br /&gt;
    case 2862:&lt;br /&gt;
      monster.level = 136;&lt;br /&gt;
      monster.vit = 200;&lt;br /&gt;
      monster.rawDefense = 5000;&lt;br /&gt;
      break;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createWeapon(vnum) {&lt;br /&gt;
  var weapon = copyObject(weaponData[vnum]);&lt;br /&gt;
  var serpentVnums = [360, 380, 1210, 2230, 3250, 5200, 6150, 7330];&lt;br /&gt;
  var weaponValues = weapon[1];&lt;br /&gt;
  var isSerpent = isValueInArray(Number(vnum), serpentVnums);&lt;br /&gt;
  var isSpecial = Array.isArray(weaponValues[0]);&lt;br /&gt;
  var isMagic;&lt;br /&gt;
&lt;br /&gt;
  if (isSpecial) {&lt;br /&gt;
    isMagic = weaponValues[0][1] &amp;gt; 0;&lt;br /&gt;
  } else {&lt;br /&gt;
    isMagic = weaponValues[1] &amp;gt; 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    type: weapon[0],&lt;br /&gt;
    maxUpgrade: weapon[2].length - 1,&lt;br /&gt;
    isSerpent: isSerpent,&lt;br /&gt;
    isMagic: isMagic,&lt;br /&gt;
    getValues: function (upgrade) {&lt;br /&gt;
      var currentWeaponValues = weaponValues;&lt;br /&gt;
&lt;br /&gt;
      if (upgrade === undefined) {&lt;br /&gt;
        // rare bug when weaponUpgrade is deleted&lt;br /&gt;
        console.warn(&amp;quot;WeaponUpgrade is missing.&amp;quot;);&lt;br /&gt;
        upgrade = this.maxUpgrade;&lt;br /&gt;
      }&lt;br /&gt;
      upgrade = Math.min(upgrade, this.maxUpgrade);&lt;br /&gt;
&lt;br /&gt;
      if (isSpecial) {&lt;br /&gt;
        currentWeaponValues = weaponValues[upgrade];&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      this.minAttackValue = currentWeaponValues[2];&lt;br /&gt;
      this.maxAttackValue = currentWeaponValues[3];&lt;br /&gt;
      this.minMagicAttackValue = currentWeaponValues[0];&lt;br /&gt;
      this.maxMagicAttackValue = currentWeaponValues[1];&lt;br /&gt;
      this.growth = weapon[2][upgrade];&lt;br /&gt;
    },&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createMonster(&lt;br /&gt;
  monsterVnum,&lt;br /&gt;
  translateMonster,&lt;br /&gt;
  attacker,&lt;br /&gt;
  polymorphMonster&lt;br /&gt;
) {&lt;br /&gt;
  var monsterAttributes = monsterData[monsterVnum];&lt;br /&gt;
&lt;br /&gt;
  var monster = {&lt;br /&gt;
    vnum: Number(monsterVnum),&lt;br /&gt;
    name: translateMonster&lt;br /&gt;
      ? getTranslatedMonsterName(monsterVnum)&lt;br /&gt;
      : monsterAttributes[36],&lt;br /&gt;
    rank: monsterAttributes[0],&lt;br /&gt;
    race: monsterAttributes[1],&lt;br /&gt;
    attack: monsterAttributes[2],&lt;br /&gt;
    level: monsterAttributes[3],&lt;br /&gt;
    type: monsterAttributes[4],&lt;br /&gt;
    str: monsterAttributes[5],&lt;br /&gt;
    dex: monsterAttributes[6],&lt;br /&gt;
    vit: monsterAttributes[7],&lt;br /&gt;
    int: monsterAttributes[8],&lt;br /&gt;
    minAttackValue: monsterAttributes[9],&lt;br /&gt;
    maxAttackValue: monsterAttributes[10],&lt;br /&gt;
    rawDefense: monsterAttributes[11],&lt;br /&gt;
    criticalHit: monsterAttributes[12],&lt;br /&gt;
    piercingHit: monsterAttributes[13],&lt;br /&gt;
    fistDefense: monsterAttributes[14],&lt;br /&gt;
    swordDefense: monsterAttributes[15],&lt;br /&gt;
    twoHandedSwordDefense: monsterAttributes[16],&lt;br /&gt;
    daggerDefense: monsterAttributes[17],&lt;br /&gt;
    bellDefense: monsterAttributes[18],&lt;br /&gt;
    fanDefense: monsterAttributes[19],&lt;br /&gt;
    arrowDefense: monsterAttributes[20],&lt;br /&gt;
    clawDefense: monsterAttributes[21],&lt;br /&gt;
    fireResistance: monsterAttributes[22],&lt;br /&gt;
    lightningResistance: monsterAttributes[23],&lt;br /&gt;
    magicResistance: monsterAttributes[24],&lt;br /&gt;
    windResistance: monsterAttributes[25],&lt;br /&gt;
    lightningBonus: monsterAttributes[26],&lt;br /&gt;
    fireBonus: monsterAttributes[27],&lt;br /&gt;
    iceBonus: monsterAttributes[28],&lt;br /&gt;
    windBonus: monsterAttributes[29],&lt;br /&gt;
    earthBonus: monsterAttributes[30],&lt;br /&gt;
    darknessBonus: monsterAttributes[31],&lt;br /&gt;
    darknessResistance: monsterAttributes[32],&lt;br /&gt;
    iceResistance: monsterAttributes[33],&lt;br /&gt;
    earthResistance: monsterAttributes[34],&lt;br /&gt;
    damageMultiplier: monsterAttributes[35],&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  // monster.instance = 0;&lt;br /&gt;
&lt;br /&gt;
  // if (attacker &amp;amp;&amp;amp; monster.instance === 0) {&lt;br /&gt;
  //   changeMonsterValues(monster, &amp;quot;SungMahiTower&amp;quot;, attacker);&lt;br /&gt;
  // }&lt;br /&gt;
  if (!polymorphMonster) {&lt;br /&gt;
    changeMonsterValues(monster);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  monster.defense = monster.rawDefense + monster.level + monster.vit;&lt;br /&gt;
&lt;br /&gt;
  return monster;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addPotentialErrorInformation(&lt;br /&gt;
  errorInformation,&lt;br /&gt;
  attacker,&lt;br /&gt;
  victim,&lt;br /&gt;
  skillType,&lt;br /&gt;
  characters&lt;br /&gt;
) {&lt;br /&gt;
  for (var error of Object.values(errorInformation)) {&lt;br /&gt;
    hideElement(error);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker)) {&lt;br /&gt;
    if (isRiding(attacker)) {&lt;br /&gt;
      if (attacker.horsePoint === 0) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;horse-level&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
      showElement(errorInformation[&amp;quot;horse-stat&amp;quot;]);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isPolymorph(attacker)) {&lt;br /&gt;
      if (attacker.polymorphPoint === 0) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;polymorph-level&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (&lt;br /&gt;
        (attacker.polymorphPoint &amp;lt;= 39 &amp;amp;&amp;amp; attacker.attackValuePercent &amp;lt;= 199) ||&lt;br /&gt;
        (attacker.polymorphPoint === 40 &amp;amp;&amp;amp; attacker.attackValuePercent &amp;lt;= 299)&lt;br /&gt;
      ) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;polymorph-bonus&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
    if (skillType === &amp;quot;magic&amp;quot; &amp;amp;&amp;amp; !isDispell(attacker, 6)) {&lt;br /&gt;
      if (attacker.magicAttackValue) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;magic-attack-value-bonus&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
      if (victim.magicResistance) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;magic-resistance&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
      if (victim.magicResistance &amp;gt; 0 &amp;amp;&amp;amp; attacker.magicPenetration) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;magic-penetration&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    showElement(errorInformation[&amp;quot;monster-attacker&amp;quot;]);&lt;br /&gt;
    if (isMagicAttacker(attacker) &amp;amp;&amp;amp; victim.magicResistance) {&lt;br /&gt;
      showElement(errorInformation[&amp;quot;magic-resistance&amp;quot;]);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (isPC(victim)) {&lt;br /&gt;
    if (isRiding(victim)) {&lt;br /&gt;
      showElement(errorInformation[&amp;quot;horse-stat&amp;quot;]);&lt;br /&gt;
    }&lt;br /&gt;
    if (isPolymorph(victim)) {&lt;br /&gt;
      if (attacker.polymorphPoint === 0) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;polymorph-level&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
      showElement(errorInformation[&amp;quot;polymorph-defense&amp;quot;]);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (characters.unsavedChanges) {&lt;br /&gt;
    showElement(errorInformation[&amp;quot;save&amp;quot;]);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function reduceChartPointsListener(battle) {&lt;br /&gt;
  var {&lt;br /&gt;
    reduceChartPointsContainer,&lt;br /&gt;
    reduceChartPoints,&lt;br /&gt;
    numberFormats: { second: numberFormat },&lt;br /&gt;
    displayTime,&lt;br /&gt;
  } = battle;&lt;br /&gt;
&lt;br /&gt;
  reduceChartPoints.addEventListener(&amp;quot;change&amp;quot;, function () {&lt;br /&gt;
    reduceChartPoints.disabled = true;&lt;br /&gt;
&lt;br /&gt;
    var startDisplayTime = performance.now();&lt;br /&gt;
    var scatterDataByType = battle.scatterDataByType;&lt;br /&gt;
    var {&lt;br /&gt;
      chart,&lt;br /&gt;
      maxPoints,&lt;br /&gt;
      chart: {&lt;br /&gt;
        data: { datasets },&lt;br /&gt;
      },&lt;br /&gt;
    } = battle.damageChart;&lt;br /&gt;
    var addAnimations = false;&lt;br /&gt;
&lt;br /&gt;
    for (var index = 0; index &amp;lt; datasets.length; index++) {&lt;br /&gt;
      var dataset = datasets[index];&lt;br /&gt;
      var scatterData = scatterDataByType[dataset.name];&lt;br /&gt;
&lt;br /&gt;
      if (dataset.canBeReduced &amp;amp;&amp;amp; reduceChartPoints.checked) {&lt;br /&gt;
        dataset.data = aggregateDamage(scatterData, maxPoints);&lt;br /&gt;
        addAnimations = true;&lt;br /&gt;
      } else {&lt;br /&gt;
        dataset.data = scatterData;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    handleChartAnimations(chart, addAnimations);&lt;br /&gt;
    chart.update();&lt;br /&gt;
&lt;br /&gt;
    displayTime.textContent = numberFormat.format(&lt;br /&gt;
      (performance.now() - startDisplayTime) / 1000&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    setTimeout(function () {&lt;br /&gt;
      reduceChartPoints.disabled = false;&lt;br /&gt;
    }, 1000);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  reduceChartPointsContainer.addEventListener(&amp;quot;pointerup&amp;quot;, function (event) {&lt;br /&gt;
    if (event.pointerType === &amp;quot;mouse&amp;quot;) {&lt;br /&gt;
      if (event.target.closest(&amp;quot;label&amp;quot;)) {&lt;br /&gt;
        return;&lt;br /&gt;
      }&lt;br /&gt;
      reduceChartPoints.click();&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function downloadRawDataListener(battle) {&lt;br /&gt;
  var { downLoadRawData, downLoadRawDataVariation } = battle;&lt;br /&gt;
  var fileType = &amp;quot;text/csv;charset=utf-8;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  downLoadRawData.addEventListener(&amp;quot;click&amp;quot;, function () {&lt;br /&gt;
    var damageWeightedByType = battle.damageWeightedByType;&lt;br /&gt;
    var filename = &amp;quot;raw_damage.csv&amp;quot;;&lt;br /&gt;
    var csvContent = &amp;quot;damage,probabilities,damageType\n&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    for (var damageType in damageWeightedByType) {&lt;br /&gt;
      var damageWeighted = damageWeightedByType[damageType];&lt;br /&gt;
&lt;br /&gt;
      for (var damage in damageWeighted) {&lt;br /&gt;
        csvContent +=&lt;br /&gt;
          damage + &amp;quot;,&amp;quot; + damageWeighted[damage] + &amp;quot;,&amp;quot; + damageType + &amp;quot;\n&amp;quot;;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    downloadData(csvContent, fileType, filename);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  downLoadRawDataVariation.addEventListener(&amp;quot;click&amp;quot;, function () {&lt;br /&gt;
    var damageByBonus = battle.damageByBonus;&lt;br /&gt;
    var damageByBonusLength = damageByBonus.length;&lt;br /&gt;
    var filename = &amp;quot;damage_variation.csv&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    if (!damageByBonusLength) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var csvContent =&lt;br /&gt;
      damageByBonus[damageByBonusLength - 1] + &amp;quot;,averageDamage\n&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    for (var index = 0; index &amp;lt; damageByBonusLength - 1; index++) {&lt;br /&gt;
      var row = damageByBonus[index];&lt;br /&gt;
&lt;br /&gt;
      csvContent += row.x + &amp;quot;,&amp;quot; + row.y + &amp;quot;\n&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    downloadData(csvContent, fileType, filename);&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function displayResults(&lt;br /&gt;
  attackValues,&lt;br /&gt;
  damageWeightedByType,&lt;br /&gt;
  battle,&lt;br /&gt;
  attackerName,&lt;br /&gt;
  victimName&lt;br /&gt;
) {&lt;br /&gt;
  var [meanDamage, minDamage, maxDamage, scatterDataByType, uniqueDamageCount] =&lt;br /&gt;
    prepareDamageData(damageWeightedByType, attackValues);&lt;br /&gt;
&lt;br /&gt;
  addToDamageChart(battle, scatterDataByType);&lt;br /&gt;
  updateDamageChartDescription(battle, uniqueDamageCount);&lt;br /&gt;
  displayFightResults(&lt;br /&gt;
    battle,&lt;br /&gt;
    attackerName,&lt;br /&gt;
    victimName,&lt;br /&gt;
    meanDamage,&lt;br /&gt;
    minDamage,&lt;br /&gt;
    maxDamage&lt;br /&gt;
  );&lt;br /&gt;
  battle.damageWeightedByType = damageWeightedByType;&lt;br /&gt;
  battle.scatterDataByType = scatterDataByType;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function displayFightResults(&lt;br /&gt;
  battle,&lt;br /&gt;
  attackerName,&lt;br /&gt;
  victimName,&lt;br /&gt;
  meanDamage,&lt;br /&gt;
  minDamage,&lt;br /&gt;
  maxDamage&lt;br /&gt;
) {&lt;br /&gt;
  var {&lt;br /&gt;
    tableResultFight,&lt;br /&gt;
    tableResultHistory,&lt;br /&gt;
    savedFights,&lt;br /&gt;
    numberFormats: { default: numberFormat },&lt;br /&gt;
    deleteFightTemplate,&lt;br /&gt;
  } = battle;&lt;br /&gt;
&lt;br /&gt;
  hideElement(tableResultHistory.rows[1]);&lt;br /&gt;
&lt;br /&gt;
  var valuesToDisplay = [&lt;br /&gt;
    attackerName,&lt;br /&gt;
    victimName,&lt;br /&gt;
    battle.battleChoice.attackType.selectedText,&lt;br /&gt;
    meanDamage,&lt;br /&gt;
    minDamage,&lt;br /&gt;
    maxDamage,&lt;br /&gt;
  ];&lt;br /&gt;
&lt;br /&gt;
  savedFights.push(valuesToDisplay);&lt;br /&gt;
  updateSavedFights(savedFights);&lt;br /&gt;
&lt;br /&gt;
  editTableResultRow(tableResultFight.rows[1], valuesToDisplay, numberFormat);&lt;br /&gt;
  addRowToTableResultHistory(&lt;br /&gt;
    tableResultHistory,&lt;br /&gt;
    valuesToDisplay,&lt;br /&gt;
    deleteFightTemplate,&lt;br /&gt;
    numberFormat&lt;br /&gt;
  );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function displayFightInfo(&lt;br /&gt;
  possibleDamageCount,&lt;br /&gt;
  damageTimeDuration,&lt;br /&gt;
  displayTimeDuration,&lt;br /&gt;
  battle&lt;br /&gt;
) {&lt;br /&gt;
  const {&lt;br /&gt;
    damageInfoContainer,&lt;br /&gt;
    numberFormats: { default: defaultFormat, second: secondFormat },&lt;br /&gt;
    possibleDamageCounter,&lt;br /&gt;
    damageTime,&lt;br /&gt;
    displayTime,&lt;br /&gt;
  } = battle;&lt;br /&gt;
&lt;br /&gt;
  if (possibleDamageCount &amp;lt;= 1) {&lt;br /&gt;
    hideElement(damageInfoContainer);&lt;br /&gt;
    return;&lt;br /&gt;
  } else {&lt;br /&gt;
    showElement(damageInfoContainer);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  possibleDamageCount = defaultFormat.format(possibleDamageCount);&lt;br /&gt;
  damageTimeDuration = secondFormat.format(damageTimeDuration / 1000);&lt;br /&gt;
  displayTimeDuration = secondFormat.format(displayTimeDuration / 1000);&lt;br /&gt;
&lt;br /&gt;
  possibleDamageCounter.textContent = possibleDamageCount;&lt;br /&gt;
  damageTime.textContent = damageTimeDuration;&lt;br /&gt;
  displayTime.textContent = displayTimeDuration;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function parseTypeAndName(data) {&lt;br /&gt;
  var [type, nameOrVnum] = splitFirst(data, &amp;quot;-&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    type: type,&lt;br /&gt;
    nameOrVnum: nameOrVnum,&lt;br /&gt;
    isCharacter: type === &amp;quot;character&amp;quot;,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isCharacterSelected(characterName, selected) {&lt;br /&gt;
  if (!selected) {&lt;br /&gt;
    return false;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var { nameOrVnum, isCharacter } = parseTypeAndName(selected);&lt;br /&gt;
&lt;br /&gt;
  return nameOrVnum === characterName &amp;amp;&amp;amp; isCharacter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function useBonusVariationMode(character, variation) {&lt;br /&gt;
  return (&lt;br /&gt;
    isChecked(character.useBonusVariation) &amp;amp;&amp;amp;&lt;br /&gt;
    character.hasOwnProperty(variation) &amp;amp;&amp;amp;&lt;br /&gt;
    character.bonusVariationMinValue &amp;lt; character.bonusVariationMaxValue&lt;br /&gt;
  );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createBattle(characters, battle) {&lt;br /&gt;
  var battleChoice = battle.battleChoice;&lt;br /&gt;
  var battleForm = battleChoice.form;&lt;br /&gt;
  var lastInvalidTime = 0;&lt;br /&gt;
&lt;br /&gt;
  battleForm.addEventListener(&amp;quot;change&amp;quot;, handleBattleFormChange);&lt;br /&gt;
  battleForm.addEventListener(&amp;quot;invalid&amp;quot;, handleBattleFormInvalid, true);&lt;br /&gt;
  battleForm.addEventListener(&amp;quot;submit&amp;quot;, handleBattleFormSubmit);&lt;br /&gt;
&lt;br /&gt;
  function handleBattleFormChange(event) {&lt;br /&gt;
    var target = event.target;&lt;br /&gt;
    var { name: targetName, value: targetValue, type: targetType } = target;&lt;br /&gt;
&lt;br /&gt;
    if (targetType !== &amp;quot;radio&amp;quot;) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (targetName === &amp;quot;attackType&amp;quot;) {&lt;br /&gt;
      battleChoice.attackType.selectedText =&lt;br /&gt;
        target.previousElementSibling.textContent;&lt;br /&gt;
    } else {&lt;br /&gt;
      updateBattleChoiceButton(battleChoice, targetName, targetValue);&lt;br /&gt;
&lt;br /&gt;
      if (targetName === &amp;quot;attacker&amp;quot;) {&lt;br /&gt;
        filterAttackTypeSelection(characters, battleChoice, targetValue);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function handleBattleFormInvalid(event) {&lt;br /&gt;
    var currentTime = Date.now();&lt;br /&gt;
&lt;br /&gt;
    if (currentTime - lastInvalidTime &amp;lt; 100) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    lastInvalidTime = currentTime;&lt;br /&gt;
&lt;br /&gt;
    var target = event.target;&lt;br /&gt;
    var modal = target.closest(&amp;quot;.modal&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (!modal) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var dataModal = modal.dataset.modal;&lt;br /&gt;
&lt;br /&gt;
    if (!dataModal) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var category = dataModal.split(&amp;quot;-&amp;quot;)[0];&lt;br /&gt;
&lt;br /&gt;
    if (isValueInArray(category, battleChoice.categories)) {&lt;br /&gt;
      battleChoice[category].button.click();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function handleBattleFormSubmit(event) {&lt;br /&gt;
    event.preventDefault();&lt;br /&gt;
&lt;br /&gt;
    // auto save&lt;br /&gt;
    if (characters.unsavedChanges) {&lt;br /&gt;
      characters.saveButton.click();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var battleInfo = new FormData(event.target);&lt;br /&gt;
    var attackerData = battleInfo.get(&amp;quot;attacker&amp;quot;);&lt;br /&gt;
    var attackType = battleInfo.get(&amp;quot;attackType&amp;quot;);&lt;br /&gt;
    var victimData = battleInfo.get(&amp;quot;victim&amp;quot;);&lt;br /&gt;
    var attackerVariation;&lt;br /&gt;
    var victimVariation;&lt;br /&gt;
&lt;br /&gt;
    if (!attackerData &amp;amp;&amp;amp; !attackType &amp;amp;&amp;amp; !victimData) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var { nameOrVnum: attackerNameOrVnum, isCharacter: attackerIsPlayer } =&lt;br /&gt;
      parseTypeAndName(attackerData);&lt;br /&gt;
    var { nameOrVnum: victimNameOrVnum, isCharacter: victimIsPlayer } =&lt;br /&gt;
      parseTypeAndName(victimData);&lt;br /&gt;
&lt;br /&gt;
    if (attackerIsPlayer) {&lt;br /&gt;
      var attacker = copyObject(characters.savedCharacters[attackerNameOrVnum]);&lt;br /&gt;
      attackerVariation = attacker.bonusVariation;&lt;br /&gt;
    } else {&lt;br /&gt;
      var attacker = createMonster(&lt;br /&gt;
        attackerNameOrVnum,&lt;br /&gt;
        characters.translateMonsters&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (victimIsPlayer) {&lt;br /&gt;
      var victim = copyObject(characters.savedCharacters[victimNameOrVnum]);&lt;br /&gt;
      victimVariation = victim.bonusVariation;&lt;br /&gt;
    } else {&lt;br /&gt;
      var victim = createMonster(&lt;br /&gt;
        victimNameOrVnum,&lt;br /&gt;
        characters.translateMonsters,&lt;br /&gt;
        attacker&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (useBonusVariationMode(attacker, attackerVariation)) {&lt;br /&gt;
      damageWithVariation(&lt;br /&gt;
        attacker,&lt;br /&gt;
        victim,&lt;br /&gt;
        attackType,&lt;br /&gt;
        battle,&lt;br /&gt;
        attacker,&lt;br /&gt;
        attackerVariation&lt;br /&gt;
      );&lt;br /&gt;
    } else if (useBonusVariationMode(victim, victimVariation)) {&lt;br /&gt;
      damageWithVariation(&lt;br /&gt;
        attacker,&lt;br /&gt;
        victim,&lt;br /&gt;
        attackType,&lt;br /&gt;
        battle,&lt;br /&gt;
        victim,&lt;br /&gt;
        victimVariation&lt;br /&gt;
      );&lt;br /&gt;
    } else {&lt;br /&gt;
      damageWithoutVariation(attacker, victim, attackType, battle, characters);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createMapping() {&lt;br /&gt;
  return {&lt;br /&gt;
    typeFlag: [&lt;br /&gt;
      &amp;quot;animalBonus&amp;quot;, // 0&lt;br /&gt;
      &amp;quot;humanBonus&amp;quot;, // 1&lt;br /&gt;
      &amp;quot;orcBonus&amp;quot;, // 2&lt;br /&gt;
      &amp;quot;mysticBonus&amp;quot;, // 3&lt;br /&gt;
      &amp;quot;undeadBonus&amp;quot;, // 4&lt;br /&gt;
      &amp;quot;insectBonus&amp;quot;, // 5&lt;br /&gt;
      &amp;quot;desertBonus&amp;quot;, // 6&lt;br /&gt;
      &amp;quot;devilBonus&amp;quot;, // 7&lt;br /&gt;
      &amp;quot;zodiacBonus&amp;quot;, // 8&lt;br /&gt;
    ],&lt;br /&gt;
    raceBonus: {&lt;br /&gt;
      warrior: &amp;quot;warriorBonus&amp;quot;,&lt;br /&gt;
      sura: &amp;quot;suraBonus&amp;quot;,&lt;br /&gt;
      ninja: &amp;quot;ninjaBonus&amp;quot;,&lt;br /&gt;
      shaman: &amp;quot;shamanBonus&amp;quot;,&lt;br /&gt;
      lycan: &amp;quot;lycanBonus&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    raceResistance: {&lt;br /&gt;
      warrior: &amp;quot;warriorResistance&amp;quot;,&lt;br /&gt;
      sura: &amp;quot;suraResistance&amp;quot;,&lt;br /&gt;
      ninja: &amp;quot;ninjaResistance&amp;quot;,&lt;br /&gt;
      shaman: &amp;quot;shamanResistance&amp;quot;,&lt;br /&gt;
      lycan: &amp;quot;lycanResistance&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    defenseWeapon: [&lt;br /&gt;
      &amp;quot;swordDefense&amp;quot;, // 0&lt;br /&gt;
      &amp;quot;daggerDefense&amp;quot;, // 1&lt;br /&gt;
      &amp;quot;arrowDefense&amp;quot;, // 2&lt;br /&gt;
      &amp;quot;twoHandedSwordDefense&amp;quot;, // 3&lt;br /&gt;
      &amp;quot;bellDefense&amp;quot;, // 4&lt;br /&gt;
      &amp;quot;clawDefense&amp;quot;, // 5&lt;br /&gt;
      &amp;quot;fanDefense&amp;quot;, // 6&lt;br /&gt;
      &amp;quot;swordDefense&amp;quot;, // 7&lt;br /&gt;
      &amp;quot;fistDefense&amp;quot;, // 8&lt;br /&gt;
    ],&lt;br /&gt;
    breakWeapon: [&lt;br /&gt;
      &amp;quot;breakSwordDefense&amp;quot;, // 0&lt;br /&gt;
      &amp;quot;breakDaggerDefense&amp;quot;, // 1&lt;br /&gt;
      &amp;quot;breakArrowDefense&amp;quot;, // 2&lt;br /&gt;
      &amp;quot;breakTwoHandedSwordDefense&amp;quot;, // 3&lt;br /&gt;
      &amp;quot;breakBellDefense&amp;quot;, // 4&lt;br /&gt;
      &amp;quot;breakClawDefense&amp;quot;, // 5&lt;br /&gt;
      &amp;quot;breakFanDefense&amp;quot;, // 6&lt;br /&gt;
      &amp;quot;breakSwordDefense&amp;quot;, // 7&lt;br /&gt;
    ],&lt;br /&gt;
    elementBonus: [&lt;br /&gt;
      &amp;quot;fireBonus&amp;quot;, // 0&lt;br /&gt;
      &amp;quot;iceBonus&amp;quot;, // 1&lt;br /&gt;
      &amp;quot;windBonus&amp;quot;, // 2&lt;br /&gt;
      &amp;quot;lightningBonus&amp;quot;, // 3&lt;br /&gt;
      &amp;quot;earthBonus&amp;quot;, // 4&lt;br /&gt;
      &amp;quot;darknessBonus&amp;quot;, // 5&lt;br /&gt;
    ],&lt;br /&gt;
    elementResistance: [&lt;br /&gt;
      &amp;quot;fireResistance&amp;quot;, // 0&lt;br /&gt;
      &amp;quot;iceResistance&amp;quot;, // 1&lt;br /&gt;
      &amp;quot;windResistance&amp;quot;, // 2&lt;br /&gt;
      &amp;quot;lightningResistance&amp;quot;, // 3&lt;br /&gt;
      &amp;quot;earthResistance&amp;quot;, // 4&lt;br /&gt;
      &amp;quot;darknessResistance&amp;quot;, // 5&lt;br /&gt;
    ],&lt;br /&gt;
    attackType: [&lt;br /&gt;
      &amp;quot;normalHit&amp;quot;,&lt;br /&gt;
      &amp;quot;criticalHit&amp;quot;,&lt;br /&gt;
      &amp;quot;piercingHit&amp;quot;,&lt;br /&gt;
      &amp;quot;criticalPiercingHit&amp;quot;,&lt;br /&gt;
    ],&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createConstants() {&lt;br /&gt;
  var constants = {&lt;br /&gt;
    polymorphPowerTable: [&lt;br /&gt;
      10, 11, 11, 12, 13, 13, 14, 15, 16, 17, 18, 19, 20, 22, 23, 24, 26, 27,&lt;br /&gt;
      29, 31, 33, 35, 37, 39, 41, 44, 46, 49, 52, 55, 59, 62, 66, 70, 74, 79,&lt;br /&gt;
      84, 89, 94, 100, 0,&lt;br /&gt;
    ],&lt;br /&gt;
    skillPowerTable: [&lt;br /&gt;
      0, 0.05, 0.06, 0.08, 0.1, 0.12, 0.14, 0.16, 0.18, 0.2, 0.22, 0.24, 0.26,&lt;br /&gt;
      0.28, 0.3, 0.32, 0.34, 0.36, 0.38, 0.4, 0.5, 0.52, 0.54, 0.56, 0.58, 0.6,&lt;br /&gt;
      0.63, 0.66, 0.69, 0.72, 0.82, 0.85, 0.88, 0.91, 0.94, 0.98, 1.02, 1.06,&lt;br /&gt;
      1.1, 1.15, 1.25,&lt;br /&gt;
    ],&lt;br /&gt;
    marriageTable: {&lt;br /&gt;
      harmonyEarrings: [4, 5, 6, 8],&lt;br /&gt;
      loveEarrings: [4, 5, 6, 8],&lt;br /&gt;
      harmonyBracelet: [4, 5, 6, 8],&lt;br /&gt;
      loveNecklace: [20, 25, 30, 40],&lt;br /&gt;
      harmonyNecklace: [12, 16, 20, 30],&lt;br /&gt;
    },&lt;br /&gt;
    allowedWeaponsPerRace: {&lt;br /&gt;
      warrior: [0, 3, 8],&lt;br /&gt;
      ninja: [0, 1, 2, 8],&lt;br /&gt;
      sura: [0, 7, 8],&lt;br /&gt;
      shaman: [4, 6, 8],&lt;br /&gt;
      lycan: [5, 8],&lt;br /&gt;
    },&lt;br /&gt;
  };&lt;br /&gt;
  return constants;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initResultTableHistory(battle) {&lt;br /&gt;
  var {&lt;br /&gt;
    tableResultHistory,&lt;br /&gt;
    savedFights,&lt;br /&gt;
    deleteFightTemplate,&lt;br /&gt;
    numberFormats: { default: numberFormat },&lt;br /&gt;
  } = battle;&lt;br /&gt;
  var startIndex = 3;&lt;br /&gt;
&lt;br /&gt;
  if (savedFights.length) {&lt;br /&gt;
    hideElement(tableResultHistory.rows[1]);&lt;br /&gt;
&lt;br /&gt;
    for (var savedFight of savedFights) {&lt;br /&gt;
      addRowToTableResultHistory(&lt;br /&gt;
        tableResultHistory,&lt;br /&gt;
        savedFight,&lt;br /&gt;
        deleteFightTemplate,&lt;br /&gt;
        numberFormat&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  tableResultHistory.addEventListener(&amp;quot;click&amp;quot;, function (event) {&lt;br /&gt;
    var deleteButton = event.target.closest(&amp;quot;.svg-icon-delete&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (deleteButton) {&lt;br /&gt;
      var row = deleteButton.closest(&amp;quot;tr&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
      if (row) {&lt;br /&gt;
        savedFights.splice(row.rowIndex - startIndex, 1);&lt;br /&gt;
        updateSavedFights(savedFights);&lt;br /&gt;
&lt;br /&gt;
        row.remove();&lt;br /&gt;
&lt;br /&gt;
        if (tableResultHistory.rows.length === startIndex) {&lt;br /&gt;
          showElement(tableResultHistory.rows[1]);&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initDamageChart(battle, currentLanguage, defaultText) {&lt;br /&gt;
  const { reduceChartPointsContainer, reduceChartPoints } = battle;&lt;br /&gt;
  const { default: defaultFormat, percent: percentFormat } =&lt;br /&gt;
    battle.numberFormats;&lt;br /&gt;
  const customPlugins = {&lt;br /&gt;
    id: &amp;quot;customPlugins&amp;quot;,&lt;br /&gt;
    afterDraw(chart) {&lt;br /&gt;
      const missPercentage = chart.data.missPercentage;&lt;br /&gt;
&lt;br /&gt;
      if (!missPercentage) {&lt;br /&gt;
        return;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      const {&lt;br /&gt;
        ctx,&lt;br /&gt;
        chartArea: { top, right },&lt;br /&gt;
      } = chart;&lt;br /&gt;
      ctx.save();&lt;br /&gt;
      const text =&lt;br /&gt;
        defaultText.miss + &amp;quot; : &amp;quot; + percentFormat.format(missPercentage);&lt;br /&gt;
      const padding = 4;&lt;br /&gt;
      const fontSize = 14;&lt;br /&gt;
&lt;br /&gt;
      ctx.font = fontSize + &amp;quot;px Helvetica Neue&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
      const textWidth = ctx.measureText(text).width;&lt;br /&gt;
      const xPosition = right - textWidth - 5;&lt;br /&gt;
      const yPosition = top + 5;&lt;br /&gt;
&lt;br /&gt;
      ctx.fillStyle = &amp;quot;rgba(255, 0, 0, 0.2)&amp;quot;;&lt;br /&gt;
      ctx.fillRect(&lt;br /&gt;
        xPosition - padding,&lt;br /&gt;
        yPosition - padding,&lt;br /&gt;
        textWidth + 2 * padding,&lt;br /&gt;
        fontSize + 2 * padding&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      ctx.strokeStyle = &amp;quot;red&amp;quot;;&lt;br /&gt;
      ctx.strokeRect(&lt;br /&gt;
        xPosition - padding,&lt;br /&gt;
        yPosition - padding,&lt;br /&gt;
        textWidth + 2 * padding,&lt;br /&gt;
        fontSize + 2 * padding&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      ctx.fillStyle = &amp;quot;#666&amp;quot;;&lt;br /&gt;
      ctx.textBaseline = &amp;quot;top&amp;quot;;&lt;br /&gt;
      ctx.fillText(text, xPosition, yPosition + 1);&lt;br /&gt;
&lt;br /&gt;
      ctx.restore();&lt;br /&gt;
    },&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  Chart.register(customPlugins);&lt;br /&gt;
&lt;br /&gt;
  const ctx = battle.plotDamage.getContext(&amp;quot;2d&amp;quot;);&lt;br /&gt;
  const maxLabelsInTooltip = 10;&lt;br /&gt;
  const nullLabelText = &amp;quot; ...&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  const chart = new Chart(ctx, {&lt;br /&gt;
    type: &amp;quot;scatter&amp;quot;,&lt;br /&gt;
    data: {&lt;br /&gt;
      missPercentage: 0,&lt;br /&gt;
      datasets: [],&lt;br /&gt;
    },&lt;br /&gt;
    options: {&lt;br /&gt;
      locale: currentLanguage,&lt;br /&gt;
      responsive: true,&lt;br /&gt;
      maintainAspectRatio: false,&lt;br /&gt;
      plugins: {&lt;br /&gt;
        legend: {&lt;br /&gt;
          display: true,&lt;br /&gt;
          onHover: function (e) {&lt;br /&gt;
            e.native.target.style.cursor = &amp;quot;pointer&amp;quot;;&lt;br /&gt;
          },&lt;br /&gt;
          onLeave: function (e) {&lt;br /&gt;
            e.native.target.style.cursor = &amp;quot;default&amp;quot;;&lt;br /&gt;
          },&lt;br /&gt;
          onClick: function (e, legendItem, legend) {&lt;br /&gt;
            const currentIndex = legendItem.datasetIndex;&lt;br /&gt;
            const ci = legend.chart;&lt;br /&gt;
            const isCurrentDatasetVisible = ci.isDatasetVisible(currentIndex);&lt;br /&gt;
            const datasets = ci.data.datasets;&lt;br /&gt;
            const isReducePointsChecked = reduceChartPoints.checked;&lt;br /&gt;
            let hideReducePoints = true;&lt;br /&gt;
&lt;br /&gt;
            datasets[currentIndex].hidden = isCurrentDatasetVisible;&lt;br /&gt;
            legendItem.hidden = isCurrentDatasetVisible;&lt;br /&gt;
&lt;br /&gt;
            for (const index in datasets) {&lt;br /&gt;
              if (ci.isDatasetVisible(index) &amp;amp;&amp;amp; datasets[index].canBeReduced) {&lt;br /&gt;
                showElement(reduceChartPointsContainer);&lt;br /&gt;
                hideReducePoints = false;&lt;br /&gt;
                break;&lt;br /&gt;
              }&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            if (hideReducePoints) {&lt;br /&gt;
              hideElement(reduceChartPointsContainer);&lt;br /&gt;
              handleChartAnimations(ci, true);&lt;br /&gt;
            } else {&lt;br /&gt;
              handleChartAnimations(ci, isReducePointsChecked);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            ci.update();&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        title: {&lt;br /&gt;
          display: true,&lt;br /&gt;
          text: defaultText.damageRepartition,&lt;br /&gt;
          font: {&lt;br /&gt;
            size: 20,&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        tooltip: {&lt;br /&gt;
          callbacks: {&lt;br /&gt;
            label: function (context) {&lt;br /&gt;
              if (context.label === null) {&lt;br /&gt;
                return nullLabelText;&lt;br /&gt;
              }&lt;br /&gt;
&lt;br /&gt;
              const xValue = defaultFormat.format(context.parsed.x);&lt;br /&gt;
              const yValue = percentFormat.format(context.parsed.y);&lt;br /&gt;
              const label =&lt;br /&gt;
                &amp;quot; &amp;quot; +&lt;br /&gt;
                context.dataset.label +&lt;br /&gt;
                &amp;quot; : (&amp;quot; +&lt;br /&gt;
                xValue +&lt;br /&gt;
                &amp;quot;, &amp;quot; +&lt;br /&gt;
                yValue +&lt;br /&gt;
                &amp;quot;)&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
              return label;&lt;br /&gt;
            },&lt;br /&gt;
            beforeBody: function (tooltipItems) {&lt;br /&gt;
              if (tooltipItems.length &amp;gt; maxLabelsInTooltip + 1) {&lt;br /&gt;
                tooltipItems.splice(maxLabelsInTooltip + 1);&lt;br /&gt;
                tooltipItems[maxLabelsInTooltip].label = null;&lt;br /&gt;
              }&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          caretPadding: 10,&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
      scales: {&lt;br /&gt;
        x: {&lt;br /&gt;
          type: &amp;quot;linear&amp;quot;,&lt;br /&gt;
          position: &amp;quot;bottom&amp;quot;,&lt;br /&gt;
          title: {&lt;br /&gt;
            display: true,&lt;br /&gt;
            text: defaultText.damage,&lt;br /&gt;
            font: {&lt;br /&gt;
              size: 16,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          ticks: {&lt;br /&gt;
            callback: function (value) {&lt;br /&gt;
              return Number.isInteger(value) ? value : &amp;quot;&amp;quot;;&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        y: {&lt;br /&gt;
          title: {&lt;br /&gt;
            display: true,&lt;br /&gt;
            text: defaultText.percentage,&lt;br /&gt;
            font: {&lt;br /&gt;
              size: 16,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          ticks: {&lt;br /&gt;
            format: {&lt;br /&gt;
              style: &amp;quot;percent&amp;quot;,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
      elements: {&lt;br /&gt;
        point: {&lt;br /&gt;
          borderWidth: 1,&lt;br /&gt;
          radius: 3,&lt;br /&gt;
          hitRadius: 3,&lt;br /&gt;
          hoverRadius: 6,&lt;br /&gt;
          hoverBorderWidth: 2,&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
    },&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  const datasetsStyle = [&lt;br /&gt;
    {&lt;br /&gt;
      name: &amp;quot;normalHit&amp;quot;,&lt;br /&gt;
      canBeReduced: false,&lt;br /&gt;
      label: defaultText.normalHit,&lt;br /&gt;
      backgroundColor: &amp;quot;rgba(75, 192, 192, 0.2)&amp;quot;,&lt;br /&gt;
      borderColor: &amp;quot;rgba(75, 192, 192, 1)&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      name: &amp;quot;piercingHit&amp;quot;,&lt;br /&gt;
      canBeReduced: false,&lt;br /&gt;
      label: defaultText.piercingHit,&lt;br /&gt;
      backgroundColor: &amp;quot;rgba(192, 192, 75, 0.2)&amp;quot;,&lt;br /&gt;
      borderColor: &amp;quot;rgba(192, 192, 75, 1)&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      name: &amp;quot;criticalHit&amp;quot;,&lt;br /&gt;
      canBeReduced: false,&lt;br /&gt;
      label: defaultText.criticalHit,&lt;br /&gt;
      backgroundColor: &amp;quot;rgba(192, 75, 192, 0.2)&amp;quot;,&lt;br /&gt;
      borderColor: &amp;quot;rgba(192, 75, 192, 1)&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      name: &amp;quot;criticalPiercingHit&amp;quot;,&lt;br /&gt;
      canBeReduced: false,&lt;br /&gt;
      label: defaultText.criticalPiercingHit,&lt;br /&gt;
      backgroundColor: &amp;quot;rgba(75, 75, 192, 0.2)&amp;quot;,&lt;br /&gt;
      borderColor: &amp;quot;rgba(75, 75, 192, 1)&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
  ];&lt;br /&gt;
  battle.damageChart = {&lt;br /&gt;
    chart: chart,&lt;br /&gt;
    datasetsStyle: datasetsStyle,&lt;br /&gt;
    maxPoints: 500,&lt;br /&gt;
    reduceChartPointsContainer: reduceChartPointsContainer,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initBonusVariationChart(battle, currentLanguage, defaultText) {&lt;br /&gt;
  const { plotBonusVariation } = battle;&lt;br /&gt;
&lt;br /&gt;
  const ctx = plotBonusVariation.getContext(&amp;quot;2d&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  const chart = new Chart(ctx, {&lt;br /&gt;
    type: &amp;quot;line&amp;quot;,&lt;br /&gt;
    data: {&lt;br /&gt;
      datasets: [&lt;br /&gt;
        {&lt;br /&gt;
          label: defaultText.averageDamage,&lt;br /&gt;
          backgroundColor: &amp;quot;rgba(75, 192, 192, 0.2)&amp;quot;,&lt;br /&gt;
          borderColor: &amp;quot;rgba(75, 192, 192, 1)&amp;quot;,&lt;br /&gt;
          fill: true,&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          label: defaultText.damageAugmentation,&lt;br /&gt;
          backgroundColor: &amp;quot;rgba(192, 192, 75, 0.2)&amp;quot;,&lt;br /&gt;
          borderColor: &amp;quot;rgba(192, 192, 75, 1)&amp;quot;,&lt;br /&gt;
          hidden: true,&lt;br /&gt;
          yTicksFormat: { style: &amp;quot;percent&amp;quot; },&lt;br /&gt;
          fill: true,&lt;br /&gt;
        },&lt;br /&gt;
      ],&lt;br /&gt;
    },&lt;br /&gt;
    options: {&lt;br /&gt;
      locale: currentLanguage,&lt;br /&gt;
      responsive: true,&lt;br /&gt;
      maintainAspectRatio: false,&lt;br /&gt;
      plugins: {&lt;br /&gt;
        legend: {&lt;br /&gt;
          display: true,&lt;br /&gt;
          onHover: function (e) {&lt;br /&gt;
            e.native.target.style.cursor = &amp;quot;pointer&amp;quot;;&lt;br /&gt;
          },&lt;br /&gt;
          onLeave: function (e) {&lt;br /&gt;
            e.native.target.style.cursor = &amp;quot;default&amp;quot;;&lt;br /&gt;
          },&lt;br /&gt;
          onClick: function (e, legendItem, legend) {&lt;br /&gt;
            var currentIndex = legendItem.datasetIndex;&lt;br /&gt;
            var ci = legend.chart;&lt;br /&gt;
            var datasets = ci.data.datasets;&lt;br /&gt;
            var isCurrentDatasetVisible = ci.isDatasetVisible(currentIndex);&lt;br /&gt;
            var yAxis = ci.options.scales.y;&lt;br /&gt;
&lt;br /&gt;
            var otherIndex = currentIndex === 0 ? 1 : 0;&lt;br /&gt;
            var visibleDataset = isCurrentDatasetVisible&lt;br /&gt;
              ? datasets[otherIndex]&lt;br /&gt;
              : datasets[currentIndex];&lt;br /&gt;
&lt;br /&gt;
            datasets[currentIndex].hidden = isCurrentDatasetVisible;&lt;br /&gt;
            datasets[otherIndex].hidden = !isCurrentDatasetVisible;&lt;br /&gt;
&lt;br /&gt;
            yAxis.title.text = visibleDataset.label;&lt;br /&gt;
            yAxis.ticks.format = visibleDataset.yTicksFormat;&lt;br /&gt;
&lt;br /&gt;
            ci.update();&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        title: {&lt;br /&gt;
          display: true,&lt;br /&gt;
          text: defaultText.bonusVariationTitle.split(&amp;quot;[[]]&amp;quot;),&lt;br /&gt;
          font: {&lt;br /&gt;
            size: 18,&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        tooltip: {&lt;br /&gt;
          caretPadding: 10,&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
      scales: {&lt;br /&gt;
        x: {&lt;br /&gt;
          type: &amp;quot;linear&amp;quot;,&lt;br /&gt;
          position: &amp;quot;bottom&amp;quot;,&lt;br /&gt;
          title: {&lt;br /&gt;
            display: true,&lt;br /&gt;
            text: &amp;quot;Bonus&amp;quot;,&lt;br /&gt;
            font: {&lt;br /&gt;
              size: 16,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          ticks: {&lt;br /&gt;
            callback: function (value) {&lt;br /&gt;
              if (Number.isInteger(value)) {&lt;br /&gt;
                return Number(value);&lt;br /&gt;
              }&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        y: {&lt;br /&gt;
          title: {&lt;br /&gt;
            display: true,&lt;br /&gt;
            text: defaultText.averageDamage,&lt;br /&gt;
            font: {&lt;br /&gt;
              size: 16,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
      elements: {&lt;br /&gt;
        point: {&lt;br /&gt;
          borderWidth: 1,&lt;br /&gt;
          radius: 3,&lt;br /&gt;
          hitRadius: 3,&lt;br /&gt;
          hoverRadius: 6,&lt;br /&gt;
          hoverBorderWidth: 2,&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
    },&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  battle.bonusVariationChart = chart;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterAttackTypeSelection(characters, battleChoice, targetValue) {&lt;br /&gt;
  var { nameOrVnum: attackerNameOrVnum, isCharacter: isAttackerPlayer } =&lt;br /&gt;
    parseTypeAndName(targetValue);&lt;br /&gt;
&lt;br /&gt;
  if (isAttackerPlayer) {&lt;br /&gt;
    var attacker = characters.savedCharacters[attackerNameOrVnum];&lt;br /&gt;
    filterAttackTypeSelectionCharacter(attacker, battleChoice.attackType);&lt;br /&gt;
  } else {&lt;br /&gt;
    filterAttackTypeSelectionMonster(battleChoice.attackType);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addBattleData(battle) {&lt;br /&gt;
  var errorElements = document.querySelectorAll(&amp;quot;[data-error]&amp;quot;);&lt;br /&gt;
  var { elements: attackTypeElements, container: attackTypeContainer } =&lt;br /&gt;
    battle.battleChoice.attackType;&lt;br /&gt;
  var attackTypeChilds = attackTypeContainer.children;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; errorElements.length; index++) {&lt;br /&gt;
    var errorElement = errorElements[index];&lt;br /&gt;
    battle.errorInformation[errorElement.dataset.error] = errorElement;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (var index = 1; index &amp;lt; attackTypeChilds.length - 1; index++) {&lt;br /&gt;
    var attackTypeChild = attackTypeChilds[index];&lt;br /&gt;
    var input = attackTypeChild.querySelector(&amp;quot;input&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    attackTypeElements.push({&lt;br /&gt;
      container: attackTypeChild,&lt;br /&gt;
      input: input,&lt;br /&gt;
      inputClass: input.dataset.class,&lt;br /&gt;
      inputValue: input.value,&lt;br /&gt;
    });&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createDamageCalculatorInformation(&lt;br /&gt;
  defaultLang,&lt;br /&gt;
  currentLanguage,&lt;br /&gt;
  defaultText&lt;br /&gt;
) {&lt;br /&gt;
  const characters = {&lt;br /&gt;
    unsavedChanges: false,&lt;br /&gt;
    savedCharacters: {},&lt;br /&gt;
    currentCharacter: null,&lt;br /&gt;
    savedMonsters: getSavedMonsters(),&lt;br /&gt;
    monsterElements: {},&lt;br /&gt;
    characterCreation: document.getElementById(&amp;quot;character-creation&amp;quot;),&lt;br /&gt;
    addNewCharacterButton: document.getElementById(&amp;quot;add-new-character&amp;quot;),&lt;br /&gt;
    dropZone: document.getElementById(&amp;quot;character-drop-zone&amp;quot;),&lt;br /&gt;
    characterInput: document.getElementById(&amp;quot;character-input&amp;quot;),&lt;br /&gt;
    newCharacterTemplate: document.getElementById(&amp;quot;new-character-template&amp;quot;)&lt;br /&gt;
      .children[0],&lt;br /&gt;
    charactersContainer: document.getElementById(&amp;quot;characters-container&amp;quot;),&lt;br /&gt;
    monsterButtonTemplates: document.getElementById(&amp;quot;monster-button-templates&amp;quot;),&lt;br /&gt;
    monsterTemplate: document.getElementById(&amp;quot;new-monster-template&amp;quot;)&lt;br /&gt;
      .children[0],&lt;br /&gt;
    monstersContainer: document.getElementById(&amp;quot;monsters-container&amp;quot;),&lt;br /&gt;
    monsteriFrame: document.getElementById(&amp;quot;monster-iframe&amp;quot;),&lt;br /&gt;
    stoneiFrame: document.getElementById(&amp;quot;stone-iframe&amp;quot;),&lt;br /&gt;
    saveButton: document.getElementById(&amp;quot;save-character&amp;quot;),&lt;br /&gt;
    weaponCategory: document.getElementById(&amp;quot;weapon-category&amp;quot;),&lt;br /&gt;
    weaponDisplay: document.getElementById(&amp;quot;weapon-display&amp;quot;),&lt;br /&gt;
    randomAttackValue: document.getElementById(&amp;quot;random-attack-value&amp;quot;),&lt;br /&gt;
    randomMagicAttackValue: document.getElementById(&lt;br /&gt;
      &amp;quot;random-magic-attack-value&amp;quot;&lt;br /&gt;
    ),&lt;br /&gt;
    toggleSiblings: {},&lt;br /&gt;
    polymorphDisplay: document.getElementById(&amp;quot;polymorph-display&amp;quot;),&lt;br /&gt;
    bonusVariation: {&lt;br /&gt;
      tabButton: document.getElementById(&amp;quot;Variation&amp;quot;),&lt;br /&gt;
      checkbox: document.getElementById(&amp;quot;use-bonus-variation&amp;quot;),&lt;br /&gt;
      input: document.getElementById(&amp;quot;bonus-variation&amp;quot;),&lt;br /&gt;
      inputName: document.getElementById(&amp;quot;bonus-variation-name&amp;quot;),&lt;br /&gt;
      container: document.getElementById(&amp;quot;bonus-variation-creation&amp;quot;),&lt;br /&gt;
      minValue: document.getElementById(&amp;quot;bonus-variation-min-value&amp;quot;),&lt;br /&gt;
      maxValue: document.getElementById(&amp;quot;bonus-variation-max-value&amp;quot;),&lt;br /&gt;
      disabledText: document.getElementById(&amp;quot;bonus-variation-disabled&amp;quot;),&lt;br /&gt;
      selectedText: document.getElementById(&amp;quot;bonus-variation-selected&amp;quot;),&lt;br /&gt;
      displaySpan: document.getElementById(&amp;quot;bonus-variation-display&amp;quot;),&lt;br /&gt;
    },&lt;br /&gt;
    skillElementsToFilter: document.querySelectorAll(&lt;br /&gt;
      &amp;quot;#skill-container [data-class]&amp;quot;&lt;br /&gt;
    ),&lt;br /&gt;
    currentLanguage: currentLanguage,&lt;br /&gt;
    translateMonsters: defaultLang !== currentLanguage,&lt;br /&gt;
    defaultText: defaultText,&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  for (const [pseudo, character] of Object.entries(getSavedCharacters())) {&lt;br /&gt;
    characters.savedCharacters[pseudo] = character;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  document.querySelectorAll(&amp;quot;.toggle-sibling&amp;quot;).forEach(function (element) {&lt;br /&gt;
    const target = element.dataset.target;&lt;br /&gt;
    const sibling = document.getElementById(target);&lt;br /&gt;
    characters.toggleSiblings[element.name] = sibling;&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  const constants = createConstants();&lt;br /&gt;
&lt;br /&gt;
  const battle = {&lt;br /&gt;
    savedFights: getSavedFights(),&lt;br /&gt;
    battleChoice: {&lt;br /&gt;
      resetAttackType: false,&lt;br /&gt;
      form: document.getElementById(&amp;quot;create-battle&amp;quot;),&lt;br /&gt;
      template: document.getElementById(&amp;quot;battle-selection-template&amp;quot;)&lt;br /&gt;
        .children[0],&lt;br /&gt;
      raceToImage: {&lt;br /&gt;
        warrior: &amp;quot;/images/0/0f/Bandeaurougehomme.png&amp;quot;,&lt;br /&gt;
        ninja: &amp;quot;/images/0/0e/Queuedechevalclair.png&amp;quot;,&lt;br /&gt;
        sura: &amp;quot;/images/3/37/Couperespectablerouge.png&amp;quot;,&lt;br /&gt;
        shaman: &amp;quot;/images/6/6a/Coupeeleganteclairfemme.png&amp;quot;,&lt;br /&gt;
        lycan: &amp;quot;/images/4/4e/Protectionfrontalerouge.png&amp;quot;,&lt;br /&gt;
      },&lt;br /&gt;
      categories: [&amp;quot;attacker&amp;quot;, &amp;quot;victim&amp;quot;],&lt;br /&gt;
      translateMonsters: defaultLang !== currentLanguage,&lt;br /&gt;
      attacker: {&lt;br /&gt;
        character: {&lt;br /&gt;
          count: 0,&lt;br /&gt;
          container: document.getElementById(&amp;quot;attacker-selection-characters&amp;quot;),&lt;br /&gt;
          elements: {},&lt;br /&gt;
        },&lt;br /&gt;
        monster: {&lt;br /&gt;
          count: 0,&lt;br /&gt;
          container: document.getElementById(&amp;quot;attacker-selection-monsters&amp;quot;),&lt;br /&gt;
          elements: {},&lt;br /&gt;
        },&lt;br /&gt;
        button: document.getElementById(&amp;quot;attacker-trigger&amp;quot;),&lt;br /&gt;
        defaultButtonContent: document.getElementById(&lt;br /&gt;
          &amp;quot;attacker-default-button-content&amp;quot;&lt;br /&gt;
        ),&lt;br /&gt;
        buttonContent: document.getElementById(&amp;quot;attacker-button-content&amp;quot;),&lt;br /&gt;
        container: document.getElementById(&amp;quot;attacker-selection&amp;quot;),&lt;br /&gt;
        selected: null,&lt;br /&gt;
      },&lt;br /&gt;
      victim: {&lt;br /&gt;
        character: {&lt;br /&gt;
          count: 0,&lt;br /&gt;
          container: document.getElementById(&amp;quot;victim-selection-characters&amp;quot;),&lt;br /&gt;
          elements: {},&lt;br /&gt;
        },&lt;br /&gt;
        monster: {&lt;br /&gt;
          count: 0,&lt;br /&gt;
          container: document.getElementById(&amp;quot;victim-selection-monsters&amp;quot;),&lt;br /&gt;
          elements: {},&lt;br /&gt;
        },&lt;br /&gt;
        stone: {&lt;br /&gt;
          count: 0,&lt;br /&gt;
          container: document.getElementById(&amp;quot;victim-selection-stones&amp;quot;),&lt;br /&gt;
          elements: {},&lt;br /&gt;
        },&lt;br /&gt;
        button: document.getElementById(&amp;quot;victim-trigger&amp;quot;),&lt;br /&gt;
        defaultButtonContent: document.getElementById(&lt;br /&gt;
          &amp;quot;victim-default-button-content&amp;quot;&lt;br /&gt;
        ),&lt;br /&gt;
        buttonContent: document.getElementById(&amp;quot;victim-button-content&amp;quot;),&lt;br /&gt;
        selected: null,&lt;br /&gt;
      },&lt;br /&gt;
      attackType: {&lt;br /&gt;
        container: document.getElementById(&amp;quot;attack-type-selection&amp;quot;),&lt;br /&gt;
        elements: [],&lt;br /&gt;
        defaultInput: document.getElementById(&amp;quot;physical-attack&amp;quot;),&lt;br /&gt;
        selectedText: &amp;quot;&amp;quot;,&lt;br /&gt;
      },&lt;br /&gt;
    },&lt;br /&gt;
    damageWeightedByType: {},&lt;br /&gt;
    scatterDataByType: {},&lt;br /&gt;
    damageByBonus: [],&lt;br /&gt;
    tableResultFight: document.getElementById(&amp;quot;result-table-fight&amp;quot;),&lt;br /&gt;
    tableResultHistory: document.getElementById(&amp;quot;result-table-history&amp;quot;),&lt;br /&gt;
    deleteFightTemplate: document.getElementById(&amp;quot;delete-fight-template&amp;quot;)&lt;br /&gt;
      .children[0],&lt;br /&gt;
    errorInformation: {},&lt;br /&gt;
    fightResultTitle: document.getElementById(&amp;quot;fight-result-title&amp;quot;),&lt;br /&gt;
    fightResultContainer: document.getElementById(&amp;quot;fight-result-container&amp;quot;),&lt;br /&gt;
    downLoadRawData: document.getElementById(&amp;quot;download-raw-data&amp;quot;),&lt;br /&gt;
    downLoadRawDataVariation: document.getElementById(&lt;br /&gt;
      &amp;quot;download-raw-data-variation&amp;quot;&lt;br /&gt;
    ),&lt;br /&gt;
    bonusVariationResultContainer: document.getElementById(&lt;br /&gt;
      &amp;quot;bonus-variation-result-container&amp;quot;&lt;br /&gt;
    ),&lt;br /&gt;
    reduceChartPointsContainer: document.getElementById(&lt;br /&gt;
      &amp;quot;reduce-chart-points-container&amp;quot;&lt;br /&gt;
    ),&lt;br /&gt;
    reduceChartPoints: document.getElementById(&amp;quot;reduce-chart-points&amp;quot;),&lt;br /&gt;
    plotDamage: document.getElementById(&amp;quot;plot-damage&amp;quot;),&lt;br /&gt;
    plotBonusVariation: document.getElementById(&amp;quot;plot-bonus-variation&amp;quot;),&lt;br /&gt;
    chartDescriptionContainer: document.getElementById(&lt;br /&gt;
      &amp;quot;chart-description-container&amp;quot;&lt;br /&gt;
    ),&lt;br /&gt;
    damageInfoContainer: document.getElementById(&amp;quot;damage-info-container&amp;quot;),&lt;br /&gt;
    uniqueDamageCounters: document.querySelectorAll(&amp;quot;.unique-damage-counter&amp;quot;),&lt;br /&gt;
    possibleDamageCounter: document.getElementById(&amp;quot;possible-damage-counter&amp;quot;),&lt;br /&gt;
    damageTime: document.getElementById(&amp;quot;damage-time&amp;quot;),&lt;br /&gt;
    displayTime: document.getElementById(&amp;quot;display-time&amp;quot;),&lt;br /&gt;
    simulationCounter: document.getElementById(&amp;quot;simulation-counter&amp;quot;),&lt;br /&gt;
    simulationTime: document.getElementById(&amp;quot;simulation-time&amp;quot;),&lt;br /&gt;
    numberFormats: {&lt;br /&gt;
      default: new Intl.NumberFormat(currentLanguage, {&lt;br /&gt;
        minimumFractionDigits: 0,&lt;br /&gt;
        maximumFractionDigits: 1,&lt;br /&gt;
      }),&lt;br /&gt;
      percent: new Intl.NumberFormat(currentLanguage, {&lt;br /&gt;
        style: &amp;quot;percent&amp;quot;,&lt;br /&gt;
        maximumFractionDigits: 3,&lt;br /&gt;
      }),&lt;br /&gt;
      second: new Intl.NumberFormat(currentLanguage, {&lt;br /&gt;
        style: &amp;quot;unit&amp;quot;,&lt;br /&gt;
        unit: &amp;quot;second&amp;quot;,&lt;br /&gt;
        unitDisplay: &amp;quot;long&amp;quot;,&lt;br /&gt;
        maximumFractionDigits: 3,&lt;br /&gt;
      }),&lt;br /&gt;
    },&lt;br /&gt;
    mapping: createMapping(),&lt;br /&gt;
    constants: constants,&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  addBattleData(battle);&lt;br /&gt;
  initResultTableHistory(battle);&lt;br /&gt;
  initDamageChart(battle, currentLanguage, defaultText);&lt;br /&gt;
  initBonusVariationChart(battle, currentLanguage, defaultText);&lt;br /&gt;
  reduceChartPointsListener(battle);&lt;br /&gt;
  downloadRawDataListener(battle);&lt;br /&gt;
&lt;br /&gt;
  return [characters, battle];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function parseText(input) {&lt;br /&gt;
  const regex = /\[\[(.*?)\]\]|([^\[]+)/g;&lt;br /&gt;
  const result = [];&lt;br /&gt;
&lt;br /&gt;
  input.replace(regex, (_, matchA, matchText) =&amp;gt; {&lt;br /&gt;
    if (matchA !== undefined) {&lt;br /&gt;
      result.push({&lt;br /&gt;
        text: matchA,&lt;br /&gt;
        category: matchA === &amp;quot;&amp;quot; ? &amp;quot;NOTRANSLATE&amp;quot; : &amp;quot;A&amp;quot;,&lt;br /&gt;
      });&lt;br /&gt;
    } else if (matchText) {&lt;br /&gt;
      result.push({ text: matchText, category: &amp;quot;#text&amp;quot; });&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  return result;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function translateText(general) {&lt;br /&gt;
  const nodesToTranslate = [&amp;quot;A&amp;quot;, &amp;quot;I&amp;quot;, &amp;quot;B&amp;quot;];&lt;br /&gt;
&lt;br /&gt;
  for (const element of document.querySelectorAll(&amp;quot;[data-t]&amp;quot;)) {&lt;br /&gt;
    const translateText = general[element.dataset.t];&lt;br /&gt;
&lt;br /&gt;
    if (!translateText) continue;&lt;br /&gt;
&lt;br /&gt;
    const childNodes = element.childNodes;&lt;br /&gt;
    const numChildren = childNodes.length;&lt;br /&gt;
&lt;br /&gt;
    if (numChildren === 1) {&lt;br /&gt;
      childNodes[0].textContent = translateText;&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    const parsedText = parseText(translateText);&lt;br /&gt;
    const numParsed = parsedText.length;&lt;br /&gt;
&lt;br /&gt;
    let childIndex = 0;&lt;br /&gt;
    let textIndex = 0;&lt;br /&gt;
&lt;br /&gt;
    while (childIndex &amp;lt; numChildren) {&lt;br /&gt;
      const child = childNodes[childIndex];&lt;br /&gt;
&lt;br /&gt;
      if (textIndex === numParsed) {&lt;br /&gt;
        console.warn(&amp;quot;Bad translation for element&amp;quot;, element);&lt;br /&gt;
        break;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      const parsed = parsedText[textIndex];&lt;br /&gt;
&lt;br /&gt;
      let childName = child.nodeName;&lt;br /&gt;
      const isNodeToTranslate = nodesToTranslate.includes(childName);&lt;br /&gt;
&lt;br /&gt;
      if (&lt;br /&gt;
        (childName === &amp;quot;A&amp;quot; &amp;amp;&amp;amp; child.firstChild?.nodeName === &amp;quot;IMG&amp;quot;) ||&lt;br /&gt;
        !(isNodeToTranslate || childName === &amp;quot;#text&amp;quot;) ||&lt;br /&gt;
        child.dataset?.notranslate&lt;br /&gt;
      ) {&lt;br /&gt;
        childName = &amp;quot;NOTRANSLATE&amp;quot;;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (&lt;br /&gt;
        childName === parsed.category ||&lt;br /&gt;
        (parsed.category === &amp;quot;A&amp;quot; &amp;amp;&amp;amp; isNodeToTranslate)&lt;br /&gt;
      ) {&lt;br /&gt;
        if (childName !== &amp;quot;NOTRANSLATE&amp;quot;) {&lt;br /&gt;
          child.textContent = parsed.text;&lt;br /&gt;
        }&lt;br /&gt;
        childIndex++;&lt;br /&gt;
        textIndex++;&lt;br /&gt;
      } else if (childName === &amp;quot;NOTRANSLATE&amp;quot;) {&lt;br /&gt;
        childIndex++;&lt;br /&gt;
      } else if (isNodeToTranslate) {&lt;br /&gt;
        element.insertBefore(document.createTextNode(parsed.text), child);&lt;br /&gt;
        textIndex++;&lt;br /&gt;
      } else {&lt;br /&gt;
        child.textContent = &amp;quot;&amp;quot;;&lt;br /&gt;
        childIndex++;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (textIndex &amp;lt; parsedText.length) {&lt;br /&gt;
      const textNode = document.createTextNode(parsedText[textIndex].text);&lt;br /&gt;
      element.appendChild(textNode);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function translateWeapons(weapons) {&lt;br /&gt;
  const characterCreation = document.getElementById(&amp;quot;character-creation&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  for (const weaponInput of characterCreation.elements[&amp;quot;weapon&amp;quot;]) {&lt;br /&gt;
    const weaponTranslation = weapons[weaponInput.value];&lt;br /&gt;
&lt;br /&gt;
    if (weaponTranslation) {&lt;br /&gt;
      weaponInput.parentElement.lastElementChild.textContent =&lt;br /&gt;
        weaponTranslation;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleSpecialIndexes(generalTranslations, specialIndexes) {&lt;br /&gt;
  const specialTranslations = {};&lt;br /&gt;
&lt;br /&gt;
  translation.special = specialTranslations;&lt;br /&gt;
&lt;br /&gt;
  for (const [generalIndex, specialKey] of Object.entries(specialIndexes)) {&lt;br /&gt;
    const translatedValue = generalTranslations[generalIndex];&lt;br /&gt;
&lt;br /&gt;
    if (translatedValue) {&lt;br /&gt;
      specialTranslations[specialKey] = translatedValue;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  translation.mapping = {&lt;br /&gt;
    &amp;quot;Demi-humain&amp;quot;: specialTranslations.halfHuman,&lt;br /&gt;
    Mal: specialTranslations.devil,&lt;br /&gt;
    Désert: specialTranslations.desert,&lt;br /&gt;
    Animal: specialTranslations.animal,&lt;br /&gt;
    Orc: specialTranslations.orc,&lt;br /&gt;
    Mystique: specialTranslations.mystic,&lt;br /&gt;
    &amp;quot;Mort-vivant&amp;quot;: specialTranslations.undead,&lt;br /&gt;
    Insecte: specialTranslations.insect,&lt;br /&gt;
    Zodiaque: specialTranslations.zodiac,&lt;br /&gt;
    &amp;quot;Aucun type&amp;quot;: specialTranslations.noType,&lt;br /&gt;
    Mêlée: specialTranslations.melee,&lt;br /&gt;
    Flèche: specialTranslations.arrow,&lt;br /&gt;
    Magique: specialTranslations.magic,&lt;br /&gt;
    DC: specialTranslations.skill,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function translateTitle() {&lt;br /&gt;
  const translatedTitle = translation.special.pageTitle;&lt;br /&gt;
&lt;br /&gt;
  if (translatedTitle) {&lt;br /&gt;
    document.querySelector(&amp;quot;h1&amp;quot;).textContent = translatedTitle;&lt;br /&gt;
    document.querySelector(&amp;quot;ul.subpage&amp;quot;).lastElementChild.textContent =&lt;br /&gt;
      translatedTitle;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function translateSummary(attempts = 5) {&lt;br /&gt;
  const tocContainer = document.getElementById(&amp;quot;toc&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (!tocContainer) {&lt;br /&gt;
    if (attempts &amp;gt; 0) {&lt;br /&gt;
      console.log(`Translating summary... Attempts left: ${attempts}`);&lt;br /&gt;
      setTimeout(() =&amp;gt; translateSummary(attempts - 1), 1000);&lt;br /&gt;
    }&lt;br /&gt;
    return;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  const { toc, hide } = translation.special;&lt;br /&gt;
&lt;br /&gt;
  const heading = tocContainer.querySelector(&amp;quot;h2&amp;quot;);&lt;br /&gt;
  const toggleLink = tocContainer.querySelector(&amp;quot;a.togglelink&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (heading) heading.textContent = toc;&lt;br /&gt;
  if (toggleLink) toggleLink.textContent = hide;&lt;br /&gt;
&lt;br /&gt;
  for (const link of tocContainer.querySelectorAll(&amp;quot;ul a&amp;quot;)) {&lt;br /&gt;
    const hash = link.hash.substring(1);&lt;br /&gt;
    const title = document.getElementById(hash);&lt;br /&gt;
&lt;br /&gt;
    if (title) {&lt;br /&gt;
      const toctext = link.querySelector(&amp;quot;span.toctext&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
      if (toctext?.firstElementChild) {&lt;br /&gt;
        toctext.firstElementChild.textContent = title.textContent;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function translateDefaultText(defaultText) {&lt;br /&gt;
  const specialTranslations = translation.special;&lt;br /&gt;
&lt;br /&gt;
  for (const key of Object.keys(defaultText)) {&lt;br /&gt;
    if (specialTranslations.hasOwnProperty(key)) {&lt;br /&gt;
      defaultText[key] = specialTranslations[key];&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function translatePage(defaultText, currentLanguage) {&lt;br /&gt;
  const mwContent = document.querySelector(&amp;quot;.mw-content-ltr&amp;quot;);&lt;br /&gt;
  const { general, weapons } = translation;&lt;br /&gt;
  const specialIndexes = {&lt;br /&gt;
    471: &amp;quot;placeholder&amp;quot;,&lt;br /&gt;
    473: &amp;quot;boss&amp;quot;,&lt;br /&gt;
    474: &amp;quot;pageTitle&amp;quot;,&lt;br /&gt;
    475: &amp;quot;toc&amp;quot;,&lt;br /&gt;
    476: &amp;quot;hide&amp;quot;,&lt;br /&gt;
    502: &amp;quot;unsavedWarning&amp;quot;,&lt;br /&gt;
    503: &amp;quot;deleteWarning&amp;quot;,&lt;br /&gt;
    504: &amp;quot;pseudo&amp;quot;,&lt;br /&gt;
    481: &amp;quot;damage&amp;quot;,&lt;br /&gt;
    505: &amp;quot;percentage&amp;quot;,&lt;br /&gt;
    506: &amp;quot;miss&amp;quot;,&lt;br /&gt;
    507: &amp;quot;normalHit&amp;quot;,&lt;br /&gt;
    508: &amp;quot;criticalHit&amp;quot;,&lt;br /&gt;
    509: &amp;quot;piercingHit&amp;quot;,&lt;br /&gt;
    510: &amp;quot;criticalPiercingHit&amp;quot;,&lt;br /&gt;
    511: &amp;quot;damageRepartition&amp;quot;,&lt;br /&gt;
    512: &amp;quot;averageDamage&amp;quot;,&lt;br /&gt;
    513: &amp;quot;damageAugmentation&amp;quot;,&lt;br /&gt;
    514: &amp;quot;bonusVariationTitle&amp;quot;,&lt;br /&gt;
    489: &amp;quot;halfHuman&amp;quot;,&lt;br /&gt;
    490: &amp;quot;devil&amp;quot;,&lt;br /&gt;
    491: &amp;quot;desert&amp;quot;,&lt;br /&gt;
    492: &amp;quot;animal&amp;quot;,&lt;br /&gt;
    493: &amp;quot;orc&amp;quot;,&lt;br /&gt;
    494: &amp;quot;mystic&amp;quot;,&lt;br /&gt;
    495: &amp;quot;undead&amp;quot;,&lt;br /&gt;
    496: &amp;quot;insect&amp;quot;,&lt;br /&gt;
    497: &amp;quot;zodiac&amp;quot;,&lt;br /&gt;
    515: &amp;quot;noType&amp;quot;,&lt;br /&gt;
    498: &amp;quot;melee&amp;quot;,&lt;br /&gt;
    499: &amp;quot;arrow&amp;quot;,&lt;br /&gt;
    500: &amp;quot;magic&amp;quot;,&lt;br /&gt;
    516: &amp;quot;skill&amp;quot;,&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  translateText(general);&lt;br /&gt;
  translateWeapons(weapons);&lt;br /&gt;
  handleSpecialIndexes(general, specialIndexes);&lt;br /&gt;
  translateTitle();&lt;br /&gt;
  translateSummary();&lt;br /&gt;
  translateDefaultText(defaultText);&lt;br /&gt;
&lt;br /&gt;
  if (mwContent) {&lt;br /&gt;
    mwContent.setAttribute(&amp;quot;lang&amp;quot;, currentLanguage);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getDefaultText() {&lt;br /&gt;
  return {&lt;br /&gt;
    unsavedWarning:&lt;br /&gt;
      &amp;quot;Voulez-vous continuer ? Les dernières modifications ne seront pas sauvegardées.&amp;quot;,&lt;br /&gt;
    deleteWarning:&lt;br /&gt;
      &amp;quot;Voulez-vous vraiment supprimer définitivement le personnage [[]] ?&amp;quot;,&lt;br /&gt;
    pseudo: &amp;quot;Pseudo&amp;quot;,&lt;br /&gt;
    damage: &amp;quot;Dégâts&amp;quot;,&lt;br /&gt;
    percentage: &amp;quot;Pourcentage&amp;quot;,&lt;br /&gt;
    miss: &amp;quot;Miss&amp;quot;,&lt;br /&gt;
    normalHit: &amp;quot;Coup classique&amp;quot;,&lt;br /&gt;
    criticalHit: &amp;quot;Coup critique&amp;quot;,&lt;br /&gt;
    piercingHit: &amp;quot;Coup perçant&amp;quot;,&lt;br /&gt;
    criticalPiercingHit: &amp;quot;Coup critique perçant&amp;quot;,&lt;br /&gt;
    damageRepartition: &amp;quot;Distribution des dégâts&amp;quot;,&lt;br /&gt;
    averageDamage: &amp;quot;Dégâts moyens&amp;quot;,&lt;br /&gt;
    damageAugmentation: &amp;quot;Augmentation des dégâts&amp;quot;,&lt;br /&gt;
    bonusVariationTitle:&lt;br /&gt;
      &amp;quot;Évolution des dégâts moyens[[]]par rapport à la valeur d'un bonus&amp;quot;,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setLanguage(radios, lang, url, reload = false) {&lt;br /&gt;
  url.searchParams.set(&amp;quot;lang&amp;quot;, lang);&lt;br /&gt;
  updateLastLang(lang);&lt;br /&gt;
&lt;br /&gt;
  if (reload) {&lt;br /&gt;
    window.location.href = url.toString();&lt;br /&gt;
  } else {&lt;br /&gt;
    radios.value = lang;&lt;br /&gt;
    history.replaceState(null, &amp;quot;&amp;quot;, url);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getCurrentLanguage(defaultLang) {&lt;br /&gt;
  const url = new URL(window.location.href);&lt;br /&gt;
  const URLlang = url.searchParams.get(&amp;quot;lang&amp;quot;);&lt;br /&gt;
  const lastLang = getLastLang();&lt;br /&gt;
  const browserLang = navigator.language.split(&amp;quot;-&amp;quot;)[0];&lt;br /&gt;
  const languageSelection = document.getElementById(&amp;quot;language-selection&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (!languageSelection) {&lt;br /&gt;
    return defaultLang;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  const radios = languageSelection.elements[&amp;quot;country&amp;quot;];&lt;br /&gt;
&lt;br /&gt;
  if (!radios) {&lt;br /&gt;
    return defaultLang;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  languageSelection.addEventListener(&amp;quot;change&amp;quot;, changeLanguage);&lt;br /&gt;
&lt;br /&gt;
  function changeLanguage(event) {&lt;br /&gt;
    const newLang = event.target.value;&lt;br /&gt;
    const newUrl = new URL(window.location.href);&lt;br /&gt;
    setLanguage(radios, newLang, newUrl, true);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  const allowedLanguages = Array.from(radios).map((input) =&amp;gt; input.value);&lt;br /&gt;
&lt;br /&gt;
  for (const lang of [URLlang, lastLang, browserLang]) {&lt;br /&gt;
    if (allowedLanguages.includes(lang)) {&lt;br /&gt;
      setLanguage(radios, lang, url);&lt;br /&gt;
      return lang;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return defaultLang;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadStyle(src) {&lt;br /&gt;
  var link = document.createElement(&amp;quot;link&amp;quot;);&lt;br /&gt;
  link.href = src;&lt;br /&gt;
  link.rel = &amp;quot;stylesheet&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  document.head.appendChild(link);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
async function addScript(src) {&lt;br /&gt;
  return new Promise((resolve, reject) =&amp;gt; {&lt;br /&gt;
    const script = document.createElement(&amp;quot;script&amp;quot;);&lt;br /&gt;
    script.src = src;&lt;br /&gt;
    script.async = true;&lt;br /&gt;
&lt;br /&gt;
    script.onload = () =&amp;gt; resolve();&lt;br /&gt;
    script.onerror = () =&amp;gt; reject(new Error(`Failed to load script: ${src}`));&lt;br /&gt;
&lt;br /&gt;
    document.head.appendChild(script);&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
(async function () {&lt;br /&gt;
  const basePath = &amp;quot;/index.php?title=Utilisateur:Ankhseram/&amp;quot;;&lt;br /&gt;
  const dataScript = `${basePath}WeaponsAndMonsters.js&amp;amp;action=raw&amp;amp;ctype=text/javascript`;&lt;br /&gt;
  const simulatorStyle = `${basePath}SimulatorStyle.css&amp;amp;action=raw&amp;amp;ctype=text/css`;&lt;br /&gt;
  const chartLibrary = &amp;quot;https://cdn.jsdelivr.net/npm/chart.js&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  const defaultLang = &amp;quot;fr&amp;quot;;&lt;br /&gt;
  const defaultText = getDefaultText();&lt;br /&gt;
  const currentLanguage = getCurrentLanguage(defaultLang);&lt;br /&gt;
&lt;br /&gt;
  loadStyle(simulatorStyle);&lt;br /&gt;
&lt;br /&gt;
  let translationScript;&lt;br /&gt;
&lt;br /&gt;
  if (currentLanguage !== defaultLang) {&lt;br /&gt;
    translationScript = `${basePath}Calculator/${currentLanguage}.js&amp;amp;action=raw&amp;amp;ctype=text/javascript`;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  const scriptsToLoad = [addScript(chartLibrary), addScript(dataScript)];&lt;br /&gt;
&lt;br /&gt;
  if (translationScript) {&lt;br /&gt;
    scriptsToLoad.push(addScript(translationScript));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  await Promise.all(scriptsToLoad);&lt;br /&gt;
&lt;br /&gt;
  if (translationScript) {&lt;br /&gt;
    translatePage(defaultText, currentLanguage);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  const [characters, battle] = createDamageCalculatorInformation(&lt;br /&gt;
    defaultLang,&lt;br /&gt;
    currentLanguage,&lt;br /&gt;
    defaultText&lt;br /&gt;
  );&lt;br /&gt;
  characterManagement(characters, battle);&lt;br /&gt;
  monsterManagement(characters, battle);&lt;br /&gt;
  updateBattleChoice(characters, battle.battleChoice);&lt;br /&gt;
  createBattle(characters, battle);&lt;br /&gt;
})();&lt;/div&gt;</summary>
		<author><name>Dexter</name></author>
		
	</entry>
	<entry>
		<id>https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Script/Calculator.js&amp;diff=108152</id>
		<title>MediaWiki:Script/Calculator.js</title>
		<link rel="alternate" type="text/html" href="https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Script/Calculator.js&amp;diff=108152"/>
		<updated>2025-10-24T00:21:05Z</updated>

		<summary type="html">&lt;p&gt;Dexter : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;function removeAccent(str) {&lt;br /&gt;
  return str.normalize(&amp;quot;NFD&amp;quot;).replace(/[\u0300-\u036f]/g, &amp;quot;&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function pseudoFormat(str) {&lt;br /&gt;
  return removeAccent(str).replace(/[^A-Za-z0-9 \(\)\+_-]+/g, &amp;quot;&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isValueInArray(value, array) {&lt;br /&gt;
  return array.indexOf(value) !== -1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function splitFirst(value, delimiter) {&lt;br /&gt;
  var parts = value.split(delimiter);&lt;br /&gt;
  var first = parts[0];&lt;br /&gt;
  var rest = parts.slice(1).join(delimiter);&lt;br /&gt;
  return [first, rest];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function copyObject(object) {&lt;br /&gt;
  var copy = {};&lt;br /&gt;
  for (var key in object) {&lt;br /&gt;
    copy[key] = object[key];&lt;br /&gt;
  }&lt;br /&gt;
  return copy;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function compareNumbers(a, b) {&lt;br /&gt;
  return b - a;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isChecked(attribute) {&lt;br /&gt;
  return attribute === &amp;quot;on&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function floorMultiplication(firstFactor, secondFactor) {&lt;br /&gt;
  return Math.floor((firstFactor * secondFactor).toFixed(8));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function truncateNumber(number, precision) {&lt;br /&gt;
  return Math.floor(number * 10 ** precision) / 10 ** precision;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function newChangeEvent() {&lt;br /&gt;
  return new Event(&amp;quot;change&amp;quot;, { bubbles: true });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function openTargetTab(target) {&lt;br /&gt;
  var tabberContainer = target.closest(&amp;quot;.tabber-container&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (!tabberContainer) {&lt;br /&gt;
    return;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var [buttonsContainer, tabsContainer] = tabberContainer.children;&lt;br /&gt;
  var buttons = buttonsContainer.children;&lt;br /&gt;
  var tabs = tabsContainer.children;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; tabs.length; index++) {&lt;br /&gt;
    var tab = tabs[index];&lt;br /&gt;
    if (tab.contains(target) &amp;amp;&amp;amp; !tab.checkVisibility()) {&lt;br /&gt;
      buttons[index].click();&lt;br /&gt;
      break;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function openTargetCollapsible(target) {&lt;br /&gt;
  var collapsible = target.closest(&amp;quot;.improved-collapsible&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (!collapsible) {&lt;br /&gt;
    return;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var span = collapsible.firstElementChild;&lt;br /&gt;
&lt;br /&gt;
  if (!span.classList.contains(&amp;quot;mw-collapsible-toggle-expanded&amp;quot;)) {&lt;br /&gt;
    span.click();&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function editTableResultRow(row, valuesToDisplay, numberFormat) {&lt;br /&gt;
  row.innerHTML = &amp;quot;&amp;quot;;&lt;br /&gt;
  for (var index = 0; index &amp;lt; valuesToDisplay.length; index++) {&lt;br /&gt;
    var cell = row.insertCell();&lt;br /&gt;
    var textContent;&lt;br /&gt;
&lt;br /&gt;
    if (index &amp;gt;= 3) {&lt;br /&gt;
      textContent = numberFormat.format(valuesToDisplay[index]);&lt;br /&gt;
    } else {&lt;br /&gt;
      textContent = valuesToDisplay[index];&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    cell.textContent = textContent;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return row;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addRowToTableResultHistory(&lt;br /&gt;
  tableResultHistory,&lt;br /&gt;
  valuesToDisplay,&lt;br /&gt;
  deleteFightTemplate,&lt;br /&gt;
  numberFormat&lt;br /&gt;
) {&lt;br /&gt;
  var row = tableResultHistory.insertRow();&lt;br /&gt;
  editTableResultRow(row, valuesToDisplay, numberFormat);&lt;br /&gt;
  var cell = row.insertCell();&lt;br /&gt;
  cell.appendChild(deleteFightTemplate.cloneNode(true));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function processSavedDamage(savedDamage, damageWeightedByType, battleValues) {&lt;br /&gt;
  const { damageTypeWeights, attackTypeMapping } = battleValues;&lt;br /&gt;
&lt;br /&gt;
  for (const key in savedDamage) {&lt;br /&gt;
    const [weight, damageByType] = savedDamage[key];&lt;br /&gt;
&lt;br /&gt;
    for (let index = 0; index &amp;lt; 4; index++) {&lt;br /&gt;
      const damageWeighted = damageWeightedByType[attackTypeMapping[index]];&lt;br /&gt;
      const damageByTypeIndex = damageByType[index];&lt;br /&gt;
&lt;br /&gt;
      if (damageByTypeIndex.length === 0) continue;&lt;br /&gt;
&lt;br /&gt;
      const currentWeight =&lt;br /&gt;
        (weight * damageTypeWeights[index]) / damageByTypeIndex.length;&lt;br /&gt;
&lt;br /&gt;
      for (const damage of damageByTypeIndex) {&lt;br /&gt;
        damageWeighted[damage] = (damageWeighted[damage] || 0) + currentWeight;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcMeanDamage(damageWeightedByType, totalCardinal) {&lt;br /&gt;
  var sumDamage = 0;&lt;br /&gt;
&lt;br /&gt;
  for (var damageTypeName in damageWeightedByType) {&lt;br /&gt;
    if (damageTypeName === &amp;quot;miss&amp;quot;) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var damageWeighted = damageWeightedByType[damageTypeName];&lt;br /&gt;
&lt;br /&gt;
    for (var damage in damageWeighted) {&lt;br /&gt;
      sumDamage += damage * damageWeighted[damage];&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return sumDamage / totalCardinal;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function prepareDamageData(damageWeightedByType, attackValues) {&lt;br /&gt;
  const totalCardinal = attackValues.totalCardinal;&lt;br /&gt;
  const scatterDataByType = {};&lt;br /&gt;
  const criticalAttackRange = attackValues.criticalAttackRange;&lt;br /&gt;
&lt;br /&gt;
  let minDamage = Infinity;&lt;br /&gt;
  let maxDamage = 0;&lt;br /&gt;
  let sumDamage = 0;&lt;br /&gt;
&lt;br /&gt;
  let possibleDamageCount = 0;&lt;br /&gt;
  let possibleDamageCountTemp = 0;&lt;br /&gt;
  let uniqueDamageCount = 0;&lt;br /&gt;
&lt;br /&gt;
  for (const damageTypeName in damageWeightedByType) {&lt;br /&gt;
    if (damageTypeName === &amp;quot;miss&amp;quot;) {&lt;br /&gt;
      scatterDataByType.miss = damageWeightedByType.miss;&lt;br /&gt;
      possibleDamageCount++;&lt;br /&gt;
      uniqueDamageCount++;&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
    const damageWeighted = damageWeightedByType[damageTypeName];&lt;br /&gt;
    const scatterData = [];&lt;br /&gt;
&lt;br /&gt;
    scatterDataByType[damageTypeName] = scatterData;&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      (damageTypeName === &amp;quot;criticalHit&amp;quot; ||&lt;br /&gt;
        damageTypeName === &amp;quot;criticalPiercingHit&amp;quot;) &amp;amp;&amp;amp;&lt;br /&gt;
      criticalAttackRange&lt;br /&gt;
    ) {&lt;br /&gt;
      possibleDamageCountTemp =&lt;br /&gt;
        attackValues.possibleDamageCount * criticalAttackRange.length;&lt;br /&gt;
    } else {&lt;br /&gt;
      possibleDamageCountTemp = attackValues.possibleDamageCount;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    for (let damage in damageWeighted) {&lt;br /&gt;
      damage = +damage;&lt;br /&gt;
&lt;br /&gt;
      if (damage &amp;lt; minDamage) {&lt;br /&gt;
        minDamage = damage;&lt;br /&gt;
      }&lt;br /&gt;
      if (damage &amp;gt; maxDamage) {&lt;br /&gt;
        maxDamage = damage;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      const weight = damageWeighted[damage];&lt;br /&gt;
      const probability = weight / totalCardinal;&lt;br /&gt;
&lt;br /&gt;
      sumDamage += damage * weight;&lt;br /&gt;
      damageWeighted[damage] = probability;&lt;br /&gt;
      scatterData.push({ x: damage, y: probability });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    const scatterDataLength = scatterData.length;&lt;br /&gt;
&lt;br /&gt;
    if (!scatterDataLength) {&lt;br /&gt;
      delete scatterDataByType[damageTypeName];&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    possibleDamageCount += possibleDamageCountTemp;&lt;br /&gt;
    uniqueDamageCount += scatterDataLength;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (minDamage === Infinity) {&lt;br /&gt;
    minDamage = 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  attackValues.possibleDamageCount = possibleDamageCount;&lt;br /&gt;
&lt;br /&gt;
  return [&lt;br /&gt;
    sumDamage / totalCardinal,&lt;br /&gt;
    minDamage,&lt;br /&gt;
    maxDamage,&lt;br /&gt;
    scatterDataByType,&lt;br /&gt;
    uniqueDamageCount,&lt;br /&gt;
  ];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function aggregateDamage(scatterData, maxPoints) {&lt;br /&gt;
  const dataLength = scatterData.length;&lt;br /&gt;
  const groupLength = Math.ceil(dataLength / maxPoints);&lt;br /&gt;
  const aggregateScatterData = [];&lt;br /&gt;
  const groupCount = Math.ceil(dataLength / groupLength);&lt;br /&gt;
&lt;br /&gt;
  for (let groupIndex = 0; groupIndex &amp;lt; groupCount; groupIndex++) {&lt;br /&gt;
    const startIndex = groupIndex * groupLength;&lt;br /&gt;
    const endIndex = Math.min(startIndex + groupLength, dataLength);&lt;br /&gt;
&lt;br /&gt;
    let aggregateDamage = 0;&lt;br /&gt;
    let aggregateProbability = 0;&lt;br /&gt;
&lt;br /&gt;
    for (let index = startIndex; index &amp;lt; endIndex; index++) {&lt;br /&gt;
      const { x: damage, y: probability } = scatterData[index];&lt;br /&gt;
      aggregateDamage += damage * probability;&lt;br /&gt;
      aggregateProbability += probability;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    aggregateScatterData.push({&lt;br /&gt;
      x: aggregateDamage / aggregateProbability,&lt;br /&gt;
      y: aggregateProbability,&lt;br /&gt;
    });&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return aggregateScatterData;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addToDamageChart(battle, scatterDataByType) {&lt;br /&gt;
  const { chart, datasetsStyle, maxPoints, reduceChartPointsContainer } =&lt;br /&gt;
    battle.damageChart;&lt;br /&gt;
  const isReducePointsChecked = battle.reduceChartPoints.checked;&lt;br /&gt;
  const datasets = chart.data.datasets;&lt;br /&gt;
&lt;br /&gt;
  let isFirstDataset = true;&lt;br /&gt;
&lt;br /&gt;
  datasets.length = 0;&lt;br /&gt;
&lt;br /&gt;
  for (let index = 0; index &amp;lt; datasetsStyle.length; index++) {&lt;br /&gt;
    const dataset = copyObject(datasetsStyle[index]);&lt;br /&gt;
&lt;br /&gt;
    if (!scatterDataByType.hasOwnProperty(dataset.name)) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    const scatterData = scatterDataByType[dataset.name];&lt;br /&gt;
    const canBeReduced = scatterData.length &amp;gt; 2 * maxPoints;&lt;br /&gt;
&lt;br /&gt;
    dataset.hidden = !isFirstDataset;&lt;br /&gt;
    dataset.canBeReduced = canBeReduced;&lt;br /&gt;
&lt;br /&gt;
    if (canBeReduced &amp;amp;&amp;amp; isReducePointsChecked) {&lt;br /&gt;
      dataset.data = aggregateDamage(scatterData, maxPoints);&lt;br /&gt;
    } else {&lt;br /&gt;
      dataset.data = scatterData;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isFirstDataset) {&lt;br /&gt;
      isFirstDataset = false;&lt;br /&gt;
&lt;br /&gt;
      if (canBeReduced) {&lt;br /&gt;
        showElement(reduceChartPointsContainer);&lt;br /&gt;
&lt;br /&gt;
        if (!isReducePointsChecked) {&lt;br /&gt;
          handleChartAnimations(chart, false);&lt;br /&gt;
        }&lt;br /&gt;
      } else {&lt;br /&gt;
        hideElement(reduceChartPointsContainer);&lt;br /&gt;
        handleChartAnimations(chart, true);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    datasets.push(dataset);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  chart.data.missPercentage = scatterDataByType.miss;&lt;br /&gt;
  chart.update();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addToBonusVariationChart(&lt;br /&gt;
  damageByBonus,&lt;br /&gt;
  augmentationByBonus,&lt;br /&gt;
  xLabel,&lt;br /&gt;
  chart&lt;br /&gt;
) {&lt;br /&gt;
  chart.data.datasets[0].data = damageByBonus;&lt;br /&gt;
  chart.data.datasets[1].data = augmentationByBonus;&lt;br /&gt;
  chart.options.scales.x.title.text = xLabel;&lt;br /&gt;
  chart.update();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleChartAnimations(chart, addAnimations) {&lt;br /&gt;
  chart.options.animation = addAnimations;&lt;br /&gt;
  chart.options.animations.colors = addAnimations;&lt;br /&gt;
  chart.options.animations.x = addAnimations;&lt;br /&gt;
  chart.options.transitions.active.animation.duration = addAnimations * 1000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateDamageChartDescription(battle, uniqueDamageCount) {&lt;br /&gt;
  const {&lt;br /&gt;
    chartDescriptionContainer,&lt;br /&gt;
    uniqueDamageCounters,&lt;br /&gt;
    numberFormats: { default: defaultFormat },&lt;br /&gt;
  } = battle;&lt;br /&gt;
&lt;br /&gt;
  if (uniqueDamageCount &amp;gt; 1) {&lt;br /&gt;
    uniqueDamageCounters.forEach(function (element) {&lt;br /&gt;
      element.textContent = defaultFormat.format(uniqueDamageCount);&lt;br /&gt;
    });&lt;br /&gt;
    showElement(chartDescriptionContainer);&lt;br /&gt;
  } else {&lt;br /&gt;
    hideElement(chartDescriptionContainer);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getMonsterName(monsterVnum) {&lt;br /&gt;
  var monsterAttributes = monsterData[monsterVnum];&lt;br /&gt;
  return monsterAttributes[monsterAttributes.length - 1];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getTranslatedMonsterName(monsterVnum) {&lt;br /&gt;
  return translation.monsters[monsterVnum];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterClass(selectedRace, classChoice, selectValueIsChanged = false) {&lt;br /&gt;
  for (var radioNode of classChoice) {&lt;br /&gt;
    var radioGrandParent = radioNode.parentElement.parentElement;&lt;br /&gt;
&lt;br /&gt;
    if (radioNode.getAttribute(&amp;quot;data-race&amp;quot;) === selectedRace) {&lt;br /&gt;
      if (!selectValueIsChanged) {&lt;br /&gt;
        radioNode.checked = true;&lt;br /&gt;
        selectValueIsChanged = true;&lt;br /&gt;
      }&lt;br /&gt;
      showElement(radioGrandParent);&lt;br /&gt;
    } else {&lt;br /&gt;
      hideElement(radioGrandParent);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterWeapon(&lt;br /&gt;
  selectedRace,&lt;br /&gt;
  weaponElement,&lt;br /&gt;
  weaponCategory,&lt;br /&gt;
  allowedWeaponsPerRace,&lt;br /&gt;
  selectValueIsChanged = false&lt;br /&gt;
) {&lt;br /&gt;
  var allowedWeapons = allowedWeaponsPerRace[selectedRace];&lt;br /&gt;
&lt;br /&gt;
  if (!selectValueIsChanged) {&lt;br /&gt;
    var weaponType = createWeapon(weaponElement.value).type;&lt;br /&gt;
&lt;br /&gt;
    if (!isValueInArray(weaponType, allowedWeapons)) {&lt;br /&gt;
      weaponElement.value = 0;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var children = weaponCategory.children;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; children.length; index++) {&lt;br /&gt;
    var child = children[index];&lt;br /&gt;
&lt;br /&gt;
    if (isValueInArray(index, allowedWeapons)) {&lt;br /&gt;
      showElement(child);&lt;br /&gt;
    } else {&lt;br /&gt;
      hideElement(child);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function changePolymorphValues(characterCreation, monsterVnum, monsterImage) {&lt;br /&gt;
  var { polymorphMonster, polymorphMonsterImage } = characterCreation;&lt;br /&gt;
&lt;br /&gt;
  polymorphMonster.value = monsterVnum;&lt;br /&gt;
  polymorphMonsterImage.value = monsterImage;&lt;br /&gt;
&lt;br /&gt;
  polymorphMonster.dispatchEvent(newChangeEvent());&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function resetImageFromWiki(image) {&lt;br /&gt;
  image.removeAttribute(&amp;quot;srcset&amp;quot;);&lt;br /&gt;
  image.removeAttribute(&amp;quot;data-file-width&amp;quot;);&lt;br /&gt;
  image.removeAttribute(&amp;quot;data-file-height&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleImageFromWiki(image, newSrc) {&lt;br /&gt;
  image.src = newSrc;&lt;br /&gt;
  image.alt = newSrc.split(&amp;quot;/&amp;quot;).pop();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handlePolymorphDisplay(characters, monsterVnum, monsterSrc) {&lt;br /&gt;
  var { translateMonsters, polymorphDisplay } = characters;&lt;br /&gt;
  var oldImage = polymorphDisplay.firstChild;&lt;br /&gt;
  var oldLink = oldImage.nextElementSibling;&lt;br /&gt;
  var monsterName = getMonsterName(monsterVnum);&lt;br /&gt;
  var displayName = translateMonsters&lt;br /&gt;
    ? getTranslatedMonsterName(monsterVnum)&lt;br /&gt;
    : monsterName;&lt;br /&gt;
  var newLink = createWikiLink(monsterName, displayName);&lt;br /&gt;
&lt;br /&gt;
  resetImageFromWiki(oldImage);&lt;br /&gt;
  handleImageFromWiki(oldImage, monsterSrc);&lt;br /&gt;
&lt;br /&gt;
  polymorphDisplay.replaceChild(newLink, oldLink);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createWikiLink(pageName, displayName) {&lt;br /&gt;
  var wikiLink = document.createElement(&amp;quot;a&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  wikiLink.href = mw.util.getUrl(pageName);&lt;br /&gt;
  wikiLink.title = pageName;&lt;br /&gt;
  wikiLink.textContent = displayName || pageName;&lt;br /&gt;
&lt;br /&gt;
  return wikiLink;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSelectedWeapon(weaponCategory) {&lt;br /&gt;
  return weaponCategory.querySelector(&amp;quot;input[type='radio']:checked&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleWeaponDisplay(&lt;br /&gt;
  weaponCategory,&lt;br /&gt;
  weaponDisplay,&lt;br /&gt;
  weaponVnum,&lt;br /&gt;
  newWeapon&lt;br /&gt;
) {&lt;br /&gt;
  var newWeapon = newWeapon || getSelectedWeapon(weaponCategory);&lt;br /&gt;
&lt;br /&gt;
  var newImage = newWeapon.nextElementSibling;&lt;br /&gt;
  var newText = document.createElement(&amp;quot;span&amp;quot;);&lt;br /&gt;
  var oldImage = weaponDisplay.firstChild;&lt;br /&gt;
  var oldText = oldImage.nextElementSibling;&lt;br /&gt;
  var weaponTooltip = newImage.nextElementSibling;&lt;br /&gt;
  var originalWeaponName = weaponTooltip.dataset.o;&lt;br /&gt;
  var weaponName = weaponTooltip.textContent;&lt;br /&gt;
&lt;br /&gt;
  if (weaponVnum == 0) {&lt;br /&gt;
    newText.textContent = weaponName;&lt;br /&gt;
  } else {&lt;br /&gt;
    var weaponLink = createWikiLink(originalWeaponName, weaponName);&lt;br /&gt;
    newText.appendChild(weaponLink);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  weaponDisplay.replaceChild(newImage.cloneNode(), oldImage);&lt;br /&gt;
  weaponDisplay.replaceChild(newText, oldText);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterUpgrade(&lt;br /&gt;
  weaponUpgrade,&lt;br /&gt;
  weaponVnum,&lt;br /&gt;
  randomAttackValue,&lt;br /&gt;
  randomMagicAttackValue&lt;br /&gt;
) {&lt;br /&gt;
  var weapon = createWeapon(weaponVnum);&lt;br /&gt;
  var currentUpgrade = Number(weaponUpgrade.value);&lt;br /&gt;
  var weaponUpgradeChildren = weaponUpgrade.children;&lt;br /&gt;
&lt;br /&gt;
  if (weapon.isSerpent) {&lt;br /&gt;
    showElement(randomAttackValue);&lt;br /&gt;
&lt;br /&gt;
    if (weapon.isMagic) {&lt;br /&gt;
      showElement(randomMagicAttackValue);&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    hideElement(randomAttackValue);&lt;br /&gt;
    hideElement(randomMagicAttackValue);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (weapon.maxUpgrade &amp;lt; 1) {&lt;br /&gt;
    hideElement(weaponUpgrade.parentElement);&lt;br /&gt;
  } else {&lt;br /&gt;
    showElement(weaponUpgrade.parentElement);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (var upgrade = 0; upgrade &amp;lt;= weapon.maxUpgrade; upgrade++) {&lt;br /&gt;
    showElement(weaponUpgradeChildren[upgrade]);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (&lt;br /&gt;
    var upgrade = weapon.maxUpgrade + 1;&lt;br /&gt;
    upgrade &amp;lt; weaponUpgradeChildren.length;&lt;br /&gt;
    upgrade++&lt;br /&gt;
  ) {&lt;br /&gt;
    hideElement(weaponUpgradeChildren[upgrade]);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (currentUpgrade &amp;gt; weapon.maxUpgrade) {&lt;br /&gt;
    weaponUpgrade.value = weapon.maxUpgrade;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterCheckbox(checkbox, element) {&lt;br /&gt;
  if (checkbox.checked) {&lt;br /&gt;
    showElement(element);&lt;br /&gt;
  } else {&lt;br /&gt;
    hideElement(element);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterSkills(selectedClass, skillElementsToFilter) {&lt;br /&gt;
  for (var element of skillElementsToFilter) {&lt;br /&gt;
    if (isValueInArray(selectedClass, element.dataset.class)) {&lt;br /&gt;
      showElement(element);&lt;br /&gt;
    } else {&lt;br /&gt;
      hideElement(element);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterForm(characters, battle) {&lt;br /&gt;
  var { saveButton, characterCreation, toggleSiblings } = characters;&lt;br /&gt;
  var allowedWeaponsPerRace = battle.constants.allowedWeaponsPerRace;&lt;br /&gt;
  var battleChoice = battle.battleChoice;&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;change&amp;quot;, function (event) {&lt;br /&gt;
    var target = event.target;&lt;br /&gt;
    var targetName = target.name;&lt;br /&gt;
&lt;br /&gt;
    saveButtonOrange(saveButton);&lt;br /&gt;
    characters.unsavedChanges = true;&lt;br /&gt;
&lt;br /&gt;
    switch (targetName) {&lt;br /&gt;
      case &amp;quot;race&amp;quot;:&lt;br /&gt;
        var selectedRace = target.value;&lt;br /&gt;
        var classChoice = characterCreation.class;&lt;br /&gt;
        var weaponElement = characterCreation.weapon;&lt;br /&gt;
&lt;br /&gt;
        filterClass(selectedRace, classChoice);&lt;br /&gt;
        filterWeapon(&lt;br /&gt;
          selectedRace,&lt;br /&gt;
          weaponElement,&lt;br /&gt;
          characters.weaponCategory,&lt;br /&gt;
          allowedWeaponsPerRace&lt;br /&gt;
        );&lt;br /&gt;
        handleWeaponDisplay(&lt;br /&gt;
          characters.weaponCategory,&lt;br /&gt;
          characters.weaponDisplay,&lt;br /&gt;
          weaponElement.value&lt;br /&gt;
        );&lt;br /&gt;
        filterUpgrade(&lt;br /&gt;
          characterCreation.weaponUpgrade,&lt;br /&gt;
          weaponElement.value,&lt;br /&gt;
          characters.randomAttackValue,&lt;br /&gt;
          characters.randomMagicAttackValue&lt;br /&gt;
        );&lt;br /&gt;
        filterSkills(classChoice.value, characters.skillElementsToFilter);&lt;br /&gt;
        handleBonusVariationUpdate(&lt;br /&gt;
          characterCreation,&lt;br /&gt;
          characters.bonusVariation,&lt;br /&gt;
          true&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        battleChoice.resetAttackType = true;&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;class&amp;quot;:&lt;br /&gt;
        filterSkills(target.value, characters.skillElementsToFilter);&lt;br /&gt;
        handleBonusVariationUpdate(&lt;br /&gt;
          characterCreation,&lt;br /&gt;
          characters.bonusVariation,&lt;br /&gt;
          true&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        battleChoice.resetAttackType = true;&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;weapon&amp;quot;:&lt;br /&gt;
        var weaponElement = characterCreation.weapon;&lt;br /&gt;
&lt;br /&gt;
        handleWeaponDisplay(&lt;br /&gt;
          characters.weaponCategory,&lt;br /&gt;
          characters.weaponDisplay,&lt;br /&gt;
          weaponElement.value,&lt;br /&gt;
          target&lt;br /&gt;
        );&lt;br /&gt;
        filterUpgrade(&lt;br /&gt;
          characterCreation.weaponUpgrade,&lt;br /&gt;
          target.value,&lt;br /&gt;
          characters.randomAttackValue,&lt;br /&gt;
          characters.randomMagicAttackValue&lt;br /&gt;
        );&lt;br /&gt;
        handleBonusVariationUpdate(&lt;br /&gt;
          characterCreation,&lt;br /&gt;
          characters.bonusVariation&lt;br /&gt;
        );&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;isRiding&amp;quot;:&lt;br /&gt;
        battleChoice.resetAttackType = true;&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;isPolymorph&amp;quot;:&lt;br /&gt;
        battleChoice.resetAttackType = true;&lt;br /&gt;
        break;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (toggleSiblings.hasOwnProperty(targetName)) {&lt;br /&gt;
      filterCheckbox(target, toggleSiblings[targetName]);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      targetName.startsWith(&amp;quot;attackSkill&amp;quot;) ||&lt;br /&gt;
      targetName.startsWith(&amp;quot;horseSkill&amp;quot;)&lt;br /&gt;
    ) {&lt;br /&gt;
      battleChoice.resetAttackType = true;&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addUniquePseudo(characterDataObject, savedCharactersPseudo) {&lt;br /&gt;
  var characterPseudo = String(characterDataObject.name);&lt;br /&gt;
  var originalPseudo = characterPseudo;&lt;br /&gt;
  var count = 0;&lt;br /&gt;
&lt;br /&gt;
  var regex = /(.*)(\d)$/;&lt;br /&gt;
  var match = characterPseudo.match(regex);&lt;br /&gt;
&lt;br /&gt;
  if (match) {&lt;br /&gt;
    originalPseudo = match[1];&lt;br /&gt;
    count = match[2];&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  while (isValueInArray(characterPseudo, savedCharactersPseudo)) {&lt;br /&gt;
    characterPseudo = originalPseudo + count;&lt;br /&gt;
    count++;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  characterDataObject.name = characterPseudo;&lt;br /&gt;
  return [characterDataObject, characterPseudo];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function convertToNumber(value) {&lt;br /&gt;
  var valueNumber = Number(value);&lt;br /&gt;
  return isNaN(valueNumber) ? value : valueNumber;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getLocalStorageValue(key, defaultValue) {&lt;br /&gt;
  var storedValue = localStorage.getItem(key);&lt;br /&gt;
&lt;br /&gt;
  if (storedValue) {&lt;br /&gt;
    return JSON.parse(storedValue);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return defaultValue;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSavedCharacters() {&lt;br /&gt;
  return getLocalStorageValue(&amp;quot;mt2-calc.characters.saved&amp;quot;, {});&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSavedMonsters() {&lt;br /&gt;
  return getLocalStorageValue(&amp;quot;mt2-calc.monsters.saved&amp;quot;, {});&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSavedFights() {&lt;br /&gt;
  return getLocalStorageValue(&amp;quot;mt2-calc.fights.saved&amp;quot;, []);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getLastLang() {&lt;br /&gt;
  return getLocalStorageValue(&amp;quot;mt2-calc.language.last-used&amp;quot;, &amp;quot;&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveToLocalStorage(key, value) {&lt;br /&gt;
  localStorage.setItem(key, JSON.stringify(value));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateSavedCharacters(savedCharacters) {&lt;br /&gt;
  saveToLocalStorage(&amp;quot;mt2-calc.characters.saved&amp;quot;, savedCharacters);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateSavedMonsters(savedMonsters) {&lt;br /&gt;
  saveToLocalStorage(&amp;quot;mt2-calc.monsters.saved&amp;quot;, savedMonsters);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateSavedFights(savedFights) {&lt;br /&gt;
  saveToLocalStorage(&amp;quot;mt2-calc.fights.saved&amp;quot;, savedFights);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateLastLang(lang) {&lt;br /&gt;
  saveToLocalStorage(&amp;quot;mt2-calc.language.last-used&amp;quot;, lang);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveCharacter(&lt;br /&gt;
  savedCharacters,&lt;br /&gt;
  characterCreation,&lt;br /&gt;
  battle,&lt;br /&gt;
  newCharacter,&lt;br /&gt;
  characterDataObject&lt;br /&gt;
) {&lt;br /&gt;
  if (!characterDataObject) {&lt;br /&gt;
    var characterData = new FormData(characterCreation);&lt;br /&gt;
    var characterDataObject = {};&lt;br /&gt;
&lt;br /&gt;
    characterData.forEach(function (value, key) {&lt;br /&gt;
      characterDataObject[key] = convertToNumber(value);&lt;br /&gt;
    });&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var characterPseudo = characterDataObject.name;&lt;br /&gt;
  var { battleChoice } = battle;&lt;br /&gt;
&lt;br /&gt;
  savedCharacters[characterPseudo] = characterDataObject;&lt;br /&gt;
  updateSavedCharacters(savedCharacters);&lt;br /&gt;
&lt;br /&gt;
  if (newCharacter) {&lt;br /&gt;
    addBattleChoice(battleChoice, characterPseudo, characterDataObject);&lt;br /&gt;
  } else {&lt;br /&gt;
    updateBattleChoiceImage(&lt;br /&gt;
      battleChoice,&lt;br /&gt;
      characterPseudo,&lt;br /&gt;
      characterDataObject.race&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (battleChoice.resetAttackType) {&lt;br /&gt;
    if (isCharacterSelected(characterPseudo, battleChoice.attacker.selected)) {&lt;br /&gt;
      filterAttackTypeSelectionCharacter(&lt;br /&gt;
        characterDataObject,&lt;br /&gt;
        battleChoice.attackType&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
    battleChoice.resetAttackType = false;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveButtonGreen(saveButton) {&lt;br /&gt;
  saveButton.classList.remove(&amp;quot;unsaved-character&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveButtonOrange(saveButton) {&lt;br /&gt;
  saveButton.classList.add(&amp;quot;unsaved-character&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function characterCreationListener(characters, battle) {&lt;br /&gt;
  var { characterCreation, saveButton, weaponCategory } = characters;&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;submit&amp;quot;, handleSubmitForm);&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;invalid&amp;quot;, handleInvalidInput, true);&lt;br /&gt;
  document.addEventListener(&amp;quot;keydown&amp;quot;, handleSaveShortcut);&lt;br /&gt;
  weaponCategory.addEventListener(&amp;quot;mouseover&amp;quot;, handleTooltipOverflow);&lt;br /&gt;
&lt;br /&gt;
  function handleSubmitForm(event) {&lt;br /&gt;
    event.preventDefault();&lt;br /&gt;
&lt;br /&gt;
    if (characters.unsavedChanges) {&lt;br /&gt;
      saveCharacter(characters.savedCharacters, characterCreation, battle);&lt;br /&gt;
      saveButtonGreen(saveButton);&lt;br /&gt;
      characters.unsavedChanges = false;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function handleInvalidInput(event) {&lt;br /&gt;
    var target = event.target;&lt;br /&gt;
&lt;br /&gt;
    if (target.checkVisibility()) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var autoCorrectInput = target.closest(&amp;quot;.auto-correct-input&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      autoCorrectInput &amp;amp;&amp;amp;&lt;br /&gt;
      autoCorrectInput.classList.contains(&amp;quot;tabber-noactive&amp;quot;)&lt;br /&gt;
    ) {&lt;br /&gt;
      target.value = target.defaultValue;&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    openTargetTab(target);&lt;br /&gt;
    openTargetCollapsible(target);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function handleSaveShortcut(event) {&lt;br /&gt;
    if (event.ctrlKey &amp;amp;&amp;amp; event.key === &amp;quot;s&amp;quot;) {&lt;br /&gt;
      event.preventDefault();&lt;br /&gt;
      saveButton.click();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function handleTooltipOverflow(event) {&lt;br /&gt;
    var label = event.target.closest(&amp;quot;label&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (label) {&lt;br /&gt;
      var tooltip = label.lastChild;&lt;br /&gt;
&lt;br /&gt;
      if (tooltip.classList.contains(&amp;quot;popContenu&amp;quot;)) {&lt;br /&gt;
        var tooltipRect = tooltip.getBoundingClientRect();&lt;br /&gt;
        var modalRect = weaponCategory.getBoundingClientRect();&lt;br /&gt;
&lt;br /&gt;
        if (tooltipRect.right &amp;gt; modalRect.right) {&lt;br /&gt;
          tooltip.style.left = &amp;quot;-100%&amp;quot;;&lt;br /&gt;
        } else if (tooltipRect.left &amp;lt; modalRect.left) {&lt;br /&gt;
          tooltip.style.left = &amp;quot;200%&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function downloadData(content, type, filename) {&lt;br /&gt;
  var link = document.createElement(&amp;quot;a&amp;quot;);&lt;br /&gt;
  var blob = new Blob([content], { type: type });&lt;br /&gt;
  var blobURL = URL.createObjectURL(blob);&lt;br /&gt;
&lt;br /&gt;
  link.href = blobURL;&lt;br /&gt;
  link.download = filename;&lt;br /&gt;
  document.body.appendChild(link);&lt;br /&gt;
&lt;br /&gt;
  link.click();&lt;br /&gt;
  document.body.removeChild(link);&lt;br /&gt;
  URL.revokeObjectURL(blobURL);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function uploadCharacter(&lt;br /&gt;
  selectedFiles,&lt;br /&gt;
  characters,&lt;br /&gt;
  characterTemplate,&lt;br /&gt;
  charactersContainer,&lt;br /&gt;
  battle&lt;br /&gt;
) {&lt;br /&gt;
  var selectFilesLength = selectedFiles.length;&lt;br /&gt;
  var defaultPseudo = characters.defaultText.pseudo;&lt;br /&gt;
&lt;br /&gt;
  for (var fileIndex = 0; fileIndex &amp;lt; selectFilesLength; fileIndex++) {&lt;br /&gt;
    var selectedFile = selectedFiles[fileIndex];&lt;br /&gt;
&lt;br /&gt;
    if (selectedFile.type === &amp;quot;text/plain&amp;quot;) {&lt;br /&gt;
      var reader = new FileReader();&lt;br /&gt;
      reader.onload = function (e) {&lt;br /&gt;
        var fileContent = e.target.result;&lt;br /&gt;
        try {&lt;br /&gt;
          var characterDataObject = JSON.parse(fileContent);&lt;br /&gt;
&lt;br /&gt;
          if (characterDataObject.hasOwnProperty(&amp;quot;name&amp;quot;)) {&lt;br /&gt;
            var characterPseudo = String(characterDataObject.name);&lt;br /&gt;
&lt;br /&gt;
            hideElement(characters.characterCreation);&lt;br /&gt;
            characterPseudo = validPseudo(characterPseudo, defaultPseudo);&lt;br /&gt;
&lt;br /&gt;
            [characterDataObject, characterPseudo] = addUniquePseudo(&lt;br /&gt;
              characterDataObject,&lt;br /&gt;
              Object.keys(characters.savedCharacters)&lt;br /&gt;
            );&lt;br /&gt;
            var selectedCharacter = handleNewCharacter(&lt;br /&gt;
              characters,&lt;br /&gt;
              characterTemplate,&lt;br /&gt;
              charactersContainer,&lt;br /&gt;
              battle,&lt;br /&gt;
              characterPseudo&lt;br /&gt;
            )[0];&lt;br /&gt;
&lt;br /&gt;
            if (selectFilesLength === 1) {&lt;br /&gt;
              updateForm(&lt;br /&gt;
                characterDataObject,&lt;br /&gt;
                characters.characterCreation,&lt;br /&gt;
                characters,&lt;br /&gt;
                selectedCharacter,&lt;br /&gt;
                battle&lt;br /&gt;
              );&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            saveCharacter(&lt;br /&gt;
              characters.savedCharacters,&lt;br /&gt;
              characters.characterCreation,&lt;br /&gt;
              battle,&lt;br /&gt;
              true,&lt;br /&gt;
              characterDataObject&lt;br /&gt;
            );&lt;br /&gt;
          }&lt;br /&gt;
        } catch (error) {&lt;br /&gt;
          console.warn(error);&lt;br /&gt;
          if (error.name === &amp;quot;TypeError&amp;quot;) {&lt;br /&gt;
            // delete the character&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
      };&lt;br /&gt;
      reader.readAsText(selectedFile);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleUploadCharacter(&lt;br /&gt;
  characters,&lt;br /&gt;
  characterTemplate,&lt;br /&gt;
  charactersContainer,&lt;br /&gt;
  battle&lt;br /&gt;
) {&lt;br /&gt;
  var characterInput = characters.characterInput;&lt;br /&gt;
  var dropZone = characters.dropZone;&lt;br /&gt;
&lt;br /&gt;
  characterInput.accept = &amp;quot;.txt&amp;quot;;&lt;br /&gt;
  characterInput.multiple = true;&lt;br /&gt;
  dropZone.setAttribute(&amp;quot;tabindex&amp;quot;, &amp;quot;0&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  dropZone.addEventListener(&amp;quot;click&amp;quot;, function () {&lt;br /&gt;
    characterInput.click();&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  dropZone.addEventListener(&amp;quot;dragover&amp;quot;, function (event) {&lt;br /&gt;
    event.preventDefault();&lt;br /&gt;
    dropZone.classList.add(&amp;quot;drop-zone--dragover&amp;quot;);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  [&amp;quot;dragleave&amp;quot;, &amp;quot;dragend&amp;quot;].forEach(function (type) {&lt;br /&gt;
    dropZone.addEventListener(type, function () {&lt;br /&gt;
      dropZone.classList.remove(&amp;quot;drop-zone--dragover&amp;quot;);&lt;br /&gt;
    });&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  dropZone.addEventListener(&amp;quot;drop&amp;quot;, function (event) {&lt;br /&gt;
    event.preventDefault();&lt;br /&gt;
    uploadCharacter(&lt;br /&gt;
      event.dataTransfer.files,&lt;br /&gt;
      characters,&lt;br /&gt;
      characterTemplate,&lt;br /&gt;
      charactersContainer,&lt;br /&gt;
      battle&lt;br /&gt;
    );&lt;br /&gt;
    dropZone.classList.remove(&amp;quot;drop-zone--dragover&amp;quot;);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  characterInput.addEventListener(&amp;quot;change&amp;quot;, function (event) {&lt;br /&gt;
    uploadCharacter(&lt;br /&gt;
      event.target.files,&lt;br /&gt;
      characters,&lt;br /&gt;
      characterTemplate,&lt;br /&gt;
      charactersContainer,&lt;br /&gt;
      battle&lt;br /&gt;
    );&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function deleteCharacter(characters, pseudo, element, battle) {&lt;br /&gt;
  delete characters.savedCharacters[pseudo];&lt;br /&gt;
  element.remove();&lt;br /&gt;
&lt;br /&gt;
  updateSavedCharacters(characters.savedCharacters);&lt;br /&gt;
  removeBattleChoice(battle.battleChoice, pseudo, &amp;quot;character&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (&lt;br /&gt;
    !Object.keys(characters.savedCharacters).length ||&lt;br /&gt;
    characters.characterCreation.name.value === pseudo&lt;br /&gt;
  ) {&lt;br /&gt;
    saveButtonGreen(characters.saveButton);&lt;br /&gt;
    characters.unsavedChanges = false;&lt;br /&gt;
    hideElement(characters.characterCreation);&lt;br /&gt;
    showElement(characters.characterCreation.previousElementSibling);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function deleteMonster(characters, battle, monsterVnum) {&lt;br /&gt;
  var monsterElements = characters.monsterElements;&lt;br /&gt;
  var monsterType = characters.savedMonsters[monsterVnum].category;&lt;br /&gt;
&lt;br /&gt;
  if (monsterElements.hasOwnProperty(monsterVnum)) {&lt;br /&gt;
    monsterElements[monsterVnum].remove();&lt;br /&gt;
    delete monsterElements[monsterVnum];&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  delete characters.savedMonsters[monsterVnum];&lt;br /&gt;
&lt;br /&gt;
  updateSavedMonsters(characters.savedMonsters);&lt;br /&gt;
  removeBattleChoice(battle.battleChoice, monsterVnum, monsterType);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleStyle(characters, selectedElement) {&lt;br /&gt;
  var currentCharacter = characters.currentCharacter;&lt;br /&gt;
&lt;br /&gt;
  if (currentCharacter) {&lt;br /&gt;
    currentCharacter.classList.remove(&amp;quot;selected-character&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  selectedElement.classList.add(&amp;quot;selected-character&amp;quot;);&lt;br /&gt;
  characters.currentCharacter = selectedElement;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateForm(&lt;br /&gt;
  formData,&lt;br /&gt;
  characterCreation,&lt;br /&gt;
  characters,&lt;br /&gt;
  selectedElement,&lt;br /&gt;
  battle&lt;br /&gt;
) {&lt;br /&gt;
  saveButtonGreen(characters.saveButton);&lt;br /&gt;
  hideElement(characterCreation.previousElementSibling);&lt;br /&gt;
  showElement(characterCreation);&lt;br /&gt;
  handleStyle(characters, selectedElement);&lt;br /&gt;
&lt;br /&gt;
  characterCreation.reset();&lt;br /&gt;
&lt;br /&gt;
  for (var [name, value] of Object.entries(formData)) {&lt;br /&gt;
    var formElement = characterCreation[name];&lt;br /&gt;
&lt;br /&gt;
    if (!formElement) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (formElement.type === &amp;quot;checkbox&amp;quot;) {&lt;br /&gt;
      if (isChecked(value)) {&lt;br /&gt;
        formElement.checked = true;&lt;br /&gt;
      }&lt;br /&gt;
    } else {&lt;br /&gt;
      formElement.value = value;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  var selectedRace = characterCreation.race.value;&lt;br /&gt;
  var classChoice = characterCreation.class;&lt;br /&gt;
  var weaponElement = characterCreation.weapon;&lt;br /&gt;
&lt;br /&gt;
  filterClass(selectedRace, classChoice, true);&lt;br /&gt;
  filterWeapon(&lt;br /&gt;
    selectedRace,&lt;br /&gt;
    weaponElement,&lt;br /&gt;
    characters.weaponCategory,&lt;br /&gt;
    battle.constants.allowedWeaponsPerRace,&lt;br /&gt;
    true&lt;br /&gt;
  );&lt;br /&gt;
  handlePolymorphDisplay(&lt;br /&gt;
    characters,&lt;br /&gt;
    characterCreation.polymorphMonster.value,&lt;br /&gt;
    characterCreation.polymorphMonsterImage.value&lt;br /&gt;
  );&lt;br /&gt;
  handleWeaponDisplay(&lt;br /&gt;
    characters.weaponCategory,&lt;br /&gt;
    characters.weaponDisplay,&lt;br /&gt;
    weaponElement.value&lt;br /&gt;
  );&lt;br /&gt;
  filterUpgrade(&lt;br /&gt;
    characterCreation.weaponUpgrade,&lt;br /&gt;
    weaponElement.value,&lt;br /&gt;
    characters.randomAttackValue,&lt;br /&gt;
    characters.randomMagicAttackValue&lt;br /&gt;
  );&lt;br /&gt;
  for (var [targetName, sibling] of Object.entries(characters.toggleSiblings)) {&lt;br /&gt;
    filterCheckbox(characterCreation[targetName], sibling);&lt;br /&gt;
  }&lt;br /&gt;
  filterSkills(classChoice.value, characters.skillElementsToFilter);&lt;br /&gt;
  handleBonusVariationUpdate(characterCreation, characters.bonusVariation);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleClickOnCharacter(&lt;br /&gt;
  spanInput,&lt;br /&gt;
  target,&lt;br /&gt;
  characters,&lt;br /&gt;
  characterElement,&lt;br /&gt;
  battle,&lt;br /&gt;
  edition&lt;br /&gt;
) {&lt;br /&gt;
  var displayedPseudo = characters.characterCreation.name.value;&lt;br /&gt;
  var pseudo = spanInput.dataset.name;&lt;br /&gt;
  var { unsavedWarning, deleteWarning } = characters.defaultText;&lt;br /&gt;
&lt;br /&gt;
  if (edition) {&lt;br /&gt;
    if (!characters.unsavedChanges) {&lt;br /&gt;
      updateForm(&lt;br /&gt;
        characters.savedCharacters[pseudo],&lt;br /&gt;
        characters.characterCreation,&lt;br /&gt;
        characters,&lt;br /&gt;
        characterElement,&lt;br /&gt;
        battle&lt;br /&gt;
      );&lt;br /&gt;
    } else if (displayedPseudo === pseudo) {&lt;br /&gt;
      // pass&lt;br /&gt;
    } else {&lt;br /&gt;
      var result = confirm(unsavedWarning);&lt;br /&gt;
&lt;br /&gt;
      if (result) {&lt;br /&gt;
        updateForm(&lt;br /&gt;
          characters.savedCharacters[pseudo],&lt;br /&gt;
          characters.characterCreation,&lt;br /&gt;
          characters,&lt;br /&gt;
          characterElement,&lt;br /&gt;
          battle&lt;br /&gt;
        );&lt;br /&gt;
        characters.unsavedChanges = false;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    if (target.tagName === &amp;quot;path&amp;quot;) {&lt;br /&gt;
      target = target.parentElement;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    switch (target.dataset.icon) {&lt;br /&gt;
      case &amp;quot;duplicate&amp;quot;:&lt;br /&gt;
        if (!characters.unsavedChanges) {&lt;br /&gt;
          addNewCharacter(&lt;br /&gt;
            characters,&lt;br /&gt;
            characters.newCharacterTemplate,&lt;br /&gt;
            characters.charactersContainer,&lt;br /&gt;
            battle,&lt;br /&gt;
            pseudo&lt;br /&gt;
          );&lt;br /&gt;
        } else {&lt;br /&gt;
          var result = confirm(unsavedWarning);&lt;br /&gt;
&lt;br /&gt;
          if (result) {&lt;br /&gt;
            addNewCharacter(&lt;br /&gt;
              characters,&lt;br /&gt;
              characters.newCharacterTemplate,&lt;br /&gt;
              characters.charactersContainer,&lt;br /&gt;
              battle,&lt;br /&gt;
              pseudo&lt;br /&gt;
            );&lt;br /&gt;
            saveButtonGreen(characters.saveButton);&lt;br /&gt;
            characters.unsavedChanges = false;&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
        break;&lt;br /&gt;
&lt;br /&gt;
      case &amp;quot;download&amp;quot;:&lt;br /&gt;
        var character = characters.savedCharacters[pseudo];&lt;br /&gt;
        downloadData(&lt;br /&gt;
          JSON.stringify(character),&lt;br /&gt;
          &amp;quot;text/plain&amp;quot;,&lt;br /&gt;
          character.name + &amp;quot;.txt&amp;quot;&lt;br /&gt;
        );&lt;br /&gt;
        break;&lt;br /&gt;
&lt;br /&gt;
      case &amp;quot;delete&amp;quot;:&lt;br /&gt;
        var result = confirm(deleteWarning.replace(&amp;quot;[[]]&amp;quot;, pseudo));&lt;br /&gt;
        if (result) {&lt;br /&gt;
          deleteCharacter(characters, pseudo, characterElement, battle);&lt;br /&gt;
        }&lt;br /&gt;
        break;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleNewCharacter(&lt;br /&gt;
  characters,&lt;br /&gt;
  characterTemplate,&lt;br /&gt;
  charactersContainer,&lt;br /&gt;
  battle,&lt;br /&gt;
  pseudo&lt;br /&gt;
) {&lt;br /&gt;
  var newCharacterTemplate = characterTemplate.cloneNode(true);&lt;br /&gt;
  var spanInput = newCharacterTemplate.querySelector(&amp;quot;span.input&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  newCharacterTemplate.setAttribute(&amp;quot;tabindex&amp;quot;, &amp;quot;0&amp;quot;);&lt;br /&gt;
  charactersContainer.appendChild(newCharacterTemplate);&lt;br /&gt;
&lt;br /&gt;
  if (pseudo) {&lt;br /&gt;
    spanInput.textContent = pseudo;&lt;br /&gt;
    spanInput.setAttribute(&amp;quot;data-name&amp;quot;, pseudo);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  newCharacterTemplate.addEventListener(&amp;quot;click&amp;quot;, function (event) {&lt;br /&gt;
    var target = event.target;&lt;br /&gt;
&lt;br /&gt;
    if (target.tagName === &amp;quot;path&amp;quot; || target.tagName === &amp;quot;svg&amp;quot;) {&lt;br /&gt;
      handleClickOnCharacter(&lt;br /&gt;
        spanInput,&lt;br /&gt;
        target,&lt;br /&gt;
        characters,&lt;br /&gt;
        newCharacterTemplate,&lt;br /&gt;
        battle&lt;br /&gt;
      );&lt;br /&gt;
    } else {&lt;br /&gt;
      handleClickOnCharacter(&lt;br /&gt;
        spanInput,&lt;br /&gt;
        null,&lt;br /&gt;
        characters,&lt;br /&gt;
        newCharacterTemplate,&lt;br /&gt;
        battle,&lt;br /&gt;
        true&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  newCharacterTemplate.addEventListener(&amp;quot;keydown&amp;quot;, function (event) {&lt;br /&gt;
    if (event.keyCode === 13) {&lt;br /&gt;
      event.target.click();&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  return [newCharacterTemplate, spanInput];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function validPseudo(pseudo, defaultPseudo) {&lt;br /&gt;
  var newPseudo = pseudoFormat(pseudo);&lt;br /&gt;
&lt;br /&gt;
  if (!newPseudo) {&lt;br /&gt;
    return pseudoFormat(defaultPseudo);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return newPseudo;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addNewCharacter(&lt;br /&gt;
  characters,&lt;br /&gt;
  characterTemplate,&lt;br /&gt;
  charactersContainer,&lt;br /&gt;
  battle,&lt;br /&gt;
  pseudoToDuplicate&lt;br /&gt;
) {&lt;br /&gt;
  function editAndSetCharacterPseudoInput(selectedCharacter, spanInput) {&lt;br /&gt;
    var maxPseudoLength = 20;&lt;br /&gt;
    var defaultPseudo = characters.defaultText.pseudo;&lt;br /&gt;
&lt;br /&gt;
    var selection = window.getSelection();&lt;br /&gt;
    var range = document.createRange();&lt;br /&gt;
&lt;br /&gt;
    if (pseudoToDuplicate) {&lt;br /&gt;
      spanInput.textContent = pseudoToDuplicate;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    spanInput.contentEditable = true;&lt;br /&gt;
    spanInput.focus();&lt;br /&gt;
    range.selectNodeContents(spanInput);&lt;br /&gt;
    selection.removeAllRanges();&lt;br /&gt;
    selection.addRange(range);&lt;br /&gt;
&lt;br /&gt;
    function pseudoValidation() {&lt;br /&gt;
      var characterPseudo = validPseudo(spanInput.textContent, defaultPseudo);&lt;br /&gt;
      var characterDataObject = { name: characterPseudo };&lt;br /&gt;
&lt;br /&gt;
      if (pseudoToDuplicate) {&lt;br /&gt;
        characterDataObject = copyObject(&lt;br /&gt;
          characters.savedCharacters[pseudoToDuplicate]&lt;br /&gt;
        );&lt;br /&gt;
        characterDataObject.name = characterPseudo;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      [characterDataObject, characterPseudo] = addUniquePseudo(&lt;br /&gt;
        characterDataObject,&lt;br /&gt;
        Object.keys(characters.savedCharacters)&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      selection.removeAllRanges();&lt;br /&gt;
      spanInput.contentEditable = false;&lt;br /&gt;
      spanInput.textContent = characterPseudo;&lt;br /&gt;
      spanInput.setAttribute(&amp;quot;data-name&amp;quot;, characterPseudo);&lt;br /&gt;
&lt;br /&gt;
      updateForm(&lt;br /&gt;
        characterDataObject,&lt;br /&gt;
        characters.characterCreation,&lt;br /&gt;
        characters,&lt;br /&gt;
        selectedCharacter,&lt;br /&gt;
        battle&lt;br /&gt;
      );&lt;br /&gt;
      saveCharacter(&lt;br /&gt;
        characters.savedCharacters,&lt;br /&gt;
        characters.characterCreation,&lt;br /&gt;
        battle,&lt;br /&gt;
        true&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handleMaxLength(event) {&lt;br /&gt;
      if (spanInput.textContent.length &amp;gt; maxPseudoLength) {&lt;br /&gt;
        spanInput.textContent = spanInput.textContent.slice(0, maxPseudoLength);&lt;br /&gt;
        range.setStart(spanInput.childNodes[0], maxPseudoLength);&lt;br /&gt;
        selection.removeAllRanges();&lt;br /&gt;
        selection.addRange(range);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handleBlur() {&lt;br /&gt;
      spanInput.removeEventListener(&amp;quot;blur&amp;quot;, handleBlur);&lt;br /&gt;
      spanInput.removeEventListener(&amp;quot;input&amp;quot;, handleMaxLength);&lt;br /&gt;
      pseudoValidation();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handleKeyDown(event) {&lt;br /&gt;
      if (event.key === &amp;quot;Enter&amp;quot;) {&lt;br /&gt;
        event.preventDefault();&lt;br /&gt;
&lt;br /&gt;
        spanInput.removeEventListener(&amp;quot;keydown&amp;quot;, handleKeyDown);&lt;br /&gt;
        spanInput.removeEventListener(&amp;quot;blur&amp;quot;, handleBlur);&lt;br /&gt;
        spanInput.removeEventListener(&amp;quot;input&amp;quot;, handleMaxLength);&lt;br /&gt;
&lt;br /&gt;
        pseudoValidation();&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    spanInput.addEventListener(&amp;quot;input&amp;quot;, handleMaxLength);&lt;br /&gt;
    spanInput.addEventListener(&amp;quot;keydown&amp;quot;, handleKeyDown);&lt;br /&gt;
    spanInput.addEventListener(&amp;quot;blur&amp;quot;, handleBlur);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  hideElement(characters.characterCreation);&lt;br /&gt;
  var [selectedCharacter, spanInput] = handleNewCharacter(&lt;br /&gt;
    characters,&lt;br /&gt;
    characterTemplate,&lt;br /&gt;
    charactersContainer,&lt;br /&gt;
    battle&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  editAndSetCharacterPseudoInput(selectedCharacter, spanInput);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleFocus() {&lt;br /&gt;
  var tooltipLinks = document.querySelectorAll(&amp;quot;div.tooltip a&amp;quot;);&lt;br /&gt;
  tooltipLinks.forEach(function (link) {&lt;br /&gt;
    link.setAttribute(&amp;quot;tabindex&amp;quot;, -1);&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function resetBonusVariation(bonusVariation) {&lt;br /&gt;
  function resetInput(input) {&lt;br /&gt;
    input.removeAttribute(&amp;quot;min&amp;quot;);&lt;br /&gt;
    input.removeAttribute(&amp;quot;max&amp;quot;);&lt;br /&gt;
    input.defaultValue = 0;&lt;br /&gt;
    input.value = input.defaultValue;&lt;br /&gt;
  }&lt;br /&gt;
  var { minValue, maxValue, checkbox, container, disabledText, selectedText } =&lt;br /&gt;
    bonusVariation;&lt;br /&gt;
&lt;br /&gt;
  resetInput(minValue);&lt;br /&gt;
  resetInput(maxValue);&lt;br /&gt;
  showElement(disabledText);&lt;br /&gt;
  hideElement(selectedText);&lt;br /&gt;
  hideElement(container);&lt;br /&gt;
  checkbox.checked = false;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleBonusVariationUpdate(&lt;br /&gt;
  characterCreation,&lt;br /&gt;
  bonusVariation,&lt;br /&gt;
  resetSkill&lt;br /&gt;
) {&lt;br /&gt;
  var selectedBonus = characterCreation.bonusVariation.value;&lt;br /&gt;
  var displayName = characterCreation.bonusVariationName.value;&lt;br /&gt;
&lt;br /&gt;
  if (&lt;br /&gt;
    resetSkill &amp;amp;&amp;amp;&lt;br /&gt;
    (selectedBonus.startsWith(&amp;quot;attackSkill&amp;quot;) ||&lt;br /&gt;
      selectedBonus.startsWith(&amp;quot;horseSkill&amp;quot;) ||&lt;br /&gt;
      selectedBonus.startsWith(&amp;quot;skillBonus&amp;quot;))&lt;br /&gt;
  ) {&lt;br /&gt;
    resetBonusVariation(bonusVariation);&lt;br /&gt;
    return;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (&lt;br /&gt;
    characterCreation.hasOwnProperty(selectedBonus) &amp;amp;&amp;amp;&lt;br /&gt;
    selectedBonus != 0 &amp;amp;&amp;amp;&lt;br /&gt;
    displayName != 0&lt;br /&gt;
  ) {&lt;br /&gt;
    handleBonusVariation(&lt;br /&gt;
      characterCreation[selectedBonus],&lt;br /&gt;
      bonusVariation,&lt;br /&gt;
      displayName&lt;br /&gt;
    );&lt;br /&gt;
  } else {&lt;br /&gt;
    resetBonusVariation(bonusVariation);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getTargetContent(targetParent, targetName, isSkill) {&lt;br /&gt;
  var targetContent = &amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  if (targetParent.children.length &amp;lt;= 1) {&lt;br /&gt;
    targetContent = targetParent.textContent;&lt;br /&gt;
  } else if (targetName === &amp;quot;weaponUpgrade&amp;quot;) {&lt;br /&gt;
    targetContent = targetParent.children[1].textContent;&lt;br /&gt;
  } else if (targetName === &amp;quot;level&amp;quot;) {&lt;br /&gt;
    targetContent = targetParent.textContent.replace(&amp;quot;Lv&amp;quot;, &amp;quot;&amp;quot;).trim();&lt;br /&gt;
  } else if (isSkill) {&lt;br /&gt;
    var container = targetParent.children[1];&lt;br /&gt;
&lt;br /&gt;
    for (var index = 0; index &amp;lt; container.children.length; index++) {&lt;br /&gt;
      var element = container.children[index];&lt;br /&gt;
&lt;br /&gt;
      if (element.checkVisibility()) {&lt;br /&gt;
        targetContent += element.textContent;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    for (var index = 1; index &amp;lt; targetParent.children.length; index++) {&lt;br /&gt;
      var element = targetParent.children[index];&lt;br /&gt;
&lt;br /&gt;
      if (element.checkVisibility()) {&lt;br /&gt;
        targetContent += element.textContent;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return targetContent.trim();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleBonusVariation(target, bonusVariation, displayName) {&lt;br /&gt;
  var {&lt;br /&gt;
    minValue,&lt;br /&gt;
    maxValue,&lt;br /&gt;
    checkbox,&lt;br /&gt;
    container,&lt;br /&gt;
    disabledText,&lt;br /&gt;
    selectedText,&lt;br /&gt;
    displaySpan,&lt;br /&gt;
  } = bonusVariation;&lt;br /&gt;
&lt;br /&gt;
  var {&lt;br /&gt;
    min: targetMin,&lt;br /&gt;
    max: targetMax,&lt;br /&gt;
    name: targetName,&lt;br /&gt;
    value: targetValue,&lt;br /&gt;
    parentElement: targetParent,&lt;br /&gt;
    tagName,&lt;br /&gt;
  } = target;&lt;br /&gt;
&lt;br /&gt;
  targetMin = Number(targetMin);&lt;br /&gt;
  targetMax = Number(targetMax);&lt;br /&gt;
  targetValue = Number(targetValue);&lt;br /&gt;
&lt;br /&gt;
  var isSkill = tagName === &amp;quot;SELECT&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  if (isSkill) {&lt;br /&gt;
    var options = target.options;&lt;br /&gt;
&lt;br /&gt;
    targetMin = options[0].value;&lt;br /&gt;
    targetMax = options[options.length - 1].value;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  minValue.min = targetMin;&lt;br /&gt;
  minValue.max = targetMax;&lt;br /&gt;
  minValue.defaultValue = targetMin;&lt;br /&gt;
&lt;br /&gt;
  maxValue.min = targetMin;&lt;br /&gt;
  maxValue.max = targetMax;&lt;br /&gt;
  maxValue.defaultValue = targetMin;&lt;br /&gt;
&lt;br /&gt;
  hideElement(disabledText);&lt;br /&gt;
  showElement(selectedText);&lt;br /&gt;
&lt;br /&gt;
  if (displayName) {&lt;br /&gt;
    minValue.value = Math.min(Math.max(minValue.value, targetMin), targetMax);&lt;br /&gt;
    maxValue.value = Math.max(Math.min(maxValue.value, targetMax), targetMin);&lt;br /&gt;
&lt;br /&gt;
    displaySpan.textContent = displayName;&lt;br /&gt;
  } else {&lt;br /&gt;
    var { input, inputName, tabButton } = bonusVariation;&lt;br /&gt;
    var targetContent = getTargetContent(targetParent, targetName, isSkill);&lt;br /&gt;
&lt;br /&gt;
    input.value = targetName;&lt;br /&gt;
    inputName.value = targetContent;&lt;br /&gt;
    displaySpan.textContent = targetContent;&lt;br /&gt;
&lt;br /&gt;
    minValue.value = Math.max(targetValue - 10, targetMin);&lt;br /&gt;
    maxValue.value = Math.min(targetValue + 10, targetMax);&lt;br /&gt;
&lt;br /&gt;
    showElement(container);&lt;br /&gt;
    checkbox.checked = true;&lt;br /&gt;
&lt;br /&gt;
    tabButton.click();&lt;br /&gt;
    tabButton.scrollIntoView(true);&lt;br /&gt;
&lt;br /&gt;
    input.dispatchEvent(newChangeEvent());&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function characterManagement(characters, battle) {&lt;br /&gt;
  var {&lt;br /&gt;
    newCharacterTemplate: characterTemplate,&lt;br /&gt;
    charactersContainer,&lt;br /&gt;
    addNewCharacterButton,&lt;br /&gt;
    saveButton,&lt;br /&gt;
    characterCreation,&lt;br /&gt;
    bonusVariation,&lt;br /&gt;
    defaultText: { unsavedWarning },&lt;br /&gt;
  } = characters;&lt;br /&gt;
&lt;br /&gt;
  Object.keys(characters.savedCharacters).forEach(function (pseudo) {&lt;br /&gt;
    handleNewCharacter(&lt;br /&gt;
      characters,&lt;br /&gt;
      characterTemplate,&lt;br /&gt;
      charactersContainer,&lt;br /&gt;
      battle,&lt;br /&gt;
      pseudo&lt;br /&gt;
    );&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  addNewCharacterButton.addEventListener(&amp;quot;click&amp;quot;, function (event) {&lt;br /&gt;
    if (!characters.unsavedChanges) {&lt;br /&gt;
      addNewCharacter(&lt;br /&gt;
        characters,&lt;br /&gt;
        characterTemplate,&lt;br /&gt;
        charactersContainer,&lt;br /&gt;
        battle&lt;br /&gt;
      );&lt;br /&gt;
    } else {&lt;br /&gt;
      var result = confirm(unsavedWarning);&lt;br /&gt;
&lt;br /&gt;
      if (result) {&lt;br /&gt;
        addNewCharacter(&lt;br /&gt;
          characters,&lt;br /&gt;
          characterTemplate,&lt;br /&gt;
          charactersContainer,&lt;br /&gt;
          battle&lt;br /&gt;
        );&lt;br /&gt;
        saveButtonGreen(saveButton);&lt;br /&gt;
        characters.unsavedChanges = false;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  handleUploadCharacter(&lt;br /&gt;
    characters,&lt;br /&gt;
    characterTemplate,&lt;br /&gt;
    charactersContainer,&lt;br /&gt;
    battle&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  function handleLongPress(target) {&lt;br /&gt;
    if (target.tagName !== &amp;quot;INPUT&amp;quot; &amp;amp;&amp;amp; target.tagName !== &amp;quot;SELECT&amp;quot;) {&lt;br /&gt;
      target = target.querySelector(&amp;quot;input&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      !target ||&lt;br /&gt;
      (target.type !== &amp;quot;number&amp;quot; &amp;amp;&amp;amp;&lt;br /&gt;
        !target.classList.contains(&amp;quot;skill-select&amp;quot;) &amp;amp;&amp;amp;&lt;br /&gt;
        target.name !== &amp;quot;weaponUpgrade&amp;quot;) ||&lt;br /&gt;
      target.classList.contains(&amp;quot;disabled-variation&amp;quot;)&lt;br /&gt;
    ) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    handleBonusVariation(target, bonusVariation, null);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;click&amp;quot;, function (event) {&lt;br /&gt;
    if (event.shiftKey || event.ctrlKey) {&lt;br /&gt;
      handleLongPress(event.target);&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  var longPressTimer;&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;touchstart&amp;quot;, function (event) {&lt;br /&gt;
    longPressTimer = setTimeout(function () {&lt;br /&gt;
      handleLongPress(event.target);&lt;br /&gt;
    }, 800);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;touchend&amp;quot;, function () {&lt;br /&gt;
    clearTimeout(longPressTimer);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;touchmove&amp;quot;, function () {&lt;br /&gt;
    clearTimeout(longPressTimer);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  filterForm(characters, battle);&lt;br /&gt;
  characterCreationListener(characters, battle);&lt;br /&gt;
  handleFocus();&lt;br /&gt;
&lt;br /&gt;
  window.addEventListener(&amp;quot;beforeunload&amp;quot;, function (event) {&lt;br /&gt;
    if (characters.unsavedChanges) {&lt;br /&gt;
      event.preventDefault();&lt;br /&gt;
      return &amp;quot;&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addMonsterElement(characters, battle, monsterVnum, iframeInfo) {&lt;br /&gt;
  var { monsterTemplate, monstersContainer } = characters;&lt;br /&gt;
  var monsterElement = monsterTemplate.cloneNode(true);&lt;br /&gt;
  var spanInput = monsterElement.querySelector(&amp;quot;span.input&amp;quot;);&lt;br /&gt;
  var deleteSvg = monsterElement.querySelector(&amp;quot;svg&amp;quot;);&lt;br /&gt;
  var monsterName = getMonsterName(monsterVnum);&lt;br /&gt;
  var displayName = characters.translateMonsters&lt;br /&gt;
    ? getTranslatedMonsterName(monsterVnum)&lt;br /&gt;
    : monsterName;&lt;br /&gt;
  var link = createWikiLink(monsterName, displayName);&lt;br /&gt;
&lt;br /&gt;
  monsterElement.setAttribute(&amp;quot;tabindex&amp;quot;, &amp;quot;0&amp;quot;);&lt;br /&gt;
  spanInput.appendChild(link);&lt;br /&gt;
  monstersContainer.appendChild(monsterElement);&lt;br /&gt;
  characters.monsterElements[monsterVnum] = monsterElement;&lt;br /&gt;
&lt;br /&gt;
  deleteSvg.addEventListener(&amp;quot;click&amp;quot;, function () {&lt;br /&gt;
    var monster = characters.savedMonsters[monsterVnum];&lt;br /&gt;
    iframeInfo[monster.category].shouldBeUpdated = true;&lt;br /&gt;
&lt;br /&gt;
    deleteMonster(characters, battle, monsterVnum);&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addNewMonster(&lt;br /&gt;
  characters,&lt;br /&gt;
  battle,&lt;br /&gt;
  monsterVnum,&lt;br /&gt;
  monsterImage,&lt;br /&gt;
  iframeInfo,&lt;br /&gt;
  category&lt;br /&gt;
) {&lt;br /&gt;
  if (isValueInArray(monsterVnum, Object.keys(characters.savedMonsters)))&lt;br /&gt;
    return;&lt;br /&gt;
&lt;br /&gt;
  var newMonster = {&lt;br /&gt;
    image: monsterImage,&lt;br /&gt;
    category: category,&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  characters.savedMonsters[monsterVnum] = newMonster;&lt;br /&gt;
&lt;br /&gt;
  addMonsterElement(characters, battle, monsterVnum, iframeInfo);&lt;br /&gt;
  updateSavedMonsters(characters.savedMonsters);&lt;br /&gt;
  addBattleChoice(battle.battleChoice, monsterVnum, newMonster, true);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function translateiFrame(iframeDoc) {&lt;br /&gt;
  const filterName = iframeDoc.getElementById(&amp;quot;filter-name&amp;quot;);&lt;br /&gt;
  const { general, special } = translation;&lt;br /&gt;
  const translatedPlaceholder = special.placeholder;&lt;br /&gt;
&lt;br /&gt;
  if (filterName &amp;amp;&amp;amp; translatedPlaceholder) {&lt;br /&gt;
    filterName.placeholder = translatedPlaceholder;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (const element of iframeDoc.querySelectorAll(&amp;quot;[data-t]&amp;quot;)) {&lt;br /&gt;
    const translateText = general[element.dataset.t];&lt;br /&gt;
&lt;br /&gt;
    if (translateText) {&lt;br /&gt;
      element.textContent = translateText;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function translateMonsterCard(card, cardNameElement, monsterVnum) {&lt;br /&gt;
  const mapping = translation.mapping;&lt;br /&gt;
  const levelElement = card.querySelector(&amp;quot;[data-level]&amp;quot;);&lt;br /&gt;
  const typeElement = card.querySelector(&amp;quot;[data-type] a&amp;quot;);&lt;br /&gt;
  const damageElements = card.querySelectorAll(&amp;quot;[data-damage] a&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  cardNameElement.textContent = getTranslatedMonsterName(monsterVnum);&lt;br /&gt;
&lt;br /&gt;
  levelElement.textContent = levelElement.textContent.replace(&lt;br /&gt;
    &amp;quot;Boss&amp;quot;,&lt;br /&gt;
    translation.special.boss&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  if (typeElement) {&lt;br /&gt;
    typeElement.textContent = mapping[typeElement.textContent];&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  damageElements.forEach((damageElement) =&amp;gt; {&lt;br /&gt;
    damageElement.textContent = mapping[damageElement.textContent];&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addButtonsToCardsAndTranslate(&lt;br /&gt;
  characters,&lt;br /&gt;
  iframeDoc,&lt;br /&gt;
  iframeInfo,&lt;br /&gt;
  category&lt;br /&gt;
) {&lt;br /&gt;
  const buttonTemplates = characters.monsterButtonTemplates.children[0];&lt;br /&gt;
  const cardToEdit = iframeDoc.getElementById(&amp;quot;cards-container&amp;quot;).children;&lt;br /&gt;
  const { nameToVnum } = iframeInfo;&lt;br /&gt;
  const vnumToButtons = iframeInfo[category].vnumToButtons;&lt;br /&gt;
  const translateMonsters = characters.translateMonsters;&lt;br /&gt;
&lt;br /&gt;
  for (let cardIndex = 0; cardIndex &amp;lt; cardToEdit.length; cardIndex++) {&lt;br /&gt;
    const card = cardToEdit[cardIndex];&lt;br /&gt;
    const cardNameElement = card.querySelector(&amp;quot;[data-name]&amp;quot;).firstChild;&lt;br /&gt;
    const buttonTemplatesClone = buttonTemplates.cloneNode(true);&lt;br /&gt;
    const cardName = cardNameElement.title.replace(/\s/g, &amp;quot; &amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (!nameToVnum.hasOwnProperty(cardName)) {&lt;br /&gt;
      card.style.display = &amp;quot;none&amp;quot;;&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    const monsterVnum = nameToVnum[cardName];&lt;br /&gt;
&lt;br /&gt;
    buttonTemplatesClone.dataset.monsterId = monsterVnum;&lt;br /&gt;
    card.lastElementChild.appendChild(buttonTemplatesClone);&lt;br /&gt;
    vnumToButtons[monsterVnum] = buttonTemplatesClone.children;&lt;br /&gt;
&lt;br /&gt;
    if (translateMonsters) {&lt;br /&gt;
      translateMonsterCard(card, cardNameElement, monsterVnum);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (translateMonsters) {&lt;br /&gt;
    translateiFrame(iframeDoc);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateiFrameButtons(characters, iframeInfo, category) {&lt;br /&gt;
  var addedMonsters = Object.keys(characters.savedMonsters);&lt;br /&gt;
  var { currentiFrameIsMonster } = iframeInfo;&lt;br /&gt;
  var vnumToButtons = iframeInfo[category].vnumToButtons;&lt;br /&gt;
  var isPolymorphModal = category === &amp;quot;monster&amp;quot; &amp;amp;&amp;amp; !currentiFrameIsMonster;&lt;br /&gt;
&lt;br /&gt;
  for (var monsterVnum in vnumToButtons) {&lt;br /&gt;
    var [addButton, deleteButton, selectButton] = vnumToButtons[monsterVnum];&lt;br /&gt;
&lt;br /&gt;
    if (isPolymorphModal) {&lt;br /&gt;
      hideElement(addButton);&lt;br /&gt;
      hideElement(deleteButton);&lt;br /&gt;
      showElement(selectButton);&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isValueInArray(monsterVnum, addedMonsters)) {&lt;br /&gt;
      hideElement(addButton);&lt;br /&gt;
      showElement(deleteButton);&lt;br /&gt;
      hideElement(selectButton);&lt;br /&gt;
    } else {&lt;br /&gt;
      showElement(addButton);&lt;br /&gt;
      hideElement(deleteButton);&lt;br /&gt;
      hideElement(selectButton);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  iframeInfo.lastiFrameIsMonster = currentiFrameIsMonster;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getMonsterImage(buttonsContainer) {&lt;br /&gt;
  var elder = buttonsContainer.parentElement.firstElementChild;&lt;br /&gt;
  var image = elder.querySelector(&amp;quot;img&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (image) {&lt;br /&gt;
    return image.getAttribute(&amp;quot;src&amp;quot;) || &amp;quot;&amp;quot;;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return &amp;quot;&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleiFrame(iframeInfo, category) {&lt;br /&gt;
  var { characters, battle } = iframeInfo;&lt;br /&gt;
  var iframeInfoCategory = iframeInfo[category];&lt;br /&gt;
  var { iframe, pageName, vnumToButtons } = iframeInfoCategory;&lt;br /&gt;
  var loadingAnimation = iframeInfoCategory.iframe.previousElementSibling;&lt;br /&gt;
&lt;br /&gt;
  iframe.src = mw.util.getUrl(pageName);&lt;br /&gt;
&lt;br /&gt;
  window.addEventListener(&amp;quot;message&amp;quot;, function (event) {&lt;br /&gt;
    if (&lt;br /&gt;
      event.origin !== window.origin ||&lt;br /&gt;
      event.data?.type !== &amp;quot;filterReady&amp;quot; ||&lt;br /&gt;
      event.data.category !== category&lt;br /&gt;
    ) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
    var iframeDoc = iframe.contentDocument || iframe.contentWindow.document;&lt;br /&gt;
    var htmlElement = iframeDoc.documentElement;&lt;br /&gt;
    var iframeBody = iframeDoc.body;&lt;br /&gt;
    var content = iframeDoc.getElementById(&amp;quot;show-after-loading&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    htmlElement.setAttribute(&amp;quot;lang&amp;quot;, characters.currentLanguage);&lt;br /&gt;
    iframeBody.firstElementChild.replaceWith(content);&lt;br /&gt;
&lt;br /&gt;
    iframeBody.style.background = &amp;quot;transparent&amp;quot;;&lt;br /&gt;
    iframeBody.style.paddingRight = &amp;quot;10px&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    addButtonsToCardsAndTranslate(characters, iframeDoc, iframeInfo, category);&lt;br /&gt;
    updateiFrameButtons(characters, iframeInfo, category);&lt;br /&gt;
&lt;br /&gt;
    iframeInfoCategory.loadIsFinished = true;&lt;br /&gt;
&lt;br /&gt;
    hideElement(loadingAnimation);&lt;br /&gt;
    showElement(iframe);&lt;br /&gt;
&lt;br /&gt;
    iframeDoc.addEventListener(&amp;quot;click&amp;quot;, handleButtonClick);&lt;br /&gt;
&lt;br /&gt;
    function handleButtonClick(event) {&lt;br /&gt;
      var target = event.target;&lt;br /&gt;
      var link = target.closest(&amp;quot;a&amp;quot;);&lt;br /&gt;
      var buttonsContainer = target.closest(&amp;quot;.handle-monster&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
      if (link) {&lt;br /&gt;
        event.preventDefault();&lt;br /&gt;
        window.open(link.href, &amp;quot;_blank&amp;quot;);&lt;br /&gt;
      } else if (buttonsContainer) {&lt;br /&gt;
        var { monsterId: monsterVnum } = buttonsContainer.dataset;&lt;br /&gt;
&lt;br /&gt;
        // polymorph iframe&lt;br /&gt;
        if (category === &amp;quot;monster&amp;quot; &amp;amp;&amp;amp; !iframeInfo.currentiFrameIsMonster) {&lt;br /&gt;
          var monsterImage = getMonsterImage(buttonsContainer);&lt;br /&gt;
          changePolymorphValues(&lt;br /&gt;
            characters.characterCreation,&lt;br /&gt;
            monsterVnum,&lt;br /&gt;
            monsterImage&lt;br /&gt;
          );&lt;br /&gt;
          handlePolymorphDisplay(characters, monsterVnum, monsterImage);&lt;br /&gt;
          iframe.dispatchEvent(newChangeEvent());&lt;br /&gt;
        } else {&lt;br /&gt;
          var addedMonsters = Object.keys(characters.savedMonsters);&lt;br /&gt;
          var [addButton, deleteButton] = vnumToButtons[monsterVnum];&lt;br /&gt;
&lt;br /&gt;
          if (isValueInArray(monsterVnum, addedMonsters)) {&lt;br /&gt;
            deleteMonster(characters, battle, monsterVnum);&lt;br /&gt;
            showElement(addButton);&lt;br /&gt;
            hideElement(deleteButton);&lt;br /&gt;
          } else {&lt;br /&gt;
            var monsterImage = getMonsterImage(buttonsContainer);&lt;br /&gt;
            addNewMonster(&lt;br /&gt;
              characters,&lt;br /&gt;
              battle,&lt;br /&gt;
              monsterVnum,&lt;br /&gt;
              monsterImage,&lt;br /&gt;
              iframeInfo,&lt;br /&gt;
              category&lt;br /&gt;
            );&lt;br /&gt;
            hideElement(addButton);&lt;br /&gt;
            showElement(deleteButton);&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getNameToVnumMapping() {&lt;br /&gt;
  var nameToVnum = {};&lt;br /&gt;
&lt;br /&gt;
  for (var monsterVnum in monsterData) {&lt;br /&gt;
    nameToVnum[monsterData[monsterVnum][monsterData[monsterVnum].length - 1]] =&lt;br /&gt;
      monsterVnum;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return nameToVnum;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function monsterManagement(characters, battle) {&lt;br /&gt;
  var { monsteriFrame, stoneiFrame } = characters;&lt;br /&gt;
  var monsterVnums = Object.keys(monsterData);&lt;br /&gt;
&lt;br /&gt;
  var iframeInfo = {&lt;br /&gt;
    lastiFrameIsMonster: false,&lt;br /&gt;
    currentiFrameIsMonster: false,&lt;br /&gt;
    characters: characters,&lt;br /&gt;
    battle: battle,&lt;br /&gt;
    nameToVnum: getNameToVnumMapping(),&lt;br /&gt;
    monster: {&lt;br /&gt;
      isLoaded: false,&lt;br /&gt;
      loadIsFinished: false,&lt;br /&gt;
      shouldBeUpdated: false,&lt;br /&gt;
      vnumToButtons: {},&lt;br /&gt;
      pageName: &amp;quot;Monstres&amp;quot;,&lt;br /&gt;
      iframe: monsteriFrame,&lt;br /&gt;
    },&lt;br /&gt;
    stone: {&lt;br /&gt;
      isLoaded: false,&lt;br /&gt;
      loadIsFinished: false,&lt;br /&gt;
      shouldBeUpdated: false,&lt;br /&gt;
      vnumToButtons: {},&lt;br /&gt;
      pageName: &amp;quot;Pierres Metin&amp;quot;,&lt;br /&gt;
      iframe: stoneiFrame,&lt;br /&gt;
    },&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  document.addEventListener(&amp;quot;modalOpen&amp;quot;, function (event) {&lt;br /&gt;
    var modalName = event.detail.name;&lt;br /&gt;
&lt;br /&gt;
    if (modalName === &amp;quot;monster&amp;quot; || modalName === &amp;quot;stone&amp;quot;) {&lt;br /&gt;
      handleModal(event.target, modalName);&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  function handleModal(target, modalName) {&lt;br /&gt;
    var iframeInfoCategory = iframeInfo[modalName];&lt;br /&gt;
&lt;br /&gt;
    if (modalName === &amp;quot;monster&amp;quot;) {&lt;br /&gt;
      var isMonsteriFrame = target.id === &amp;quot;add-new-monster&amp;quot;;&lt;br /&gt;
      iframeInfo.currentiFrameIsMonster = isMonsteriFrame;&lt;br /&gt;
&lt;br /&gt;
      if (&lt;br /&gt;
        iframeInfoCategory.loadIsFinished &amp;amp;&amp;amp;&lt;br /&gt;
        ((isMonsteriFrame &amp;amp;&amp;amp; !iframeInfo.lastiFrameIsMonster) ||&lt;br /&gt;
          (!isMonsteriFrame &amp;amp;&amp;amp; iframeInfo.lastiFrameIsMonster))&lt;br /&gt;
      ) {&lt;br /&gt;
        iframeInfoCategory.shouldBeUpdated = true;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!iframeInfoCategory.isLoaded) {&lt;br /&gt;
      handleiFrame(iframeInfo, modalName);&lt;br /&gt;
      iframeInfoCategory.isLoaded = true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      iframeInfoCategory.loadIsFinished &amp;amp;&amp;amp;&lt;br /&gt;
      iframeInfoCategory.shouldBeUpdated&lt;br /&gt;
    ) {&lt;br /&gt;
      updateiFrameButtons(characters, iframeInfo, modalName);&lt;br /&gt;
      iframeInfoCategory.shouldBeUpdated = false;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  Object.keys(characters.savedMonsters)&lt;br /&gt;
    .slice()&lt;br /&gt;
    .forEach(function (monsterVnum) {&lt;br /&gt;
      if (isValueInArray(monsterVnum, monsterVnums)) {&lt;br /&gt;
        addMonsterElement(characters, battle, monsterVnum, iframeInfo);&lt;br /&gt;
      } else {&lt;br /&gt;
        deleteMonster(characters, battle, monsterVnum);&lt;br /&gt;
      }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function hideAttackType(container, input, attackType) {&lt;br /&gt;
  hideElement(container);&lt;br /&gt;
&lt;br /&gt;
  if (input.checked) {&lt;br /&gt;
    var defaultInput = attackType.defaultInput;&lt;br /&gt;
&lt;br /&gt;
    input.checked = false;&lt;br /&gt;
    defaultInput.checked = true;&lt;br /&gt;
    defaultInput.dispatchEvent(newChangeEvent());&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterAttackTypeSelectionCharacter(attacker, attackType) {&lt;br /&gt;
  var attackerClass = attacker.class;&lt;br /&gt;
  var attackerIsNotPolymorph = !isPolymorph(attacker);&lt;br /&gt;
  var { elements: attackTypeElements } = attackType;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; attackTypeElements.length; index++) {&lt;br /&gt;
    var { container, input, inputClass, inputValue } =&lt;br /&gt;
      attackTypeElements[index];&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      attackerIsNotPolymorph &amp;amp;&amp;amp;&lt;br /&gt;
      attacker[inputValue] &amp;amp;&amp;amp;&lt;br /&gt;
      (attackerClass === inputClass ||&lt;br /&gt;
        (inputValue.startsWith(&amp;quot;horseSkill&amp;quot;) &amp;amp;&amp;amp;&lt;br /&gt;
          isRiding(attacker) &amp;amp;&amp;amp;&lt;br /&gt;
          (!inputClass || isValueInArray(attackerClass, inputClass))))&lt;br /&gt;
    ) {&lt;br /&gt;
      showElement(container);&lt;br /&gt;
    } else {&lt;br /&gt;
      hideAttackType(container, input, attackType);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterAttackTypeSelectionMonster(attackType) {&lt;br /&gt;
  var attackTypeElements = attackType.elements;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; attackTypeElements.length; index++) {&lt;br /&gt;
    var { container, input } = attackTypeElements[index];&lt;br /&gt;
    hideAttackType(container, input, attackType);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function removeBattleElement(battleChoice, nameOrVnum, category, type) {&lt;br /&gt;
  var elements = battleChoice[category][type].elements;&lt;br /&gt;
&lt;br /&gt;
  if (elements.hasOwnProperty(nameOrVnum)) {&lt;br /&gt;
    elements[nameOrVnum].container.remove();&lt;br /&gt;
    delete elements[nameOrVnum];&lt;br /&gt;
    battleChoice[category][type].count--;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function removeBattleChoice(battleChoice, nameOrVnum, type) {&lt;br /&gt;
  battleChoice.categories.forEach(function (category) {&lt;br /&gt;
    if (category === &amp;quot;attacker&amp;quot; &amp;amp;&amp;amp; type === &amp;quot;stone&amp;quot;) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
    var selected = battleChoice[category].selected;&lt;br /&gt;
&lt;br /&gt;
    if (selected) {&lt;br /&gt;
      var { type: selectedType, nameOrVnum: selectedNameOrVnum } =&lt;br /&gt;
        parseTypeAndName(selected);&lt;br /&gt;
&lt;br /&gt;
      if (nameOrVnum === selectedNameOrVnum &amp;amp;&amp;amp; type === selectedType) {&lt;br /&gt;
        resetBattleChoiceButton(battleChoice, category);&lt;br /&gt;
        battleChoice[category].selected = null;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    removeBattleElement(battleChoice, nameOrVnum, category, type);&lt;br /&gt;
    updateBattleChoiceText(battleChoice, category, type);&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addBattleElement(&lt;br /&gt;
  battleChoice,&lt;br /&gt;
  pseudoOrVnum,&lt;br /&gt;
  characterOrMonster,&lt;br /&gt;
  category,&lt;br /&gt;
  isMonster&lt;br /&gt;
) {&lt;br /&gt;
  var { template, raceToImage, translateMonsters } = battleChoice;&lt;br /&gt;
  var battleChoiceCategory = battleChoice[category];&lt;br /&gt;
  var templateClone = template.cloneNode(true);&lt;br /&gt;
  var label = templateClone.firstElementChild;&lt;br /&gt;
  var [input, image, span] = label.children;&lt;br /&gt;
  var imageSrc;&lt;br /&gt;
  var name;&lt;br /&gt;
  var type;&lt;br /&gt;
&lt;br /&gt;
  if (isMonster) {&lt;br /&gt;
    type = characterOrMonster.category;&lt;br /&gt;
&lt;br /&gt;
    if (type === &amp;quot;stone&amp;quot; &amp;amp;&amp;amp; category === &amp;quot;attacker&amp;quot;) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
    imageSrc = characterOrMonster.image;&lt;br /&gt;
    name = translateMonsters&lt;br /&gt;
      ? getTranslatedMonsterName(pseudoOrVnum)&lt;br /&gt;
      : getMonsterName(pseudoOrVnum);&lt;br /&gt;
  } else {&lt;br /&gt;
    type = &amp;quot;character&amp;quot;;&lt;br /&gt;
    imageSrc = raceToImage[characterOrMonster.race];&lt;br /&gt;
    name = pseudoOrVnum;&lt;br /&gt;
    label.classList.add(&amp;quot;notranslate&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var value = type + &amp;quot;-&amp;quot; + pseudoOrVnum;&lt;br /&gt;
  var id = category + &amp;quot;-&amp;quot; + value;&lt;br /&gt;
  var currentBattleChoice = battleChoiceCategory[type];&lt;br /&gt;
&lt;br /&gt;
  label.setAttribute(&amp;quot;for&amp;quot;, id);&lt;br /&gt;
  input.value = value;&lt;br /&gt;
  input.id = id;&lt;br /&gt;
  input.name = category;&lt;br /&gt;
  span.textContent = name;&lt;br /&gt;
&lt;br /&gt;
  handleImageFromWiki(image, imageSrc);&lt;br /&gt;
&lt;br /&gt;
  currentBattleChoice.container.appendChild(templateClone);&lt;br /&gt;
  currentBattleChoice.count++;&lt;br /&gt;
  currentBattleChoice.elements[pseudoOrVnum] = {&lt;br /&gt;
    container: templateClone,&lt;br /&gt;
    image: image,&lt;br /&gt;
    name: name,&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  updateBattleChoiceText(battleChoice, category, type);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addBattleChoice(&lt;br /&gt;
  battleChoice,&lt;br /&gt;
  pseudoOrVnum,&lt;br /&gt;
  characterOrMonster,&lt;br /&gt;
  isMonster = false&lt;br /&gt;
) {&lt;br /&gt;
  addBattleElement(&lt;br /&gt;
    battleChoice,&lt;br /&gt;
    pseudoOrVnum,&lt;br /&gt;
    characterOrMonster,&lt;br /&gt;
    &amp;quot;attacker&amp;quot;,&lt;br /&gt;
    isMonster&lt;br /&gt;
  );&lt;br /&gt;
  addBattleElement(&lt;br /&gt;
    battleChoice,&lt;br /&gt;
    pseudoOrVnum,&lt;br /&gt;
    characterOrMonster,&lt;br /&gt;
    &amp;quot;victim&amp;quot;,&lt;br /&gt;
    isMonster&lt;br /&gt;
  );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateBattleChoiceImage(battleChoice, characterName, newRace) {&lt;br /&gt;
  var imageSrc = battleChoice.raceToImage[newRace];&lt;br /&gt;
&lt;br /&gt;
  battleChoice.categories.forEach(function (category) {&lt;br /&gt;
    handleImageFromWiki(&lt;br /&gt;
      battleChoice[category].character.elements[characterName].image,&lt;br /&gt;
      imageSrc&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    var selected = battleChoice[category].selected;&lt;br /&gt;
&lt;br /&gt;
    if (isCharacterSelected(characterName, selected)) {&lt;br /&gt;
      updateBattleChoiceButton(battleChoice, category, selected);&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateBattleChoiceText(battleChoice, category, type) {&lt;br /&gt;
  var { count, container } = battleChoice[category][type];&lt;br /&gt;
  var parentContainer = container.parentElement;&lt;br /&gt;
&lt;br /&gt;
  if (count === 0) {&lt;br /&gt;
    hideElement(parentContainer);&lt;br /&gt;
    showElement(parentContainer.nextElementSibling);&lt;br /&gt;
  } else if (count === 1) {&lt;br /&gt;
    showElement(parentContainer);&lt;br /&gt;
    hideElement(parentContainer.nextElementSibling);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateBattleChoice(characters, battleChoice) {&lt;br /&gt;
  var templateImage = battleChoice.template.querySelector(&amp;quot;img&amp;quot;);&lt;br /&gt;
  var attackerImage = battleChoice.attacker.buttonContent.querySelector(&amp;quot;img&amp;quot;);&lt;br /&gt;
  var victimImage = battleChoice.victim.buttonContent.querySelector(&amp;quot;img&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  resetImageFromWiki(templateImage);&lt;br /&gt;
  resetImageFromWiki(attackerImage);&lt;br /&gt;
  resetImageFromWiki(victimImage);&lt;br /&gt;
&lt;br /&gt;
  for (var [pseudo, character] of Object.entries(characters.savedCharacters)) {&lt;br /&gt;
    addBattleChoice(battleChoice, pseudo, character);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (var [vnum, monster] of Object.entries(characters.savedMonsters)) {&lt;br /&gt;
    addBattleChoice(battleChoice, vnum, monster, true);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateBattleChoiceButton(battleChoice, category, data) {&lt;br /&gt;
  var battleChoiceCategory = battleChoice[category];&lt;br /&gt;
  var { defaultButtonContent, buttonContent } = battleChoiceCategory;&lt;br /&gt;
  var [buttonImage, buttonSpan] = buttonContent.firstElementChild.children;&lt;br /&gt;
  var { type, nameOrVnum } = parseTypeAndName(data);&lt;br /&gt;
  var { name, image } = battleChoiceCategory[type].elements[nameOrVnum];&lt;br /&gt;
&lt;br /&gt;
  hideElement(defaultButtonContent);&lt;br /&gt;
  showElement(buttonContent);&lt;br /&gt;
&lt;br /&gt;
  buttonSpan.textContent = name;&lt;br /&gt;
  buttonImage.src = image.src;&lt;br /&gt;
  battleChoiceCategory.selected = data;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function resetBattleChoiceButton(battleChoice, category) {&lt;br /&gt;
  var { defaultButtonContent, buttonContent } = battleChoice[category];&lt;br /&gt;
&lt;br /&gt;
  showElement(defaultButtonContent);&lt;br /&gt;
  hideElement(buttonContent);&lt;br /&gt;
&lt;br /&gt;
  if (category === &amp;quot;attacker&amp;quot;) {&lt;br /&gt;
    filterAttackTypeSelectionMonster(battleChoice.attackType);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isPC(character) {&lt;br /&gt;
  if (character.race === 0 || character.race === 1) {&lt;br /&gt;
    return false;&lt;br /&gt;
  }&lt;br /&gt;
  return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isBoss(character) {&lt;br /&gt;
  return character.race === 0 &amp;amp;&amp;amp; character.rank &amp;gt;= 5;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isStone(character) {&lt;br /&gt;
  return character.race === 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isMeleeAttacker(monster) {&lt;br /&gt;
  return monster.attack == 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isRangeAttacker(monster) {&lt;br /&gt;
  return monster.attack == 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isMagicAttacker(monster) {&lt;br /&gt;
  return monster.attack == 2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isMagicClass(character) {&lt;br /&gt;
  return character.race === &amp;quot;shaman&amp;quot; || character.class === &amp;quot;black_magic&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isDispell(character, skillId) {&lt;br /&gt;
  return character.class === &amp;quot;weaponary&amp;quot; &amp;amp;&amp;amp; skillId === 6;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isPolymorph(character) {&lt;br /&gt;
  return isChecked(character.isPolymorph);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isRiding(character) {&lt;br /&gt;
  return isChecked(character.isRiding);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isBow(weaponType) {&lt;br /&gt;
  return weaponType === 2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcAttackFactor(attacker, victim) {&lt;br /&gt;
  function calcCoeffK(dex, level) {&lt;br /&gt;
    return Math.min(90, Math.floor((2 * dex + level) / 3));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var K1 = calcCoeffK(attacker.polymorphDex, attacker.level);&lt;br /&gt;
  var K2 = calcCoeffK(victim.polymorphDex, attacker.level);&lt;br /&gt;
&lt;br /&gt;
  var AR = (K1 + 210) / 300;&lt;br /&gt;
  var ER = (((2 * K2 + 5) / (K2 + 95)) * 3) / 10;&lt;br /&gt;
&lt;br /&gt;
  return truncateNumber(AR - ER, 8);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcMainAttackValue(attacker) {&lt;br /&gt;
  var leadership = 0;&lt;br /&gt;
  var weaponGrowth = 0;&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker)) {&lt;br /&gt;
    weaponGrowth = attacker.weapon.growth;&lt;br /&gt;
    leadership = attacker.leadership;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return 2 * (attacker.level + weaponGrowth) + leadership;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcStatAttackValue(character) {&lt;br /&gt;
  switch (character.race) {&lt;br /&gt;
    case &amp;quot;warrior&amp;quot;:&lt;br /&gt;
    case &amp;quot;sura&amp;quot;:&lt;br /&gt;
      return 2 * character.str;&lt;br /&gt;
    case &amp;quot;ninja&amp;quot;:&lt;br /&gt;
      return Math.floor((1 / 4) * (character.str + 7 * character.dex));&lt;br /&gt;
    case &amp;quot;shaman&amp;quot;:&lt;br /&gt;
      return Math.floor((1 / 3) * (5 * character.int + character.dex));&lt;br /&gt;
    case &amp;quot;lycan&amp;quot;:&lt;br /&gt;
      return character.vit + 2 * character.dex;&lt;br /&gt;
    default:&lt;br /&gt;
      return 2 * character.str;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcPvpCriticalAttackRange(minAttackValue, maxAttackValue, growth) {&lt;br /&gt;
  return Array.from(&lt;br /&gt;
    { length: maxAttackValue - minAttackValue + 1 },&lt;br /&gt;
    (_, index) =&amp;gt; (minAttackValue + growth + index) * 2&lt;br /&gt;
  );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcSecondaryAttackValue(attacker, isPlayerVsPlayer) {&lt;br /&gt;
  let attackValueOther = 0;&lt;br /&gt;
&lt;br /&gt;
  let minAttackValue = 0;&lt;br /&gt;
  let maxAttackValue = 0;&lt;br /&gt;
&lt;br /&gt;
  let minAttackValueSlash = 0;&lt;br /&gt;
  let maxAttackValueSlash = 0;&lt;br /&gt;
&lt;br /&gt;
  let type, isSerpent, growth;&lt;br /&gt;
&lt;br /&gt;
  let criticalAttackRange;&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker)) {&lt;br /&gt;
    ({ type, isSerpent, minAttackValue, maxAttackValue, growth } =&lt;br /&gt;
      attacker.weapon);&lt;br /&gt;
&lt;br /&gt;
    if (isSerpent) {&lt;br /&gt;
      minAttackValue = Math.max(0, attacker.minAttackValueRandom - growth);&lt;br /&gt;
      maxAttackValue = Math.max(&lt;br /&gt;
        minAttackValue,&lt;br /&gt;
        attacker.maxAttackValueRandom - growth&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    minAttackValueSlash = Math.min(&lt;br /&gt;
      attacker.minAttackValueSlash,&lt;br /&gt;
      attacker.maxAttackValueSlash&lt;br /&gt;
    );&lt;br /&gt;
    maxAttackValueSlash = Math.max(&lt;br /&gt;
      attacker.minAttackValueSlash,&lt;br /&gt;
      attacker.maxAttackValueSlash&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    attackValueOther += attacker.attackValue;&lt;br /&gt;
&lt;br /&gt;
    if (isBow(type) &amp;amp;&amp;amp; !isPolymorph(attacker)) {&lt;br /&gt;
      attackValueOther += 25;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isPlayerVsPlayer) {&lt;br /&gt;
      criticalAttackRange = calcPvpCriticalAttackRange(&lt;br /&gt;
        minAttackValue,&lt;br /&gt;
        maxAttackValue,&lt;br /&gt;
        growth&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    minAttackValue = attacker.minAttackValue;&lt;br /&gt;
    maxAttackValue = attacker.maxAttackValue;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  minAttackValue += attacker.minAttackValuePolymorph;&lt;br /&gt;
  maxAttackValue += attacker.maxAttackValuePolymorph;&lt;br /&gt;
&lt;br /&gt;
  attackValueOther += attacker.statAttackValue;&lt;br /&gt;
  attackValueOther += attacker.horseAttackValue;&lt;br /&gt;
&lt;br /&gt;
  const weaponInterval = maxAttackValue - minAttackValue + 1;&lt;br /&gt;
  const slashInterval = maxAttackValueSlash - minAttackValueSlash + 1;&lt;br /&gt;
&lt;br /&gt;
  const totalCardinal = weaponInterval * slashInterval * 1_000_000;&lt;br /&gt;
  const minInterval = Math.min(weaponInterval, slashInterval);&lt;br /&gt;
&lt;br /&gt;
  minAttackValue += minAttackValueSlash;&lt;br /&gt;
  maxAttackValue += maxAttackValueSlash;&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    minAttackValue: minAttackValue,&lt;br /&gt;
    maxAttackValue: maxAttackValue,&lt;br /&gt;
    attackValueOther: attackValueOther,&lt;br /&gt;
    totalCardinal: totalCardinal,&lt;br /&gt;
    weights: calcWeights(minAttackValue, maxAttackValue, minInterval),&lt;br /&gt;
    possibleDamageCount: maxAttackValue - minAttackValue + 1,&lt;br /&gt;
    criticalAttackRange: criticalAttackRange,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcMagicAttackValue(attacker, isPlayerVsPlayer) {&lt;br /&gt;
  let minMagicAttackValueSlash = 0;&lt;br /&gt;
  let maxMagicAttackValueSlash = 0;&lt;br /&gt;
&lt;br /&gt;
  let criticalAttackRange;&lt;br /&gt;
&lt;br /&gt;
  let {&lt;br /&gt;
    isSerpent,&lt;br /&gt;
    minMagicAttackValue,&lt;br /&gt;
    maxMagicAttackValue,&lt;br /&gt;
    minAttackValue,&lt;br /&gt;
    maxAttackValue,&lt;br /&gt;
    growth,&lt;br /&gt;
  } = attacker.weapon;&lt;br /&gt;
&lt;br /&gt;
  if (isSerpent) {&lt;br /&gt;
    minMagicAttackValue = Math.max(0, attacker.minMagicAttackValueRandom);&lt;br /&gt;
    maxMagicAttackValue = Math.max(&lt;br /&gt;
      minMagicAttackValue,&lt;br /&gt;
      attacker.maxMagicAttackValueRandom&lt;br /&gt;
    );&lt;br /&gt;
    minAttackValue = Math.max(0, attacker.minAttackValueRandom - growth);&lt;br /&gt;
    maxAttackValue = Math.max(&lt;br /&gt;
      minAttackValue,&lt;br /&gt;
      attacker.maxAttackValueRandom - growth&lt;br /&gt;
    );&lt;br /&gt;
  } else {&lt;br /&gt;
    minMagicAttackValue += growth;&lt;br /&gt;
    maxMagicAttackValue += growth;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (isPlayerVsPlayer) {&lt;br /&gt;
    criticalAttackRange = calcPvpCriticalAttackRange(&lt;br /&gt;
      minAttackValue,&lt;br /&gt;
      maxAttackValue,&lt;br /&gt;
      growth&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  minMagicAttackValueSlash = Math.min(&lt;br /&gt;
    attacker.minMagicAttackValueSlash,&lt;br /&gt;
    attacker.maxMagicAttackValueSlash&lt;br /&gt;
  );&lt;br /&gt;
  maxMagicAttackValueSlash = Math.max(&lt;br /&gt;
    attacker.minMagicAttackValueSlash,&lt;br /&gt;
    attacker.maxMagicAttackValueSlash&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  const weaponInterval = maxMagicAttackValue - minMagicAttackValue + 1;&lt;br /&gt;
  const slashInterval = maxMagicAttackValueSlash - minMagicAttackValueSlash + 1;&lt;br /&gt;
&lt;br /&gt;
  const totalCardinal = weaponInterval * slashInterval * 1_000_000;&lt;br /&gt;
  const minInterval = Math.min(weaponInterval, slashInterval);&lt;br /&gt;
&lt;br /&gt;
  minMagicAttackValue += minMagicAttackValueSlash;&lt;br /&gt;
  maxMagicAttackValue += maxMagicAttackValueSlash;&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    minMagicAttackValue: minMagicAttackValue,&lt;br /&gt;
    maxMagicAttackValue: maxMagicAttackValue,&lt;br /&gt;
    magicAttackValueAugmentation: getMagicAttackValueAugmentation(&lt;br /&gt;
      minMagicAttackValue,&lt;br /&gt;
      maxMagicAttackValue,&lt;br /&gt;
      attacker.magicAttackValue&lt;br /&gt;
    ),&lt;br /&gt;
    totalCardinal: totalCardinal,&lt;br /&gt;
    weights: calcWeights(minMagicAttackValue, maxMagicAttackValue, minInterval),&lt;br /&gt;
    possibleDamageCount: maxMagicAttackValue - minMagicAttackValue + 1,&lt;br /&gt;
    criticalAttackRange: criticalAttackRange,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getPolymorphPower(polymorphPoint, polymorphPowerTable) {&lt;br /&gt;
  return polymorphPowerTable[polymorphPoint];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSkillPower(skillPoint, skillPowerTable) {&lt;br /&gt;
  return skillPowerTable[skillPoint];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getMarriageBonusValue(character, marriageTable, itemName) {&lt;br /&gt;
  let index;&lt;br /&gt;
  const lovePoint = character.lovePoint;&lt;br /&gt;
&lt;br /&gt;
  if (lovePoint &amp;lt; 65) {&lt;br /&gt;
    index = 0;&lt;br /&gt;
  } else if (lovePoint &amp;lt; 80) {&lt;br /&gt;
    index = 1;&lt;br /&gt;
  } else if (lovePoint &amp;lt; 100) {&lt;br /&gt;
    index = 2;&lt;br /&gt;
  } else {&lt;br /&gt;
    index = 3;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return marriageTable[itemName][index];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcDamageWithPrimaryBonuses(damage, bonusValues) {&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.attackValueCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  damage += bonusValues.attackValueMarriage;&lt;br /&gt;
&lt;br /&gt;
  damage = Math.floor(&lt;br /&gt;
    (damage * bonusValues.monsterResistanceMarriageCoeff) / 100&lt;br /&gt;
  );&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.monsterResistanceCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  damage += Math.floor((damage * bonusValues.typeBonusCoeff) / 100);&lt;br /&gt;
  damage +=&lt;br /&gt;
    Math.floor((damage * bonusValues.raceBonusCoeff) / 100) -&lt;br /&gt;
    Math.floor((damage * bonusValues.raceResistanceCoeff) / 100);&lt;br /&gt;
  damage += Math.floor((damage * bonusValues.stoneBonusCoeff) / 100);&lt;br /&gt;
  damage += Math.floor((damage * bonusValues.monsterBonusCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  const elementBonusCoeff = bonusValues.elementBonusCoeff;&lt;br /&gt;
&lt;br /&gt;
  damage +=&lt;br /&gt;
    Math.trunc((damage * elementBonusCoeff[0]) / 10000) +&lt;br /&gt;
    Math.trunc((damage * elementBonusCoeff[1]) / 10000) +&lt;br /&gt;
    Math.trunc((damage * elementBonusCoeff[2]) / 10000) +&lt;br /&gt;
    Math.trunc((damage * elementBonusCoeff[3]) / 10000) +&lt;br /&gt;
    Math.trunc((damage * elementBonusCoeff[4]) / 10000) +&lt;br /&gt;
    Math.trunc((damage * elementBonusCoeff[5]) / 10000);&lt;br /&gt;
&lt;br /&gt;
  damage = Math.floor(damage * bonusValues.damageMultiplier);&lt;br /&gt;
&lt;br /&gt;
  return Math.max(0, damage);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcFinalDamage(&lt;br /&gt;
  finalDamage,&lt;br /&gt;
  damageWithPrimaryBonuses,&lt;br /&gt;
  bonusValues,&lt;br /&gt;
  criticalAttackRange,&lt;br /&gt;
  damageByType&lt;br /&gt;
) {&lt;br /&gt;
  for (let criticalIndex = 0; criticalIndex &amp;lt; 2; criticalIndex++) {&lt;br /&gt;
    if (bonusValues.skipCriticalStep[criticalIndex]) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
    let beforeCriticalDamage = finalDamage;&lt;br /&gt;
    let damageValues = criticalIndex&lt;br /&gt;
      ? criticalAttackRange || [finalDamage]&lt;br /&gt;
      : [0];&lt;br /&gt;
&lt;br /&gt;
    for (let index = 0, len = damageValues.length; index &amp;lt; len; index++) {&lt;br /&gt;
      let afterCriticalDamage = beforeCriticalDamage + damageValues[index];&lt;br /&gt;
&lt;br /&gt;
      for (let piercingIndex = 0; piercingIndex &amp;lt; 2; piercingIndex++) {&lt;br /&gt;
        if (bonusValues.skipPiercingStep[piercingIndex]) {&lt;br /&gt;
          continue;&lt;br /&gt;
        }&lt;br /&gt;
        let damage = afterCriticalDamage;&lt;br /&gt;
&lt;br /&gt;
        if (piercingIndex) {&lt;br /&gt;
          damage += Math.min(&lt;br /&gt;
            bonusValues.defenseBoost,&lt;br /&gt;
            damageWithPrimaryBonuses&lt;br /&gt;
          );&lt;br /&gt;
          damage += Math.floor(&lt;br /&gt;
            (damageWithPrimaryBonuses * bonusValues.extraPiercingHitCoeff) /&lt;br /&gt;
              1000&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        damage = Math.floor((damage * bonusValues.averageDamageCoeff) / 100);&lt;br /&gt;
        damage = Math.floor(&lt;br /&gt;
          (damage * bonusValues.averageDamageResistanceCoeff) / 100&lt;br /&gt;
        );&lt;br /&gt;
        damage = Math.floor((damage * bonusValues.skillDamageCoeff) / 100);&lt;br /&gt;
        damage = Math.floor(&lt;br /&gt;
          (damage * bonusValues.skillDamageResistanceCoeff) / 100&lt;br /&gt;
        );&lt;br /&gt;
        damage = Math.floor((damage * bonusValues.rankBonusCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
        if (bonusValues.useDarkProtection) {&lt;br /&gt;
          const { darkProtectionPoint, darkProtectionSp } = bonusValues;&lt;br /&gt;
&lt;br /&gt;
          const damageReduction = Math.floor(damage / 3);&lt;br /&gt;
          const spAbsorption = Math.floor(&lt;br /&gt;
            (damageReduction * darkProtectionPoint) / 100&lt;br /&gt;
          );&lt;br /&gt;
&lt;br /&gt;
          if (spAbsorption &amp;lt;= darkProtectionSp) {&lt;br /&gt;
            damage -= damageReduction;&lt;br /&gt;
          } else {&lt;br /&gt;
            damage -= Math.floor(&lt;br /&gt;
              (darkProtectionSp * 100) / darkProtectionPoint&lt;br /&gt;
            );&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        damage -= Math.floor(&lt;br /&gt;
          (damage * bonusValues.resistance90PercentHp) / 100&lt;br /&gt;
        );&lt;br /&gt;
        damage = Math.max(0, damage + bonusValues.defensePercent);&lt;br /&gt;
        damage += Math.min(&lt;br /&gt;
          300,&lt;br /&gt;
          Math.floor((damage * bonusValues.damageBonusCoeff) / 100)&lt;br /&gt;
        );&lt;br /&gt;
        damage = Math.floor((damage * bonusValues.empireMalusCoeff) / 10);&lt;br /&gt;
        damage = Math.floor((damage * bonusValues.sungMaStrBonusCoeff) / 10000);&lt;br /&gt;
        damage -= Math.floor(damage * bonusValues.sungmaStrMalusCoeff);&lt;br /&gt;
        damage = Math.floor(&lt;br /&gt;
          (damage * bonusValues.whiteDragonElixirCoeff) / 100&lt;br /&gt;
        );&lt;br /&gt;
        damage = Math.floor(&lt;br /&gt;
          (damage * bonusValues.steelDragonElixirCoeff) / 100&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        damageByType[criticalIndex + 2 * piercingIndex].push(damage);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveFinalDamage(&lt;br /&gt;
  damage,&lt;br /&gt;
  damageWithPrimaryBonuses,&lt;br /&gt;
  bonusValues,&lt;br /&gt;
  criticalAttackRange,&lt;br /&gt;
  damageByType&lt;br /&gt;
) {&lt;br /&gt;
  damage = Math.floor(damage * bonusValues.magicResistanceCoeff);&lt;br /&gt;
  damage = Math.trunc((damage * bonusValues.weaponDefenseCoeff) / 100);&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.tigerStrengthCoeff) / 100);&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.berserkBonusCoeff) / 100);&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.fearBonusCoeff) / 100);&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.blessingBonusCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  calcFinalDamage(&lt;br /&gt;
    damage,&lt;br /&gt;
    damageWithPrimaryBonuses,&lt;br /&gt;
    bonusValues,&lt;br /&gt;
    criticalAttackRange,&lt;br /&gt;
    damageByType&lt;br /&gt;
  );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveFinalSkillDamage(&lt;br /&gt;
  damage,&lt;br /&gt;
  bonusValues,&lt;br /&gt;
  criticalAttackRange,&lt;br /&gt;
  damageByType&lt;br /&gt;
) {&lt;br /&gt;
  damage = Math.floor(damage * bonusValues.magicResistanceCoeff);&lt;br /&gt;
  damage = Math.trunc((damage * bonusValues.weaponDefenseCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  damage -= bonusValues.defense;&lt;br /&gt;
&lt;br /&gt;
  const damageValues =&lt;br /&gt;
    damage &amp;lt;= 2 &amp;amp;&amp;amp; bonusValues.isPhysicalSkill ? [1, 2, 3, 4, 5] : [damage];&lt;br /&gt;
&lt;br /&gt;
  for (const minDamage of damageValues) {&lt;br /&gt;
    damage = floorMultiplication(minDamage, bonusValues.skillWardCoeff);&lt;br /&gt;
    damage = floorMultiplication(damage, bonusValues.skillBonusCoeff);&lt;br /&gt;
&lt;br /&gt;
    const tempDamage = Math.floor(&lt;br /&gt;
      (damage * bonusValues.skillBonusByBonusCoeff) / 100&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    damage = Math.floor(&lt;br /&gt;
      (tempDamage * bonusValues.magicAttackValueCoeff) / 100 + 0.5&lt;br /&gt;
    );&lt;br /&gt;
    damage = Math.floor((damage * bonusValues.tigerStrengthCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
    calcFinalDamage(&lt;br /&gt;
      damage,&lt;br /&gt;
      tempDamage,&lt;br /&gt;
      bonusValues,&lt;br /&gt;
      criticalAttackRange,&lt;br /&gt;
      damageByType&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function computePolymorphPoint(attacker, victim, polymorphPowerTable) {&lt;br /&gt;
  attacker.polymorphDex = attacker.dex;&lt;br /&gt;
  victim.polymorphDex = victim.dex;&lt;br /&gt;
&lt;br /&gt;
  attacker.minAttackValuePolymorph = 0;&lt;br /&gt;
  attacker.maxAttackValuePolymorph = 0;&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker) &amp;amp;&amp;amp; isPolymorph(attacker)) {&lt;br /&gt;
    var polymorphPowerPct =&lt;br /&gt;
      getPolymorphPower(attacker.polymorphPoint, polymorphPowerTable) / 100;&lt;br /&gt;
    var polymorphMonster = createMonster(&lt;br /&gt;
      attacker.polymorphMonster,&lt;br /&gt;
      null,&lt;br /&gt;
      null,&lt;br /&gt;
      true&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    var polymorphStr = floorMultiplication(&lt;br /&gt;
      polymorphPowerPct,&lt;br /&gt;
      polymorphMonster.str&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    attacker.polymorphDex += floorMultiplication(&lt;br /&gt;
      polymorphPowerPct,&lt;br /&gt;
      polymorphMonster.dex&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    attacker.minAttackValuePolymorph = floorMultiplication(&lt;br /&gt;
      polymorphPowerPct,&lt;br /&gt;
      polymorphMonster.minAttackValue&lt;br /&gt;
    );&lt;br /&gt;
    attacker.maxAttackValuePolymorph = floorMultiplication(&lt;br /&gt;
      polymorphPowerPct,&lt;br /&gt;
      polymorphMonster.maxAttackValue&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    if (!attacker.weapon) {&lt;br /&gt;
      attacker.maxAttackValuePolymorph += 1;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    attacker.attackValue = 0;&lt;br /&gt;
&lt;br /&gt;
    if (isMagicClass(attacker)) {&lt;br /&gt;
      attacker.statAttackValue = 2 * (polymorphStr + attacker.int);&lt;br /&gt;
    } else {&lt;br /&gt;
      attacker.statAttackValue = 2 * (polymorphStr + attacker.str);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function computeHorse(attacker) {&lt;br /&gt;
  attacker.horseAttackValue = 0;&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker) &amp;amp;&amp;amp; isRiding(attacker) &amp;amp;&amp;amp; !isPolymorph(attacker)) {&lt;br /&gt;
    var horseConstant = 30;&lt;br /&gt;
&lt;br /&gt;
    if (attacker.class === &amp;quot;weaponary&amp;quot;) {&lt;br /&gt;
      horseConstant = 60;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    attacker.horseAttackValue = floorMultiplication(&lt;br /&gt;
      2 * attacker.level + attacker.statAttackValue,&lt;br /&gt;
      attacker.horsePoint / horseConstant&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getRankBonus(attacker) {&lt;br /&gt;
  if (!isChecked(attacker.lowRank)) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  switch (attacker.rank) {&lt;br /&gt;
    case &amp;quot;aggressive&amp;quot;:&lt;br /&gt;
      return 1;&lt;br /&gt;
    case &amp;quot;fraudulent&amp;quot;:&lt;br /&gt;
      return 2;&lt;br /&gt;
    case &amp;quot;malicious&amp;quot;:&lt;br /&gt;
      return 3;&lt;br /&gt;
    case &amp;quot;cruel&amp;quot;:&lt;br /&gt;
      return 5;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcElementCoeffPvP(elementBonus, mapping, attacker, victim) {&lt;br /&gt;
  var minElementMalus = 0;&lt;br /&gt;
  var maxDifference = 0;&lt;br /&gt;
  var savedElementDifferences = [];&lt;br /&gt;
  var elementBonusIndex = 0;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; elementBonus.length; index++) {&lt;br /&gt;
    if (!attacker[mapping.elementBonus[index]]) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var elementDifference =&lt;br /&gt;
      attacker[mapping.elementBonus[index]] -&lt;br /&gt;
      victim[mapping.elementResistance[index]];&lt;br /&gt;
&lt;br /&gt;
    if (elementDifference &amp;gt;= 0) {&lt;br /&gt;
      elementBonus[elementBonusIndex] = 10 * elementDifference;&lt;br /&gt;
      minElementMalus -= elementDifference;&lt;br /&gt;
      maxDifference = Math.max(maxDifference, elementDifference);&lt;br /&gt;
      elementBonusIndex++;&lt;br /&gt;
    } else {&lt;br /&gt;
      savedElementDifferences.push(elementDifference);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (!savedElementDifferences.length) {&lt;br /&gt;
    return;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  minElementMalus += maxDifference;&lt;br /&gt;
  savedElementDifferences.sort(compareNumbers);&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; savedElementDifferences.length; index++) {&lt;br /&gt;
    var elementDifference = savedElementDifferences[index];&lt;br /&gt;
&lt;br /&gt;
    elementBonus[elementBonusIndex + index] =&lt;br /&gt;
      10 * Math.max(minElementMalus, elementDifference);&lt;br /&gt;
&lt;br /&gt;
    minElementMalus = Math.min(&lt;br /&gt;
      0,&lt;br /&gt;
      Math.max(minElementMalus, minElementMalus - elementDifference)&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcCriticalHitChance(criticalHitPercentage) {&lt;br /&gt;
  if (criticalHitPercentage &amp;lt;= 9) {&lt;br /&gt;
    return Math.floor((criticalHitPercentage + 5) / 5);&lt;br /&gt;
  }&lt;br /&gt;
  return Math.floor((criticalHitPercentage + 5) / 6);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcCriticalSkillChance(criticalHitPercentage) {&lt;br /&gt;
  if (criticalHitPercentage === 0) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  } else if (criticalHitPercentage &amp;lt;= 9) {&lt;br /&gt;
    return Math.floor((criticalHitPercentage + 7) / 3);&lt;br /&gt;
  }&lt;br /&gt;
  return Math.floor((criticalHitPercentage + 5) / 3);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcPiercingSkillChance(piercingHitPercentage) {&lt;br /&gt;
  if (piercingHitPercentage &amp;lt;= 9) {&lt;br /&gt;
    return Math.floor(piercingHitPercentage / 2);&lt;br /&gt;
  }&lt;br /&gt;
  return 5 + Math.floor((piercingHitPercentage - 10) / 4);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function magicResistanceToCoeff(magicResistance) {&lt;br /&gt;
  if (magicResistance) {&lt;br /&gt;
    return 2000 / (6 * magicResistance + 1000) - 1;&lt;br /&gt;
  }&lt;br /&gt;
  return 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createBattleValues(attacker, victim, battle, skillType) {&lt;br /&gt;
  var {&lt;br /&gt;
    mapping,&lt;br /&gt;
    constants: { polymorphPowerTable, skillPowerTable, marriageTable },&lt;br /&gt;
  } = battle;&lt;br /&gt;
  var calcAttackValues;&lt;br /&gt;
&lt;br /&gt;
  var missPercentage = 0;&lt;br /&gt;
  var attackValueMeleeMagic = 0;&lt;br /&gt;
  var attackValueMarriage = 0;&lt;br /&gt;
  var monsterResistanceMarriage = 0;&lt;br /&gt;
  var monsterResistance = 0;&lt;br /&gt;
  var typeBonus = 0;&lt;br /&gt;
  var raceBonus = 0;&lt;br /&gt;
  var raceResistance = 0;&lt;br /&gt;
  var stoneBonus = 0;&lt;br /&gt;
  var monsterBonus = 0;&lt;br /&gt;
  var elementBonus = [0, 0, 0, 0, 0, 0]; // fire, ice, lightning, earth, darkness, wind, order doesn't matter&lt;br /&gt;
  var defenseMarriage = 0;&lt;br /&gt;
  var damageMultiplier = 1;&lt;br /&gt;
  var useDamage = 1;&lt;br /&gt;
  var defense = victim.defense;&lt;br /&gt;
  var defenseBoost = defense;&lt;br /&gt;
  var magicResistance = 0;&lt;br /&gt;
  var magicPenetration = 0;&lt;br /&gt;
  var weaponDefense = 0;&lt;br /&gt;
  var tigerStrength = 0;&lt;br /&gt;
  var berserkBonus = 0;&lt;br /&gt;
  var blessingBonus = 0;&lt;br /&gt;
  var fearBonus = 0;&lt;br /&gt;
  var magicAttackValueMeleeMagic = 0;&lt;br /&gt;
  var criticalHitPercentage = attacker.criticalHit;&lt;br /&gt;
  var isPlayerVsPlayer = false;&lt;br /&gt;
  var piercingHitPercentage = attacker.piercingHit;&lt;br /&gt;
  var extraPiercingHitPercentage = Math.max(0, piercingHitPercentage - 100);&lt;br /&gt;
  var averageDamage = 0;&lt;br /&gt;
  var averageDamageResistance = 0;&lt;br /&gt;
  var skillDamage = 0;&lt;br /&gt;
  var skillDamageResistance = 0;&lt;br /&gt;
  var rankBonus = 0;&lt;br /&gt;
  var useDarkProtection = false;&lt;br /&gt;
  var darkProtectionPoint = 0;&lt;br /&gt;
  var resistance90PercentHp = 0;&lt;br /&gt;
  var defensePercent = 0;&lt;br /&gt;
  var damageBonus = 0;&lt;br /&gt;
  var empireMalus = 0;&lt;br /&gt;
  var sungMaStrBonus = 0;&lt;br /&gt;
  var sungmaStrMalus = 0;&lt;br /&gt;
  var whiteDragonElixir = 0;&lt;br /&gt;
  var steelDragonElixir = 0;&lt;br /&gt;
&lt;br /&gt;
  attacker.statAttackValue = calcStatAttackValue(attacker);&lt;br /&gt;
&lt;br /&gt;
  computePolymorphPoint(attacker, victim, polymorphPowerTable);&lt;br /&gt;
  computeHorse(attacker);&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker)) {&lt;br /&gt;
    if (weaponData.hasOwnProperty(attacker.weapon)) {&lt;br /&gt;
      attacker.weapon = createWeapon(attacker.weapon);&lt;br /&gt;
    } else {&lt;br /&gt;
      attacker.weapon = createWeapon(0);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    attacker.weapon.getValues(attacker.weaponUpgrade);&lt;br /&gt;
&lt;br /&gt;
    attackValueMeleeMagic =&lt;br /&gt;
      attacker.attackValuePercent + Math.min(100, attacker.attackMeleeMagic);&lt;br /&gt;
&lt;br /&gt;
    var weaponType = attacker.weapon.type;&lt;br /&gt;
&lt;br /&gt;
    if (skillType &amp;amp;&amp;amp; attacker.class === &amp;quot;archery&amp;quot;) {&lt;br /&gt;
      if (weaponType !== 2) {&lt;br /&gt;
        useDamage = 0;&lt;br /&gt;
        weaponType = 2;&lt;br /&gt;
      }&lt;br /&gt;
      defense = 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var weaponDefenseName = mapping.defenseWeapon[weaponType];&lt;br /&gt;
    var weaponDefenseBreakName = mapping.breakWeapon[weaponType];&lt;br /&gt;
&lt;br /&gt;
    if (victim.hasOwnProperty(weaponDefenseName)) {&lt;br /&gt;
      weaponDefense = victim[weaponDefenseName];&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isChecked(attacker.whiteDragonElixir)) {&lt;br /&gt;
      whiteDragonElixir = 10;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    magicPenetration = attacker.magicPenetration;&lt;br /&gt;
&lt;br /&gt;
    if (isPC(victim)) {&lt;br /&gt;
      isPlayerVsPlayer = true;&lt;br /&gt;
&lt;br /&gt;
      if (!skillType) {&lt;br /&gt;
        if (weaponType === 2 &amp;amp;&amp;amp; !isPolymorph(attacker)) {&lt;br /&gt;
          missPercentage = victim.arrowBlock;&lt;br /&gt;
        } else {&lt;br /&gt;
          missPercentage = victim.meleeBlock;&lt;br /&gt;
        }&lt;br /&gt;
        missPercentage +=&lt;br /&gt;
          victim.meleeArrowBlock -&lt;br /&gt;
          (missPercentage * victim.meleeArrowBlock) / 100;&lt;br /&gt;
&lt;br /&gt;
        criticalHitPercentage = calcCriticalHitChance(criticalHitPercentage);&lt;br /&gt;
        berserkBonus = calcBerserkBonus(skillPowerTable, victim);&lt;br /&gt;
        blessingBonus = calcBlessingBonus(skillPowerTable, victim);&lt;br /&gt;
        fearBonus = calcFearBonus(skillPowerTable, victim);&lt;br /&gt;
        averageDamageResistance = victim.averageDamageResistance;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      typeBonus = Math.max(1, attacker.humanBonus - victim.humanResistance);&lt;br /&gt;
      raceBonus = attacker[mapping.raceBonus[victim.race]];&lt;br /&gt;
      raceResistance = victim[mapping.raceResistance[attacker.race]];&lt;br /&gt;
&lt;br /&gt;
      calcElementCoeffPvP(elementBonus, mapping, attacker, victim);&lt;br /&gt;
&lt;br /&gt;
      if (weaponType !== 2 &amp;amp;&amp;amp; attacker.hasOwnProperty(weaponDefenseBreakName)) {&lt;br /&gt;
        weaponDefense -= attacker[weaponDefenseBreakName];&lt;br /&gt;
      }&lt;br /&gt;
    } else {&lt;br /&gt;
      if (isChecked(attacker.isMarried)) {&lt;br /&gt;
        if (isChecked(attacker.loveNecklace)) {&lt;br /&gt;
          attackValueMarriage = getMarriageBonusValue(&lt;br /&gt;
            attacker,&lt;br /&gt;
            marriageTable,&lt;br /&gt;
            &amp;quot;loveNecklace&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isChecked(attacker.loveEarrings)) {&lt;br /&gt;
          criticalHitPercentage += getMarriageBonusValue(&lt;br /&gt;
            attacker,&lt;br /&gt;
            marriageTable,&lt;br /&gt;
            &amp;quot;loveEarrings&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isChecked(attacker.harmonyEarrings)) {&lt;br /&gt;
          piercingHitPercentage += getMarriageBonusValue(&lt;br /&gt;
            attacker,&lt;br /&gt;
            marriageTable,&lt;br /&gt;
            &amp;quot;harmonyEarrings&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (isChecked(attacker.tigerStrength)) {&lt;br /&gt;
        tigerStrength = 40;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      for (var index = 0; index &amp;lt; elementBonus.length; index++) {&lt;br /&gt;
        var elementBonusName = mapping.elementBonus[index];&lt;br /&gt;
        var elementResistanceName = mapping.elementResistance[index];&lt;br /&gt;
&lt;br /&gt;
        if (attacker[elementBonusName] &amp;amp;&amp;amp; victim[elementBonusName]) {&lt;br /&gt;
          elementBonus[index] =&lt;br /&gt;
            50 * (attacker[elementBonusName] - victim[elementResistanceName]);&lt;br /&gt;
        } else {&lt;br /&gt;
          elementBonus[index] = 5 * attacker[elementBonusName];&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      var victimType = victim.type;&lt;br /&gt;
&lt;br /&gt;
      if (victimType !== -1) {&lt;br /&gt;
        typeBonus = attacker[mapping.typeFlag[victimType]];&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      monsterBonus = attacker.monsterBonus;&lt;br /&gt;
&lt;br /&gt;
      if (isStone(victim)) {&lt;br /&gt;
        stoneBonus = attacker.stoneBonus;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (isBoss(victim)) {&lt;br /&gt;
        if (skillType) {&lt;br /&gt;
          skillDamage += attacker.skillBossDamage;&lt;br /&gt;
        } else {&lt;br /&gt;
          averageDamage += attacker.bossDamage;&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (isChecked(attacker.onYohara)) {&lt;br /&gt;
        var sungmaStrDifference = attacker.sungmaStr - attacker.sungmaStrMalus;&lt;br /&gt;
&lt;br /&gt;
        if (sungmaStrDifference &amp;gt;= 0) {&lt;br /&gt;
          sungMaStrBonus = sungmaStrDifference;&lt;br /&gt;
        } else {&lt;br /&gt;
          sungmaStrMalus = 0.5;&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (skillType) {&lt;br /&gt;
      skillDamage += attacker.skillDamage;&lt;br /&gt;
    } else {&lt;br /&gt;
      averageDamage += attacker.averageDamage;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    rankBonus = getRankBonus(attacker);&lt;br /&gt;
    damageBonus = attacker.damageBonus;&lt;br /&gt;
&lt;br /&gt;
    if (isChecked(attacker.empireMalus)) {&lt;br /&gt;
      empireMalus = 1;&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    if (isPC(victim)) {&lt;br /&gt;
      if (isChecked(victim.isMarried)) {&lt;br /&gt;
        if (isChecked(victim.harmonyBracelet)) {&lt;br /&gt;
          monsterResistanceMarriage = getMarriageBonusValue(&lt;br /&gt;
            victim,&lt;br /&gt;
            marriageTable,&lt;br /&gt;
            &amp;quot;harmonyBracelet&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isChecked(victim.harmonyNecklace) &amp;amp;&amp;amp; !skillType) {&lt;br /&gt;
          defenseMarriage = getMarriageBonusValue(&lt;br /&gt;
            victim,&lt;br /&gt;
            marriageTable,&lt;br /&gt;
            &amp;quot;harmonyNecklace&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      monsterResistance = victim.monsterResistance;&lt;br /&gt;
&lt;br /&gt;
      for (var index = 0; index &amp;lt; elementBonus.length; index++) {&lt;br /&gt;
        var elementBonusName = mapping.elementBonus[index];&lt;br /&gt;
        var elementResistanceName = mapping.elementResistance[index];&lt;br /&gt;
&lt;br /&gt;
        if (attacker[elementBonusName]) {&lt;br /&gt;
          elementBonus[index] =&lt;br /&gt;
            80 * (attacker[elementBonusName] - victim[elementResistanceName]);&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (!skillType) {&lt;br /&gt;
        if (isMeleeAttacker(attacker)) {&lt;br /&gt;
          missPercentage = victim.meleeBlock;&lt;br /&gt;
          averageDamageResistance = victim.averageDamageResistance;&lt;br /&gt;
          berserkBonus = calcBerserkBonus(skillPowerTable, victim);&lt;br /&gt;
          blessingBonus = calcBlessingBonus(skillPowerTable, victim);&lt;br /&gt;
          fearBonus = calcFearBonus(skillPowerTable, victim);&lt;br /&gt;
        } else if (isRangeAttacker(attacker)) {&lt;br /&gt;
          missPercentage = victim.arrowBlock;&lt;br /&gt;
          weaponDefense = victim.arrowDefense;&lt;br /&gt;
          averageDamageResistance = victim.averageDamageResistance;&lt;br /&gt;
          berserkBonus = calcBerserkBonus(skillPowerTable, victim);&lt;br /&gt;
          blessingBonus = calcBlessingBonus(skillPowerTable, victim);&lt;br /&gt;
          fearBonus = calcFearBonus(skillPowerTable, victim);&lt;br /&gt;
        } else if (isMagicAttacker(attacker)) {&lt;br /&gt;
          missPercentage = victim.arrowBlock;&lt;br /&gt;
          skillDamageResistance = victim.skillDamageResistance;&lt;br /&gt;
          magicResistance = victim.magicResistance;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        missPercentage +=&lt;br /&gt;
          victim.meleeArrowBlock -&lt;br /&gt;
          (missPercentage * victim.meleeArrowBlock) / 100;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    typeBonus = 1;&lt;br /&gt;
    damageMultiplier = attacker.damageMultiplier;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillType) {&lt;br /&gt;
    criticalHitPercentage = calcCriticalSkillChance(criticalHitPercentage);&lt;br /&gt;
    piercingHitPercentage = calcPiercingSkillChance(piercingHitPercentage);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (isPC(victim)) {&lt;br /&gt;
    if (!skillType &amp;amp;&amp;amp; isChecked(victim.biologist70)) {&lt;br /&gt;
      defenseBoost = Math.floor((defenseBoost * 110) / 100);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    criticalHitPercentage = Math.max(&lt;br /&gt;
      0,&lt;br /&gt;
      criticalHitPercentage - victim.criticalHitResistance&lt;br /&gt;
    );&lt;br /&gt;
    piercingHitPercentage = Math.max(&lt;br /&gt;
      0,&lt;br /&gt;
      piercingHitPercentage - victim.piercingHitResistance&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    if (skillType) {&lt;br /&gt;
      skillDamageResistance = victim.skillDamageResistance;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      victim.useDarkProtection &amp;amp;&amp;amp;&lt;br /&gt;
      victim.class === &amp;quot;black_magic&amp;quot; &amp;amp;&amp;amp;&lt;br /&gt;
      victim.skillDarkProtection&lt;br /&gt;
    ) {&lt;br /&gt;
      useDarkProtection = true;&lt;br /&gt;
      darkProtectionPoint = calcDarkProtectionPoint(skillPowerTable, victim);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    resistance90PercentHp = victim.resistance90PercentHp || 0;&lt;br /&gt;
&lt;br /&gt;
    if (isMagicClass(victim)) {&lt;br /&gt;
      defensePercent = (-2 * victim.magicDefense * victim.defensePercent) / 100;&lt;br /&gt;
    } else {&lt;br /&gt;
      defensePercent = (-2 * defenseBoost * victim.defensePercent) / 100;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isChecked(victim.steelDragonElixir)) {&lt;br /&gt;
      steelDragonElixir = 10;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillType === &amp;quot;magic&amp;quot;) {&lt;br /&gt;
    attackValueMeleeMagic = 0;&lt;br /&gt;
    magicAttackValueMeleeMagic =&lt;br /&gt;
      attacker.attackMagic + Math.min(100, attacker.attackMeleeMagic);&lt;br /&gt;
    attackValueMarriage = 0;&lt;br /&gt;
    defense = 0;&lt;br /&gt;
    magicResistance = victim.magicResistance;&lt;br /&gt;
&lt;br /&gt;
    if (magicResistance &amp;gt; 0 &amp;amp;&amp;amp; magicPenetration) {&lt;br /&gt;
      magicResistance = Math.floor(&lt;br /&gt;
        magicResistance * (1 - magicPenetration / 120) + 0.5&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    weaponDefense = 0;&lt;br /&gt;
    calcAttackValues = calcMagicAttackValue;&lt;br /&gt;
&lt;br /&gt;
    if (isDispell(attacker, 6)) {&lt;br /&gt;
      typeBonus = 0;&lt;br /&gt;
      raceBonus = 0;&lt;br /&gt;
      raceResistance = 0;&lt;br /&gt;
      stoneBonus = 0;&lt;br /&gt;
      monsterBonus = 0;&lt;br /&gt;
      for (var index = 0; index &amp;lt; elementBonus.length; index++) {&lt;br /&gt;
        elementBonus[index] = 0;&lt;br /&gt;
      }&lt;br /&gt;
      magicResistance = 0;&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    calcAttackValues = calcSecondaryAttackValue;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  missPercentage = Math.min(100, missPercentage);&lt;br /&gt;
  criticalHitPercentage = Math.min(criticalHitPercentage, 100);&lt;br /&gt;
  piercingHitPercentage = Math.min(piercingHitPercentage, 100);&lt;br /&gt;
&lt;br /&gt;
  const bonusValues = {&lt;br /&gt;
    missPercentage: missPercentage,&lt;br /&gt;
    skipCriticalStep: [&lt;br /&gt;
      !Boolean(100 - criticalHitPercentage),&lt;br /&gt;
      !Boolean(criticalHitPercentage),&lt;br /&gt;
    ],&lt;br /&gt;
    skipPiercingStep: [&lt;br /&gt;
      !Boolean(100 - piercingHitPercentage),&lt;br /&gt;
      !Boolean(piercingHitPercentage),&lt;br /&gt;
    ],&lt;br /&gt;
    isPhysicalSkill: skillType === &amp;quot;physical&amp;quot; &amp;amp;&amp;amp; attacker.class !== &amp;quot;archery&amp;quot;,&lt;br /&gt;
    weaponBonusCoeff: 1,&lt;br /&gt;
    attackValueCoeff: 100 + attackValueMeleeMagic,&lt;br /&gt;
    attackValueMarriage: attackValueMarriage,&lt;br /&gt;
    monsterResistanceMarriageCoeff: 100 - monsterResistanceMarriage,&lt;br /&gt;
    monsterResistanceCoeff: 100 - monsterResistance,&lt;br /&gt;
    typeBonusCoeff: typeBonus,&lt;br /&gt;
    raceBonusCoeff: raceBonus,&lt;br /&gt;
    raceResistanceCoeff: raceResistance,&lt;br /&gt;
    stoneBonusCoeff: stoneBonus,&lt;br /&gt;
    monsterBonusCoeff: monsterBonus,&lt;br /&gt;
    elementBonusCoeff: elementBonus,&lt;br /&gt;
    damageMultiplier: damageMultiplier,&lt;br /&gt;
    useDamage: useDamage,&lt;br /&gt;
    defense: defense,&lt;br /&gt;
    defenseBoost: defenseBoost,&lt;br /&gt;
    defenseMarriage: defenseMarriage,&lt;br /&gt;
    tigerStrengthCoeff: 100 + tigerStrength,&lt;br /&gt;
    magicResistanceCoeff: magicResistanceToCoeff(magicResistance),&lt;br /&gt;
    weaponDefenseCoeff: 100 - weaponDefense,&lt;br /&gt;
    berserkBonusCoeff: 100 + berserkBonus,&lt;br /&gt;
    blessingBonusCoeff: 100 - blessingBonus,&lt;br /&gt;
    fearBonusCoeff: 100 - fearBonus,&lt;br /&gt;
    magicAttackValueCoeff: 100 + magicAttackValueMeleeMagic,&lt;br /&gt;
    extraPiercingHitCoeff: 5 * extraPiercingHitPercentage,&lt;br /&gt;
    averageDamageCoeff: 100 + averageDamage,&lt;br /&gt;
    averageDamageResistanceCoeff: 100 - Math.min(99, averageDamageResistance),&lt;br /&gt;
    skillDamageCoeff: 100 + skillDamage,&lt;br /&gt;
    skillDamageResistanceCoeff: 100 - Math.min(99, skillDamageResistance),&lt;br /&gt;
    useDarkProtection: useDarkProtection,&lt;br /&gt;
    darkProtectionPoint: darkProtectionPoint,&lt;br /&gt;
    darkProtectionSp: victim.darkProtectionSp,&lt;br /&gt;
    rankBonusCoeff: 100 + rankBonus,&lt;br /&gt;
    resistance90PercentHp: resistance90PercentHp,&lt;br /&gt;
    defensePercent: Math.floor(defensePercent),&lt;br /&gt;
    damageBonusCoeff: Math.min(20, damageBonus),&lt;br /&gt;
    empireMalusCoeff: 10 - empireMalus,&lt;br /&gt;
    sungMaStrBonusCoeff: 10000 + sungMaStrBonus,&lt;br /&gt;
    sungmaStrMalusCoeff: sungmaStrMalus,&lt;br /&gt;
    whiteDragonElixirCoeff: 100 + whiteDragonElixir,&lt;br /&gt;
    steelDragonElixirCoeff: 100 - steelDragonElixir,&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  const damageTypeWeights = [&lt;br /&gt;
    (100 - criticalHitPercentage) *&lt;br /&gt;
      (100 - piercingHitPercentage) *&lt;br /&gt;
      (100 - missPercentage),&lt;br /&gt;
    criticalHitPercentage *&lt;br /&gt;
      (100 - piercingHitPercentage) *&lt;br /&gt;
      (100 - missPercentage),&lt;br /&gt;
    (100 - criticalHitPercentage) *&lt;br /&gt;
      piercingHitPercentage *&lt;br /&gt;
      (100 - missPercentage),&lt;br /&gt;
    criticalHitPercentage * piercingHitPercentage * (100 - missPercentage),&lt;br /&gt;
  ];&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    attacker: attacker,&lt;br /&gt;
    victim: victim,&lt;br /&gt;
    attackFactor: calcAttackFactor(attacker, victim),&lt;br /&gt;
    mainAttackValue: calcMainAttackValue(attacker),&lt;br /&gt;
    attackValues: calcAttackValues(attacker, isPlayerVsPlayer),&lt;br /&gt;
    bonusValues: bonusValues,&lt;br /&gt;
    damageTypeWeights: damageTypeWeights,&lt;br /&gt;
    attackTypeMapping: mapping.attackType,&lt;br /&gt;
    damageWeightedByType: {&lt;br /&gt;
      normalHit: {},&lt;br /&gt;
      criticalHit: {},&lt;br /&gt;
      piercingHit: {},&lt;br /&gt;
      criticalPiercingHit: {},&lt;br /&gt;
    },&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateBattleValues(battleValues, skillFormula, skillInfo) {&lt;br /&gt;
  var weaponBonus = skillInfo.adjust || 0;&lt;br /&gt;
  var skillWard = 0;&lt;br /&gt;
  var skillBonus = 0;&lt;br /&gt;
  var skillBonusByBonus = 0;&lt;br /&gt;
  var { attacker: attacker, bonusValues: bonusValues } = battleValues;&lt;br /&gt;
  var {&lt;br /&gt;
    range: [minVariation, maxVariation],&lt;br /&gt;
  } = skillInfo;&lt;br /&gt;
  var variationLength = maxVariation - minVariation + 1;&lt;br /&gt;
&lt;br /&gt;
  if (skillInfo.hasOwnProperty(&amp;quot;weaponBonus&amp;quot;)) {&lt;br /&gt;
    var [weaponType, weaponBonusValue] = skillInfo.weaponBonus;&lt;br /&gt;
&lt;br /&gt;
    if (weaponType === attacker.weapon.type) {&lt;br /&gt;
      weaponBonus += weaponBonusValue;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillInfo.skillBonus) {&lt;br /&gt;
    skillBonus = skillInfo.skillBonus;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillInfo.skillWard) {&lt;br /&gt;
    skillWard = skillInfo.skillWard;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillInfo.skillBonusByBonus) {&lt;br /&gt;
    skillBonusByBonus = skillInfo.skillBonusByBonus;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillInfo.removeWeaponReduction) {&lt;br /&gt;
    bonusValues.weaponDefenseCoeff = 100;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  bonusValues.weaponBonusCoeff = 100 + weaponBonus;&lt;br /&gt;
  bonusValues.skillWardCoeff = 1 - skillWard / 100;&lt;br /&gt;
  bonusValues.skillBonusCoeff = 1 + skillBonus / 100;&lt;br /&gt;
  bonusValues.skillBonusByBonusCoeff = 100 + skillBonusByBonus;&lt;br /&gt;
&lt;br /&gt;
  battleValues.skillFormula = skillFormula;&lt;br /&gt;
  battleValues.skillRange = skillInfo.range;&lt;br /&gt;
  battleValues.attackValues.totalCardinal *= variationLength;&lt;br /&gt;
  battleValues.attackValues.possibleDamageCount *= variationLength;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcWeights(minValue, maxValue, minInterval) {&lt;br /&gt;
  var firstWeightLimit = minValue + minInterval - 1;&lt;br /&gt;
  var lastWeightsLimit = maxValue - minInterval + 1;&lt;br /&gt;
  var weights = [];&lt;br /&gt;
&lt;br /&gt;
  for (var value = minValue; value &amp;lt; firstWeightLimit; value++) {&lt;br /&gt;
    weights.push(value - minValue + 1);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (var value = firstWeightLimit; value &amp;lt;= lastWeightsLimit; value++) {&lt;br /&gt;
    weights.push(minInterval);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (var value = lastWeightsLimit + 1; value &amp;lt;= maxValue; value++) {&lt;br /&gt;
    weights.push(maxValue - value + 1);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return weights;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcBerserkBonus(skillPowerTable, victim) {&lt;br /&gt;
  if (!isChecked(victim.useBerserk) || victim.class !== &amp;quot;body&amp;quot;) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  const skillPower = getSkillPower(victim.skillBerserk, skillPowerTable);&lt;br /&gt;
&lt;br /&gt;
  if (!skillPower) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  const berserkBonus = Math.floor(skillPower * 25);&lt;br /&gt;
&lt;br /&gt;
  return berserkBonus;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcBlessingBonus(skillPowerTable, victim) {&lt;br /&gt;
  if (!isChecked(victim.isBlessed)) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  const int = victim.intBlessing;&lt;br /&gt;
  const dex = victim.dexBlessing;&lt;br /&gt;
  const skillPower = getSkillPower(victim.skillBlessing, skillPowerTable);&lt;br /&gt;
&lt;br /&gt;
  if (!skillPower) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  let blessingBonus = floorMultiplication(&lt;br /&gt;
    ((int * 0.3 + 5) * (2 * skillPower + 0.5) + 0.3 * dex) / (skillPower + 2.3),&lt;br /&gt;
    1&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  if (victim.class === &amp;quot;dragon&amp;quot; &amp;amp;&amp;amp; isChecked(victim.blessingOnself)) {&lt;br /&gt;
    blessingBonus = floorMultiplication(blessingBonus, 1.1);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return blessingBonus;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcFearBonus(skillPowerTable, victim) {&lt;br /&gt;
  if (!isChecked(victim.useFear) || victim.class !== &amp;quot;weaponary&amp;quot;) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  const skillPower = getSkillPower(victim.skillFear, skillPowerTable);&lt;br /&gt;
&lt;br /&gt;
  if (!skillPower) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  const fearBonus = 5 + Math.floor(skillPower * 20);&lt;br /&gt;
&lt;br /&gt;
  return fearBonus;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcDarkProtectionPoint(skillPowerTable, victim) {&lt;br /&gt;
  const skillPower = getSkillPower(victim.skillDarkProtection, skillPowerTable);&lt;br /&gt;
&lt;br /&gt;
  return floorMultiplication(100 - victim.int * 0.84 * skillPower, 1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcStealthBonus(skillPowerTable, attacker) {&lt;br /&gt;
  if (!isChecked(attacker.useStealth)) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  const skillPower = getSkillPower(attacker.skillStealth, skillPowerTable);&lt;br /&gt;
&lt;br /&gt;
  if (!skillPower) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  const stealthBonus = skillPower * 50;&lt;br /&gt;
&lt;br /&gt;
  return stealthBonus;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSkillFormula(battle, skillId, battleValues, removeSkillVariation) {&lt;br /&gt;
  var { attacker, victim, attackFactor } = battleValues;&lt;br /&gt;
  var skillPowerTable = battle.constants.skillPowerTable;&lt;br /&gt;
&lt;br /&gt;
  var skillFormula;&lt;br /&gt;
  var skillInfo = { range: [0, 0] };&lt;br /&gt;
&lt;br /&gt;
  var { class: attackerClass, level: lv, vit, str, int, dex } = attacker;&lt;br /&gt;
&lt;br /&gt;
  if (skillId &amp;lt;= 9) {&lt;br /&gt;
    var skillPower = getSkillPower(&lt;br /&gt;
      attacker[&amp;quot;attackSkill&amp;quot; + skillId],&lt;br /&gt;
      skillPowerTable&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    var improvedBySkillBonus = false;&lt;br /&gt;
    var improvedByBonus = false;&lt;br /&gt;
&lt;br /&gt;
    if (attackerClass === &amp;quot;body&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Triple lacération&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.1 * atk + (0.5 * atk + 1.5 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Moulinet à l'épée&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              3 * atk + (0.8 * atk + 5 * str + 3 * dex + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Accélération&lt;br /&gt;
        case 5:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * atk + (atk + dex * 3 + str * 7 + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Volonté de vivre&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              (3 * atk + (atk + 1.5 * str) * skillPower) * 1.07,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          break;&lt;br /&gt;
        // Tremblement de terre&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              3 * atk +&lt;br /&gt;
                (0.9 * atk + variation + 5 * str + 3 * dex + lv) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;mental&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Attaque de l'esprit&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2.3 * atk + (4 * atk + 4 * str + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Attaque de la paume&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2.3 * atk + (3 * atk + 4 * str + 3 * vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Charge&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * atk + (2 * atk + 2 * dex + 2 * vit + 4 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          break;&lt;br /&gt;
        // Coup d'épée&lt;br /&gt;
        case 5:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * atk + (atk + 3 * dex + 5 * str + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Orbe de l'épée&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              (2 * atk + (2 * atk + 2 * dex + 2 * vit + 4 * str) * skillPower) *&lt;br /&gt;
                1.1,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          break;&lt;br /&gt;
        // Tremblement de terre&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              3 * atk +&lt;br /&gt;
                (0.9 * atk + variation + 5 * str + 3 * dex + lv) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;blade_fight&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Embuscade&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk + (1.2 * atk + variation + 4 * dex + 4 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [1, 50];&lt;br /&gt;
          skillInfo.range = [500, 700];&lt;br /&gt;
          skillInfo.adjust = calcStealthBonus(skillPowerTable, attacker);&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Attaque rapide&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk + (1.6 * atk + variation + 7 * dex + 7 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [1, 35];&lt;br /&gt;
          skillInfo.range = [200, 300];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Dague filante&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * atk + (0.5 * atk + 9 * dex + 7 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Brume empoisonnée&lt;br /&gt;
        case 5:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * lv + (atk + 3 * str + 18 * dex) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Poison insidieux&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              (2 * lv + (atk + 3 * str + 18 * dex) * skillPower) * 1.1,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          break;&lt;br /&gt;
        // Étoiles brillantes&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk + (1.7 * atk + variation + 6 * dex + 5 * lv) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;archery&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Tir à répétition&lt;br /&gt;
        // case 1:&lt;br /&gt;
        //   skillFormula = function (atk) {&lt;br /&gt;
        //     return floorMultiplication(&lt;br /&gt;
        //       atk + 0.2 * atk * Math.floor(2 + 6 * skillPower) + (0.8 * atk + 8 * dex * attackFactor + 2 * int) * skillPower,&lt;br /&gt;
        //       1&lt;br /&gt;
        //     );&lt;br /&gt;
        //   };&lt;br /&gt;
        //   improvedByBonus = true;&lt;br /&gt;
        //   break;&lt;br /&gt;
        // Pluie de flèches&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk + (1.7 * atk + 5 * dex + str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Flèche de feu&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.5 * atk + (2.6 * atk + 0.9 * int + variation) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [100, 300];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Foulée de plume&lt;br /&gt;
        case 4:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              (3 * dex + 200 + 2 * str + 2 * int) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.removeWeaponReduction = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Flèche empoisonnée&lt;br /&gt;
        case 5:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk +&lt;br /&gt;
                (1.4 * atk + variation + 7 * dex + 4 * str + 4 * int) *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [100, 200];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Coup étincelant&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              (atk +&lt;br /&gt;
                (1.2 * atk + variation + 6 * dex + 3 * str + 3 * int) *&lt;br /&gt;
                  skillPower) *&lt;br /&gt;
                1.2,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [100, 200];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Tir tempête&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.9 * atk + (2.6 * atk + variation) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;weaponary&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Toucher brûlant&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk +&lt;br /&gt;
                2 * lv +&lt;br /&gt;
                2 * int +&lt;br /&gt;
                (2 * atk + 4 * str + 14 * int) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Tourbillon du dragon&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.1 * atk +&lt;br /&gt;
                2 * lv +&lt;br /&gt;
                2 * int +&lt;br /&gt;
                (1.5 * atk + str + 12 * int) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Contre-sort&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              40 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                2 * int +&lt;br /&gt;
                (10 * int + 7 * mav + variation) * attackFactor * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [50, 100];&lt;br /&gt;
          break;&lt;br /&gt;
        // Coup démoniaque&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.9 * atk + (2.6 * atk + variation) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;black_magic&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Attaque des ténèbres&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              40 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                2 * int +&lt;br /&gt;
                (13 * int + 6 * mav + variation) * attackFactor * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [50, 100];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Attaque de flammes&lt;br /&gt;
        // case 2:&lt;br /&gt;
        //   skillFormula = function (mav, variation) {&lt;br /&gt;
        //     return floorMultiplication(&lt;br /&gt;
        //       5 * lv + 2 * int + (7 * int + 8 * mav + 4 * str + 2 * vit + variation) * skillPower,&lt;br /&gt;
        //       1&lt;br /&gt;
        //     );&lt;br /&gt;
        //   };&lt;br /&gt;
        //   skillInfo.range = [180, 100];&lt;br /&gt;
        //   improvedByBonus = true;&lt;br /&gt;
        //   break;&lt;br /&gt;
        // Esprit de flammes&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              30 +&lt;br /&gt;
                2 * lv +&lt;br /&gt;
                2 * int +&lt;br /&gt;
                (7 * int + 6 * mav + variation) * attackFactor * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [200, 500];&lt;br /&gt;
          break;&lt;br /&gt;
        // Frappe de l'esprit&lt;br /&gt;
        // case 5:&lt;br /&gt;
        //   skillFormula = function (mav, variation) {&lt;br /&gt;
        //     return floorMultiplication(&lt;br /&gt;
        //       40 + 2 * lv + 2 * int + (2 * vit + 2 * dex + 13 * int + 6 * mav + variation) * attackFactor * skillPower,&lt;br /&gt;
        //       1&lt;br /&gt;
        //     );&lt;br /&gt;
        //   };&lt;br /&gt;
        //   skillInfo.range = [180, 200];&lt;br /&gt;
        //   break;&lt;br /&gt;
        // Orbe des ténèbres&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (mav) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              120 +&lt;br /&gt;
                6 * lv +&lt;br /&gt;
                (5 * vit + 5 * dex + 29 * int + 9 * mav) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Vague mortelle&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              120 +&lt;br /&gt;
                6 * lv +&lt;br /&gt;
                (5 * vit + 5 * dex + 30 * int + variation + 9 * mav) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;dragon&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Talisman volant&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (mav) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              70 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                (18 * int + 7 * str + 5 * mav + 50) * attackFactor * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [4, 10];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Dragon chassant&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (mav) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              60 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                (16 * int + 6 * dex + 6 * mav + 120) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [4, 10];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Rugissement du dragon&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (mav) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              70 +&lt;br /&gt;
                3 * lv +&lt;br /&gt;
                (20 * int + 3 * str + 10 * mav + 100) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [4, 10];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Météore&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              120 +&lt;br /&gt;
                6 * lv +&lt;br /&gt;
                (5 * vit + 5 * dex + 30 * int + variation + 9 * mav) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;heal&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Jet de foudre&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              60 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                (8 * int + 2 * dex + 8 * mav + variation) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [6, 10];&lt;br /&gt;
          skillInfo.range = [5 * int, 15 * int];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Invocation de foudre&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              40 +&lt;br /&gt;
                4 * lv +&lt;br /&gt;
                (13 * int + 2 * str + 10 * mav + variation) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [6, 10];&lt;br /&gt;
          skillInfo.range = [5 * int, 16 * int];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Griffe de foudre&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              50 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                (8 * int + 2 * str + 8 * mav + variation) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 800];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;lycan&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Déchiqueter&lt;br /&gt;
        // case 1:&lt;br /&gt;
        //   skillFormula = function (atk) {&lt;br /&gt;
        //     return floorMultiplication(&lt;br /&gt;
        //       1.1 * atk + (0.3 * atk + 1.5 * str) * skillPower,&lt;br /&gt;
        //       1&lt;br /&gt;
        //     );&lt;br /&gt;
        //   };&lt;br /&gt;
        //   skillInfo.weaponBonus = [5, 54];&lt;br /&gt;
        //   improvedByBonus = true;&lt;br /&gt;
        //   break;&lt;br /&gt;
        // Souffle de loup&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * atk + (atk + 3 * dex + 5 * str + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [5, 35];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Bond de loup&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk + (1.6 * atk + 200 + 7 * dex + 7 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [5, 35];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Griffe de loup&lt;br /&gt;
        case 4:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              3 * atk + (0.8 * atk + 6 * str + 2 * dex + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Tempête cinglante&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.8 * atk +&lt;br /&gt;
                (atk + 6 * dex + variation + 3 * str + lv) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
    if (improvedBySkillBonus) {&lt;br /&gt;
      skillInfo.skillBonus =&lt;br /&gt;
        16 * getSkillPower(attacker.skillBonus, skillPowerTable);&lt;br /&gt;
&lt;br /&gt;
      var skillWardChoice = victim.skillWardChoice;&lt;br /&gt;
&lt;br /&gt;
      if (skillWardChoice &amp;amp;&amp;amp; skillWardChoice === attackerClass) {&lt;br /&gt;
        skillInfo.skillWard =&lt;br /&gt;
          24 * getSkillPower(victim.skillWard, skillPowerTable);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (improvedByBonus) {&lt;br /&gt;
      skillInfo.skillBonusByBonus = attacker[&amp;quot;skillBonus&amp;quot; + skillId];&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (removeSkillVariation) {&lt;br /&gt;
      var averageVariation = (skillInfo.range[0] + skillInfo.range[0]) / 2;&lt;br /&gt;
      skillInfo.range = [averageVariation, averageVariation];&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    var skillPower = getSkillPower(&lt;br /&gt;
      attacker[&amp;quot;horseSkill&amp;quot; + skillId],&lt;br /&gt;
      skillPowerTable&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    switch (skillId) {&lt;br /&gt;
      // Combat équestre&lt;br /&gt;
      case 137:&lt;br /&gt;
        skillFormula = function (atk) {&lt;br /&gt;
          return floorMultiplication(atk + 2 * atk * skillPower, 1);&lt;br /&gt;
        };&lt;br /&gt;
        break;&lt;br /&gt;
      // Charge à cheval&lt;br /&gt;
      case 138:&lt;br /&gt;
        skillFormula = function (atk) {&lt;br /&gt;
          return floorMultiplication(&lt;br /&gt;
            2.4 * (200 + 1.5 * lv) + 600 * skillPower,&lt;br /&gt;
            1&lt;br /&gt;
          );&lt;br /&gt;
        };&lt;br /&gt;
        break;&lt;br /&gt;
      // Vague de Pouvoir&lt;br /&gt;
      case 139:&lt;br /&gt;
        skillFormula = function (atk) {&lt;br /&gt;
          return floorMultiplication(&lt;br /&gt;
            2 * (200 + 1.5 * lv) + 600 * skillPower,&lt;br /&gt;
            1&lt;br /&gt;
          );&lt;br /&gt;
        };&lt;br /&gt;
        break;&lt;br /&gt;
      // Grêle de flèches&lt;br /&gt;
      case 140:&lt;br /&gt;
        skillFormula = function (atk) {&lt;br /&gt;
          return floorMultiplication(atk + 2 * atk * skillPower, 1);&lt;br /&gt;
        };&lt;br /&gt;
        break;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  updateBattleValues(battleValues, skillFormula, skillInfo);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcMagicAttackValueAugmentation(&lt;br /&gt;
  magicAttackValueWeapon,&lt;br /&gt;
  magicAttackValueBonus&lt;br /&gt;
) {&lt;br /&gt;
  if (magicAttackValueBonus) {&lt;br /&gt;
    return Math.max(&lt;br /&gt;
      1,&lt;br /&gt;
      0.0025056 *&lt;br /&gt;
        magicAttackValueBonus ** 0.602338 *&lt;br /&gt;
        magicAttackValueWeapon ** 1.20476&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
  return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getMagicAttackValueAugmentation(&lt;br /&gt;
  minMagicAttackValue,&lt;br /&gt;
  maxMagicAttackValue,&lt;br /&gt;
  magicAttackValueBonus&lt;br /&gt;
) {&lt;br /&gt;
  var magicAttackValueAugmentation = [];&lt;br /&gt;
&lt;br /&gt;
  for (&lt;br /&gt;
    var magicAttackValue = minMagicAttackValue;&lt;br /&gt;
    magicAttackValue &amp;lt;= maxMagicAttackValue;&lt;br /&gt;
    magicAttackValue++&lt;br /&gt;
  ) {&lt;br /&gt;
    magicAttackValueAugmentation.push(&lt;br /&gt;
      calcMagicAttackValueAugmentation(magicAttackValue, magicAttackValueBonus)&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return magicAttackValueAugmentation;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcPhysicalDamage(battleValues) {&lt;br /&gt;
  const {&lt;br /&gt;
    attackFactor,&lt;br /&gt;
    mainAttackValue,&lt;br /&gt;
    attackValues: {&lt;br /&gt;
      minAttackValue,&lt;br /&gt;
      maxAttackValue,&lt;br /&gt;
      attackValueOther,&lt;br /&gt;
      weights,&lt;br /&gt;
      criticalAttackRange,&lt;br /&gt;
    },&lt;br /&gt;
    bonusValues,&lt;br /&gt;
    damageWeightedByType,&lt;br /&gt;
  } = battleValues;&lt;br /&gt;
&lt;br /&gt;
  const savedDamage = {};&lt;br /&gt;
&lt;br /&gt;
  if (bonusValues.missPercentage) {&lt;br /&gt;
    damageWeightedByType.miss = bonusValues.missPercentage / 100;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (&lt;br /&gt;
    let attackValue = minAttackValue;&lt;br /&gt;
    attackValue &amp;lt;= maxAttackValue;&lt;br /&gt;
    attackValue++&lt;br /&gt;
  ) {&lt;br /&gt;
    const weight = weights[attackValue - minAttackValue];&lt;br /&gt;
    const damageByType = [[], [], [], []];&lt;br /&gt;
    const currentDamageInfo = [weight, damageByType];&lt;br /&gt;
&lt;br /&gt;
    const secondaryAttackValue = 2 * attackValue + attackValueOther;&lt;br /&gt;
    const rawDamage =&lt;br /&gt;
      mainAttackValue + floorMultiplication(attackFactor, secondaryAttackValue);&lt;br /&gt;
&lt;br /&gt;
    const damageWithPrimaryBonuses = calcDamageWithPrimaryBonuses(&lt;br /&gt;
      rawDamage,&lt;br /&gt;
      bonusValues&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    const damageAfterDefense =&lt;br /&gt;
      damageWithPrimaryBonuses -&lt;br /&gt;
      bonusValues.defenseBoost -&lt;br /&gt;
      bonusValues.defenseMarriage;&lt;br /&gt;
&lt;br /&gt;
    const damageValues =&lt;br /&gt;
      damageAfterDefense &amp;lt;= 2 ? [1, 2, 3, 4, 5] : [damageAfterDefense];&lt;br /&gt;
&lt;br /&gt;
    for (const damage of damageValues) {&lt;br /&gt;
      saveFinalDamage(&lt;br /&gt;
        damage,&lt;br /&gt;
        damageWithPrimaryBonuses,&lt;br /&gt;
        bonusValues,&lt;br /&gt;
        criticalAttackRange,&lt;br /&gt;
        damageByType&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    savedDamage[attackValue] = currentDamageInfo;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  processSavedDamage(savedDamage, damageWeightedByType, battleValues);&lt;br /&gt;
&lt;br /&gt;
  return damageWeightedByType;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcPhysicalSkillDamage(battleValues) {&lt;br /&gt;
  const {&lt;br /&gt;
    attackFactor,&lt;br /&gt;
    mainAttackValue,&lt;br /&gt;
    attackValues: {&lt;br /&gt;
      minAttackValue,&lt;br /&gt;
      maxAttackValue,&lt;br /&gt;
      attackValueOther,&lt;br /&gt;
      weights,&lt;br /&gt;
      criticalAttackRange,&lt;br /&gt;
    },&lt;br /&gt;
    bonusValues,&lt;br /&gt;
    damageWeightedByType,&lt;br /&gt;
    skillFormula,&lt;br /&gt;
    skillRange: [minVariation, maxVariation],&lt;br /&gt;
  } = battleValues;&lt;br /&gt;
&lt;br /&gt;
  const savedDamage = {};&lt;br /&gt;
&lt;br /&gt;
  for (&lt;br /&gt;
    let attackValue = minAttackValue;&lt;br /&gt;
    attackValue &amp;lt;= maxAttackValue;&lt;br /&gt;
    attackValue++&lt;br /&gt;
  ) {&lt;br /&gt;
    const weight = weights[attackValue - minAttackValue];&lt;br /&gt;
&lt;br /&gt;
    const secondaryAttackValue = 2 * attackValue + attackValueOther;&lt;br /&gt;
    const rawDamage =&lt;br /&gt;
      mainAttackValue + floorMultiplication(attackFactor, secondaryAttackValue);&lt;br /&gt;
&lt;br /&gt;
    const damageWithPrimaryBonuses = calcDamageWithPrimaryBonuses(&lt;br /&gt;
      rawDamage,&lt;br /&gt;
      bonusValues&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    const damageValues =&lt;br /&gt;
      damageWithPrimaryBonuses &amp;lt;= 2&lt;br /&gt;
        ? [1, 2, 3, 4, 5]&lt;br /&gt;
        : [damageWithPrimaryBonuses];&lt;br /&gt;
    const weightByDamage = weight / damageValues.length;&lt;br /&gt;
&lt;br /&gt;
    for (let variation = minVariation; variation &amp;lt;= maxVariation; variation++) {&lt;br /&gt;
      for (const damage of damageValues) {&lt;br /&gt;
        const damageWithFormula = skillFormula(&lt;br /&gt;
          damage * bonusValues.useDamage,&lt;br /&gt;
          variation&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        let damageKey = damageWithFormula;&lt;br /&gt;
&lt;br /&gt;
        if (damageWithPrimaryBonuses &amp;lt; bonusValues.defenseBoost) {&lt;br /&gt;
          damageKey = `${damageWithFormula}_${damageWithPrimaryBonuses}`;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        const entry = savedDamage[damageKey];&lt;br /&gt;
&lt;br /&gt;
        if (entry) {&lt;br /&gt;
          entry[0] += weightByDamage;&lt;br /&gt;
          continue;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        const damageByType = [[], [], [], []];&lt;br /&gt;
        const currentDamageInfo = [weightByDamage, damageByType];&lt;br /&gt;
&lt;br /&gt;
        const finalDamage = Math.floor(&lt;br /&gt;
          (damageWithFormula * bonusValues.weaponBonusCoeff) / 100&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        saveFinalSkillDamage(&lt;br /&gt;
          finalDamage,&lt;br /&gt;
          bonusValues,&lt;br /&gt;
          criticalAttackRange,&lt;br /&gt;
          damageByType&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        savedDamage[damageKey] = currentDamageInfo;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  processSavedDamage(savedDamage, damageWeightedByType, battleValues);&lt;br /&gt;
&lt;br /&gt;
  return damageWeightedByType;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcMagicSkillDamage(battleValues) {&lt;br /&gt;
  const {&lt;br /&gt;
    attackValues: {&lt;br /&gt;
      minMagicAttackValue,&lt;br /&gt;
      maxMagicAttackValue,&lt;br /&gt;
      magicAttackValueAugmentation,&lt;br /&gt;
      weights,&lt;br /&gt;
      criticalAttackRange,&lt;br /&gt;
    },&lt;br /&gt;
    bonusValues,&lt;br /&gt;
    damageWeightedByType,&lt;br /&gt;
    skillFormula,&lt;br /&gt;
    skillRange: [minVariation, maxVariation],&lt;br /&gt;
  } = battleValues;&lt;br /&gt;
&lt;br /&gt;
  const savedDamage = {};&lt;br /&gt;
&lt;br /&gt;
  for (&lt;br /&gt;
    let magicAttackValue = minMagicAttackValue;&lt;br /&gt;
    magicAttackValue &amp;lt;= maxMagicAttackValue;&lt;br /&gt;
    magicAttackValue++&lt;br /&gt;
  ) {&lt;br /&gt;
    const index = magicAttackValue - minMagicAttackValue;&lt;br /&gt;
    const weight = weights[index];&lt;br /&gt;
&lt;br /&gt;
    for (let variation = minVariation; variation &amp;lt;= maxVariation; variation++) {&lt;br /&gt;
      const rawDamage = skillFormula(&lt;br /&gt;
        magicAttackValue + magicAttackValueAugmentation[index],&lt;br /&gt;
        variation&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      const entry = savedDamage[rawDamage];&lt;br /&gt;
&lt;br /&gt;
      if (entry) {&lt;br /&gt;
        entry[0] += weight;&lt;br /&gt;
        continue;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      const damageByType = [[], [], [], []];&lt;br /&gt;
      const currentDamageInfo = [weight, damageByType];&lt;br /&gt;
&lt;br /&gt;
      let damageWithPrimaryBonuses = Math.floor(&lt;br /&gt;
        (rawDamage * bonusValues.weaponBonusCoeff) / 100&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      damageWithPrimaryBonuses = calcDamageWithPrimaryBonuses(&lt;br /&gt;
        damageWithPrimaryBonuses,&lt;br /&gt;
        bonusValues&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      const damageValues =&lt;br /&gt;
        damageWithPrimaryBonuses &amp;lt;= 2&lt;br /&gt;
          ? [1, 2, 3, 4, 5]&lt;br /&gt;
          : [damageWithPrimaryBonuses];&lt;br /&gt;
&lt;br /&gt;
      for (const damage of damageValues) {&lt;br /&gt;
        saveFinalSkillDamage(&lt;br /&gt;
          damage,&lt;br /&gt;
          bonusValues,&lt;br /&gt;
          criticalAttackRange,&lt;br /&gt;
          damageByType&lt;br /&gt;
        );&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      savedDamage[rawDamage] = currentDamageInfo;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  processSavedDamage(savedDamage, damageWeightedByType, battleValues);&lt;br /&gt;
&lt;br /&gt;
  return damageWeightedByType;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcDamage(&lt;br /&gt;
  attacker,&lt;br /&gt;
  victim,&lt;br /&gt;
  attackType,&lt;br /&gt;
  battle,&lt;br /&gt;
  removeSkillVariation&lt;br /&gt;
) {&lt;br /&gt;
  var damageCalculator, skillId, skillType;&lt;br /&gt;
&lt;br /&gt;
  if (attackType === &amp;quot;physical&amp;quot;) {&lt;br /&gt;
    damageCalculator = calcPhysicalDamage;&lt;br /&gt;
  } else if (attackType.startsWith(&amp;quot;attackSkill&amp;quot;)) {&lt;br /&gt;
    skillId = Number(attackType.split(&amp;quot;attackSkill&amp;quot;)[1]);&lt;br /&gt;
&lt;br /&gt;
    if (isMagicClass(attacker) || isDispell(attacker, skillId)) {&lt;br /&gt;
      skillType = &amp;quot;magic&amp;quot;;&lt;br /&gt;
      damageCalculator = calcMagicSkillDamage;&lt;br /&gt;
    } else {&lt;br /&gt;
      skillType = &amp;quot;physical&amp;quot;;&lt;br /&gt;
      damageCalculator = calcPhysicalSkillDamage;&lt;br /&gt;
    }&lt;br /&gt;
  } else if (attackType.startsWith(&amp;quot;horseSkill&amp;quot;)) {&lt;br /&gt;
    skillType = &amp;quot;physical&amp;quot;;&lt;br /&gt;
    skillId = Number(attackType.split(&amp;quot;horseSkill&amp;quot;)[1]);&lt;br /&gt;
    damageCalculator = calcPhysicalSkillDamage;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var battleValues = createBattleValues(attacker, victim, battle, skillType);&lt;br /&gt;
&lt;br /&gt;
  if (skillId) {&lt;br /&gt;
    getSkillFormula(battle, skillId, battleValues, removeSkillVariation);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    damageWeightedByType: damageCalculator(battleValues),&lt;br /&gt;
    attackValues: battleValues.attackValues,&lt;br /&gt;
    skillType: skillType,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function damageWithoutVariation(&lt;br /&gt;
  attacker,&lt;br /&gt;
  victim,&lt;br /&gt;
  attackType,&lt;br /&gt;
  battle,&lt;br /&gt;
  characters&lt;br /&gt;
) {&lt;br /&gt;
  var startDamageTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
  var { damageWeightedByType, attackValues, skillType } = calcDamage(&lt;br /&gt;
    attacker,&lt;br /&gt;
    victim,&lt;br /&gt;
    attackType,&lt;br /&gt;
    battle&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  var endDamageTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
  displayResults(&lt;br /&gt;
    attackValues,&lt;br /&gt;
    damageWeightedByType,&lt;br /&gt;
    battle,&lt;br /&gt;
    attacker.name,&lt;br /&gt;
    victim.name&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  var endDisplayTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
  displayFightInfo(&lt;br /&gt;
    attackValues.possibleDamageCount,&lt;br /&gt;
    endDamageTime - startDamageTime,&lt;br /&gt;
    endDisplayTime - endDamageTime,&lt;br /&gt;
    battle&lt;br /&gt;
  );&lt;br /&gt;
  addPotentialErrorInformation(&lt;br /&gt;
    battle.errorInformation,&lt;br /&gt;
    attacker,&lt;br /&gt;
    victim,&lt;br /&gt;
    skillType,&lt;br /&gt;
    characters&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  hideElement(battle.bonusVariationResultContainer);&lt;br /&gt;
  showElement(battle.fightResultTitle);&lt;br /&gt;
  showElement(battle.fightResultContainer);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function damageWithVariation(&lt;br /&gt;
  attacker,&lt;br /&gt;
  victim,&lt;br /&gt;
  attackType,&lt;br /&gt;
  battle,&lt;br /&gt;
  entity,&lt;br /&gt;
  entityVariation&lt;br /&gt;
) {&lt;br /&gt;
  var startTime = performance.now();&lt;br /&gt;
  var damageByBonus = [];&lt;br /&gt;
  var augmentationByBonus = [];&lt;br /&gt;
  var {&lt;br /&gt;
    bonusVariationMinValue: minVariation,&lt;br /&gt;
    bonusVariationMaxValue: maxVariation,&lt;br /&gt;
  } = entity;&lt;br /&gt;
  var step = Math.ceil((maxVariation - minVariation + 1) / 500);&lt;br /&gt;
  var simulationCount = 0;&lt;br /&gt;
  var simulationTime;&lt;br /&gt;
  var firstDamage = 1;&lt;br /&gt;
&lt;br /&gt;
  for (&lt;br /&gt;
    var bonusValue = minVariation;&lt;br /&gt;
    bonusValue &amp;lt;= maxVariation;&lt;br /&gt;
    bonusValue += step&lt;br /&gt;
  ) {&lt;br /&gt;
    entity[entityVariation] = bonusValue;&lt;br /&gt;
&lt;br /&gt;
    var {&lt;br /&gt;
      damageWeightedByType,&lt;br /&gt;
      attackValues: { totalCardinal },&lt;br /&gt;
    } = calcDamage(&lt;br /&gt;
      copyObject(attacker),&lt;br /&gt;
      copyObject(victim),&lt;br /&gt;
      attackType,&lt;br /&gt;
      battle,&lt;br /&gt;
      true&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    var meanDamage = calcMeanDamage(damageWeightedByType, totalCardinal);&lt;br /&gt;
&lt;br /&gt;
    if (bonusValue === minVariation) {&lt;br /&gt;
      firstDamage = Math.max(meanDamage, 1e-3);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    damageByBonus.push({ x: bonusValue, y: meanDamage });&lt;br /&gt;
    augmentationByBonus.push({&lt;br /&gt;
      x: bonusValue,&lt;br /&gt;
      y: meanDamage / firstDamage - 1,&lt;br /&gt;
    });&lt;br /&gt;
    simulationCount++;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var endTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
  battle.damageByBonus = damageByBonus.concat(entityVariation);&lt;br /&gt;
&lt;br /&gt;
  addToBonusVariationChart(&lt;br /&gt;
    damageByBonus,&lt;br /&gt;
    augmentationByBonus,&lt;br /&gt;
    entity.bonusVariationName,&lt;br /&gt;
    battle.bonusVariationChart&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  simulationCount = battle.numberFormats.default.format(simulationCount);&lt;br /&gt;
  simulationTime = battle.numberFormats.second.format(&lt;br /&gt;
    (endTime - startTime) / 1000&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  battle.simulationCounter.textContent = simulationCount;&lt;br /&gt;
  battle.simulationTime.textContent = simulationTime;&lt;br /&gt;
&lt;br /&gt;
  hideElement(battle.fightResultContainer);&lt;br /&gt;
  showElement(battle.fightResultTitle);&lt;br /&gt;
  showElement(battle.bonusVariationResultContainer);&lt;br /&gt;
&lt;br /&gt;
  if (&lt;br /&gt;
    isChecked(attacker.useBonusVariation) &amp;amp;&amp;amp;&lt;br /&gt;
    isChecked(victim.useBonusVariation)&lt;br /&gt;
  ) {&lt;br /&gt;
    showElement(battle.errorInformation[&amp;quot;attacker-victim-variation&amp;quot;]);&lt;br /&gt;
  } else {&lt;br /&gt;
    hideElement(battle.errorInformation[&amp;quot;attacker-victim-variation&amp;quot;]);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function changeMonsterValues(monster, instance, attacker) {&lt;br /&gt;
  switch (instance) {&lt;br /&gt;
    case &amp;quot;SungMahiTower&amp;quot;:&lt;br /&gt;
      var sungMahiFloor = 1;&lt;br /&gt;
      var sungMahiStep = 1;&lt;br /&gt;
      var rawDefense = 120;&lt;br /&gt;
&lt;br /&gt;
      if (isPC(attacker)) {&lt;br /&gt;
        sungMahiFloor = attacker.sungMahiFloor;&lt;br /&gt;
        sungMahiStep = attacker.sungMahiStep;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (monster.rank === 5) {&lt;br /&gt;
        monster.level = 121;&lt;br /&gt;
        monster.dex = 75;&lt;br /&gt;
        rawDefense += 1;&lt;br /&gt;
      } else if (monster.rank === 6) {&lt;br /&gt;
        monster.level = 123;&lt;br /&gt;
        monster.dex = 75;&lt;br /&gt;
        rawDefense += 1;&lt;br /&gt;
      } else {&lt;br /&gt;
        monster.level = 120;&lt;br /&gt;
        monster.dex = 68;&lt;br /&gt;
      }&lt;br /&gt;
      monster.vit = 100;&lt;br /&gt;
      monster.rawDefense = rawDefense + (sungMahiStep - 1) * 6;&lt;br /&gt;
      monster.fistDefense = 0;&lt;br /&gt;
      monster.swordDefense = 0;&lt;br /&gt;
      monster.twoHandedSwordDefense = 0;&lt;br /&gt;
      monster.daggerDefense = 0;&lt;br /&gt;
      monster.bellDefense = 0;&lt;br /&gt;
      monster.fanDefense = 0;&lt;br /&gt;
      monster.arrowDefense = 0;&lt;br /&gt;
      monster.clawDefense = 0;&lt;br /&gt;
      monster.magicResistance = 0;&lt;br /&gt;
      monster.fireResistance = -20;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  switch (monster.vnum) {&lt;br /&gt;
    // Alastor&lt;br /&gt;
    case 6790:&lt;br /&gt;
      monster.iceResistance = 0;&lt;br /&gt;
      monster.iceBonus = 0;&lt;br /&gt;
      monster.lightningResistance = -10;&lt;br /&gt;
      monster.lightningBonus = 65;&lt;br /&gt;
      break;&lt;br /&gt;
&lt;br /&gt;
    // Zodiac boss&lt;br /&gt;
    case 2752:&lt;br /&gt;
    case 2762:&lt;br /&gt;
    case 2772:&lt;br /&gt;
    case 2782:&lt;br /&gt;
    case 2792:&lt;br /&gt;
    case 2802:&lt;br /&gt;
    case 2812:&lt;br /&gt;
    case 2822:&lt;br /&gt;
    case 2832:&lt;br /&gt;
    case 2842:&lt;br /&gt;
    case 2852:&lt;br /&gt;
    case 2862:&lt;br /&gt;
      monster.level = 136;&lt;br /&gt;
      monster.vit = 200;&lt;br /&gt;
      monster.rawDefense = 5000;&lt;br /&gt;
      break;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createWeapon(vnum) {&lt;br /&gt;
  var weapon = copyObject(weaponData[vnum]);&lt;br /&gt;
  var serpentVnums = [360, 380, 1210, 2230, 3250, 5200, 6150, 7330];&lt;br /&gt;
  var weaponValues = weapon[1];&lt;br /&gt;
  var isSerpent = isValueInArray(Number(vnum), serpentVnums);&lt;br /&gt;
  var isSpecial = Array.isArray(weaponValues[0]);&lt;br /&gt;
  var isMagic;&lt;br /&gt;
&lt;br /&gt;
  if (isSpecial) {&lt;br /&gt;
    isMagic = weaponValues[0][1] &amp;gt; 0;&lt;br /&gt;
  } else {&lt;br /&gt;
    isMagic = weaponValues[1] &amp;gt; 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    type: weapon[0],&lt;br /&gt;
    maxUpgrade: weapon[2].length - 1,&lt;br /&gt;
    isSerpent: isSerpent,&lt;br /&gt;
    isMagic: isMagic,&lt;br /&gt;
    getValues: function (upgrade) {&lt;br /&gt;
      var currentWeaponValues = weaponValues;&lt;br /&gt;
&lt;br /&gt;
      if (upgrade === undefined) {&lt;br /&gt;
        // rare bug when weaponUpgrade is deleted&lt;br /&gt;
        console.warn(&amp;quot;WeaponUpgrade is missing.&amp;quot;);&lt;br /&gt;
        upgrade = this.maxUpgrade;&lt;br /&gt;
      }&lt;br /&gt;
      upgrade = Math.min(upgrade, this.maxUpgrade);&lt;br /&gt;
&lt;br /&gt;
      if (isSpecial) {&lt;br /&gt;
        currentWeaponValues = weaponValues[upgrade];&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      this.minAttackValue = currentWeaponValues[2];&lt;br /&gt;
      this.maxAttackValue = currentWeaponValues[3];&lt;br /&gt;
      this.minMagicAttackValue = currentWeaponValues[0];&lt;br /&gt;
      this.maxMagicAttackValue = currentWeaponValues[1];&lt;br /&gt;
      this.growth = weapon[2][upgrade];&lt;br /&gt;
    },&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createMonster(&lt;br /&gt;
  monsterVnum,&lt;br /&gt;
  translateMonster,&lt;br /&gt;
  attacker,&lt;br /&gt;
  polymorphMonster&lt;br /&gt;
) {&lt;br /&gt;
  var monsterAttributes = monsterData[monsterVnum];&lt;br /&gt;
&lt;br /&gt;
  var monster = {&lt;br /&gt;
    vnum: Number(monsterVnum),&lt;br /&gt;
    name: translateMonster&lt;br /&gt;
      ? getTranslatedMonsterName(monsterVnum)&lt;br /&gt;
      : monsterAttributes[36],&lt;br /&gt;
    rank: monsterAttributes[0],&lt;br /&gt;
    race: monsterAttributes[1],&lt;br /&gt;
    attack: monsterAttributes[2],&lt;br /&gt;
    level: monsterAttributes[3],&lt;br /&gt;
    type: monsterAttributes[4],&lt;br /&gt;
    str: monsterAttributes[5],&lt;br /&gt;
    dex: monsterAttributes[6],&lt;br /&gt;
    vit: monsterAttributes[7],&lt;br /&gt;
    int: monsterAttributes[8],&lt;br /&gt;
    minAttackValue: monsterAttributes[9],&lt;br /&gt;
    maxAttackValue: monsterAttributes[10],&lt;br /&gt;
    rawDefense: monsterAttributes[11],&lt;br /&gt;
    criticalHit: monsterAttributes[12],&lt;br /&gt;
    piercingHit: monsterAttributes[13],&lt;br /&gt;
    fistDefense: monsterAttributes[14],&lt;br /&gt;
    swordDefense: monsterAttributes[15],&lt;br /&gt;
    twoHandedSwordDefense: monsterAttributes[16],&lt;br /&gt;
    daggerDefense: monsterAttributes[17],&lt;br /&gt;
    bellDefense: monsterAttributes[18],&lt;br /&gt;
    fanDefense: monsterAttributes[19],&lt;br /&gt;
    arrowDefense: monsterAttributes[20],&lt;br /&gt;
    clawDefense: monsterAttributes[21],&lt;br /&gt;
    fireResistance: monsterAttributes[22],&lt;br /&gt;
    lightningResistance: monsterAttributes[23],&lt;br /&gt;
    magicResistance: monsterAttributes[24],&lt;br /&gt;
    windResistance: monsterAttributes[25],&lt;br /&gt;
    lightningBonus: monsterAttributes[26],&lt;br /&gt;
    fireBonus: monsterAttributes[27],&lt;br /&gt;
    iceBonus: monsterAttributes[28],&lt;br /&gt;
    windBonus: monsterAttributes[29],&lt;br /&gt;
    earthBonus: monsterAttributes[30],&lt;br /&gt;
    darknessBonus: monsterAttributes[31],&lt;br /&gt;
    darknessResistance: monsterAttributes[32],&lt;br /&gt;
    iceResistance: monsterAttributes[33],&lt;br /&gt;
    earthResistance: monsterAttributes[34],&lt;br /&gt;
    damageMultiplier: monsterAttributes[35],&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  // monster.instance = 0;&lt;br /&gt;
&lt;br /&gt;
  // if (attacker &amp;amp;&amp;amp; monster.instance === 0) {&lt;br /&gt;
  //   changeMonsterValues(monster, &amp;quot;SungMahiTower&amp;quot;, attacker);&lt;br /&gt;
  // }&lt;br /&gt;
  if (!polymorphMonster) {&lt;br /&gt;
    changeMonsterValues(monster);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  monster.defense = monster.rawDefense + monster.level + monster.vit;&lt;br /&gt;
&lt;br /&gt;
  return monster;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addPotentialErrorInformation(&lt;br /&gt;
  errorInformation,&lt;br /&gt;
  attacker,&lt;br /&gt;
  victim,&lt;br /&gt;
  skillType,&lt;br /&gt;
  characters&lt;br /&gt;
) {&lt;br /&gt;
  for (var error of Object.values(errorInformation)) {&lt;br /&gt;
    hideElement(error);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker)) {&lt;br /&gt;
    if (isRiding(attacker)) {&lt;br /&gt;
      if (attacker.horsePoint === 0) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;horse-level&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
      showElement(errorInformation[&amp;quot;horse-stat&amp;quot;]);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isPolymorph(attacker)) {&lt;br /&gt;
      if (attacker.polymorphPoint === 0) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;polymorph-level&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (&lt;br /&gt;
        (attacker.polymorphPoint &amp;lt;= 39 &amp;amp;&amp;amp; attacker.attackValuePercent &amp;lt;= 199) ||&lt;br /&gt;
        (attacker.polymorphPoint === 40 &amp;amp;&amp;amp; attacker.attackValuePercent &amp;lt;= 299)&lt;br /&gt;
      ) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;polymorph-bonus&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
    if (skillType === &amp;quot;magic&amp;quot; &amp;amp;&amp;amp; !isDispell(attacker, 6)) {&lt;br /&gt;
      if (attacker.magicAttackValue) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;magic-attack-value-bonus&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
      if (victim.magicResistance) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;magic-resistance&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
      if (victim.magicResistance &amp;gt; 0 &amp;amp;&amp;amp; attacker.magicPenetration) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;magic-penetration&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    showElement(errorInformation[&amp;quot;monster-attacker&amp;quot;]);&lt;br /&gt;
    if (isMagicAttacker(attacker) &amp;amp;&amp;amp; victim.magicResistance) {&lt;br /&gt;
      showElement(errorInformation[&amp;quot;magic-resistance&amp;quot;]);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (isPC(victim)) {&lt;br /&gt;
    if (isRiding(victim)) {&lt;br /&gt;
      showElement(errorInformation[&amp;quot;horse-stat&amp;quot;]);&lt;br /&gt;
    }&lt;br /&gt;
    if (isPolymorph(victim)) {&lt;br /&gt;
      if (attacker.polymorphPoint === 0) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;polymorph-level&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
      showElement(errorInformation[&amp;quot;polymorph-defense&amp;quot;]);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (characters.unsavedChanges) {&lt;br /&gt;
    showElement(errorInformation[&amp;quot;save&amp;quot;]);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function reduceChartPointsListener(battle) {&lt;br /&gt;
  var {&lt;br /&gt;
    reduceChartPointsContainer,&lt;br /&gt;
    reduceChartPoints,&lt;br /&gt;
    numberFormats: { second: numberFormat },&lt;br /&gt;
    displayTime,&lt;br /&gt;
  } = battle;&lt;br /&gt;
&lt;br /&gt;
  reduceChartPoints.addEventListener(&amp;quot;change&amp;quot;, function () {&lt;br /&gt;
    reduceChartPoints.disabled = true;&lt;br /&gt;
&lt;br /&gt;
    var startDisplayTime = performance.now();&lt;br /&gt;
    var scatterDataByType = battle.scatterDataByType;&lt;br /&gt;
    var {&lt;br /&gt;
      chart,&lt;br /&gt;
      maxPoints,&lt;br /&gt;
      chart: {&lt;br /&gt;
        data: { datasets },&lt;br /&gt;
      },&lt;br /&gt;
    } = battle.damageChart;&lt;br /&gt;
    var addAnimations = false;&lt;br /&gt;
&lt;br /&gt;
    for (var index = 0; index &amp;lt; datasets.length; index++) {&lt;br /&gt;
      var dataset = datasets[index];&lt;br /&gt;
      var scatterData = scatterDataByType[dataset.name];&lt;br /&gt;
&lt;br /&gt;
      if (dataset.canBeReduced &amp;amp;&amp;amp; reduceChartPoints.checked) {&lt;br /&gt;
        dataset.data = aggregateDamage(scatterData, maxPoints);&lt;br /&gt;
        addAnimations = true;&lt;br /&gt;
      } else {&lt;br /&gt;
        dataset.data = scatterData;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    handleChartAnimations(chart, addAnimations);&lt;br /&gt;
    chart.update();&lt;br /&gt;
&lt;br /&gt;
    displayTime.textContent = numberFormat.format(&lt;br /&gt;
      (performance.now() - startDisplayTime) / 1000&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    setTimeout(function () {&lt;br /&gt;
      reduceChartPoints.disabled = false;&lt;br /&gt;
    }, 1000);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  reduceChartPointsContainer.addEventListener(&amp;quot;pointerup&amp;quot;, function (event) {&lt;br /&gt;
    if (event.pointerType === &amp;quot;mouse&amp;quot;) {&lt;br /&gt;
      if (event.target.closest(&amp;quot;label&amp;quot;)) {&lt;br /&gt;
        return;&lt;br /&gt;
      }&lt;br /&gt;
      reduceChartPoints.click();&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function downloadRawDataListener(battle) {&lt;br /&gt;
  var { downLoadRawData, downLoadRawDataVariation } = battle;&lt;br /&gt;
  var fileType = &amp;quot;text/csv;charset=utf-8;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  downLoadRawData.addEventListener(&amp;quot;click&amp;quot;, function () {&lt;br /&gt;
    var damageWeightedByType = battle.damageWeightedByType;&lt;br /&gt;
    var filename = &amp;quot;raw_damage.csv&amp;quot;;&lt;br /&gt;
    var csvContent = &amp;quot;damage,probabilities,damageType\n&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    for (var damageType in damageWeightedByType) {&lt;br /&gt;
      var damageWeighted = damageWeightedByType[damageType];&lt;br /&gt;
&lt;br /&gt;
      for (var damage in damageWeighted) {&lt;br /&gt;
        csvContent +=&lt;br /&gt;
          damage + &amp;quot;,&amp;quot; + damageWeighted[damage] + &amp;quot;,&amp;quot; + damageType + &amp;quot;\n&amp;quot;;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    downloadData(csvContent, fileType, filename);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  downLoadRawDataVariation.addEventListener(&amp;quot;click&amp;quot;, function () {&lt;br /&gt;
    var damageByBonus = battle.damageByBonus;&lt;br /&gt;
    var damageByBonusLength = damageByBonus.length;&lt;br /&gt;
    var filename = &amp;quot;damage_variation.csv&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    if (!damageByBonusLength) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var csvContent =&lt;br /&gt;
      damageByBonus[damageByBonusLength - 1] + &amp;quot;,averageDamage\n&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    for (var index = 0; index &amp;lt; damageByBonusLength - 1; index++) {&lt;br /&gt;
      var row = damageByBonus[index];&lt;br /&gt;
&lt;br /&gt;
      csvContent += row.x + &amp;quot;,&amp;quot; + row.y + &amp;quot;\n&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    downloadData(csvContent, fileType, filename);&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function displayResults(&lt;br /&gt;
  attackValues,&lt;br /&gt;
  damageWeightedByType,&lt;br /&gt;
  battle,&lt;br /&gt;
  attackerName,&lt;br /&gt;
  victimName&lt;br /&gt;
) {&lt;br /&gt;
  var [meanDamage, minDamage, maxDamage, scatterDataByType, uniqueDamageCount] =&lt;br /&gt;
    prepareDamageData(damageWeightedByType, attackValues);&lt;br /&gt;
&lt;br /&gt;
  addToDamageChart(battle, scatterDataByType);&lt;br /&gt;
  updateDamageChartDescription(battle, uniqueDamageCount);&lt;br /&gt;
  displayFightResults(&lt;br /&gt;
    battle,&lt;br /&gt;
    attackerName,&lt;br /&gt;
    victimName,&lt;br /&gt;
    meanDamage,&lt;br /&gt;
    minDamage,&lt;br /&gt;
    maxDamage&lt;br /&gt;
  );&lt;br /&gt;
  battle.damageWeightedByType = damageWeightedByType;&lt;br /&gt;
  battle.scatterDataByType = scatterDataByType;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function displayFightResults(&lt;br /&gt;
  battle,&lt;br /&gt;
  attackerName,&lt;br /&gt;
  victimName,&lt;br /&gt;
  meanDamage,&lt;br /&gt;
  minDamage,&lt;br /&gt;
  maxDamage&lt;br /&gt;
) {&lt;br /&gt;
  var {&lt;br /&gt;
    tableResultFight,&lt;br /&gt;
    tableResultHistory,&lt;br /&gt;
    savedFights,&lt;br /&gt;
    numberFormats: { default: numberFormat },&lt;br /&gt;
    deleteFightTemplate,&lt;br /&gt;
  } = battle;&lt;br /&gt;
&lt;br /&gt;
  hideElement(tableResultHistory.rows[1]);&lt;br /&gt;
&lt;br /&gt;
  var valuesToDisplay = [&lt;br /&gt;
    attackerName,&lt;br /&gt;
    victimName,&lt;br /&gt;
    battle.battleChoice.attackType.selectedText,&lt;br /&gt;
    meanDamage,&lt;br /&gt;
    minDamage,&lt;br /&gt;
    maxDamage,&lt;br /&gt;
  ];&lt;br /&gt;
&lt;br /&gt;
  savedFights.push(valuesToDisplay);&lt;br /&gt;
  updateSavedFights(savedFights);&lt;br /&gt;
&lt;br /&gt;
  editTableResultRow(tableResultFight.rows[1], valuesToDisplay, numberFormat);&lt;br /&gt;
  addRowToTableResultHistory(&lt;br /&gt;
    tableResultHistory,&lt;br /&gt;
    valuesToDisplay,&lt;br /&gt;
    deleteFightTemplate,&lt;br /&gt;
    numberFormat&lt;br /&gt;
  );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function displayFightInfo(&lt;br /&gt;
  possibleDamageCount,&lt;br /&gt;
  damageTimeDuration,&lt;br /&gt;
  displayTimeDuration,&lt;br /&gt;
  battle&lt;br /&gt;
) {&lt;br /&gt;
  const {&lt;br /&gt;
    damageInfoContainer,&lt;br /&gt;
    numberFormats: { default: defaultFormat, second: secondFormat },&lt;br /&gt;
    possibleDamageCounter,&lt;br /&gt;
    damageTime,&lt;br /&gt;
    displayTime,&lt;br /&gt;
  } = battle;&lt;br /&gt;
&lt;br /&gt;
  if (possibleDamageCount &amp;lt;= 1) {&lt;br /&gt;
    hideElement(damageInfoContainer);&lt;br /&gt;
    return;&lt;br /&gt;
  } else {&lt;br /&gt;
    showElement(damageInfoContainer);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  possibleDamageCount = defaultFormat.format(possibleDamageCount);&lt;br /&gt;
  damageTimeDuration = secondFormat.format(damageTimeDuration / 1000);&lt;br /&gt;
  displayTimeDuration = secondFormat.format(displayTimeDuration / 1000);&lt;br /&gt;
&lt;br /&gt;
  possibleDamageCounter.textContent = possibleDamageCount;&lt;br /&gt;
  damageTime.textContent = damageTimeDuration;&lt;br /&gt;
  displayTime.textContent = displayTimeDuration;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function parseTypeAndName(data) {&lt;br /&gt;
  var [type, nameOrVnum] = splitFirst(data, &amp;quot;-&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    type: type,&lt;br /&gt;
    nameOrVnum: nameOrVnum,&lt;br /&gt;
    isCharacter: type === &amp;quot;character&amp;quot;,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isCharacterSelected(characterName, selected) {&lt;br /&gt;
  if (!selected) {&lt;br /&gt;
    return false;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var { nameOrVnum, isCharacter } = parseTypeAndName(selected);&lt;br /&gt;
&lt;br /&gt;
  return nameOrVnum === characterName &amp;amp;&amp;amp; isCharacter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function useBonusVariationMode(character, variation) {&lt;br /&gt;
  return (&lt;br /&gt;
    isChecked(character.useBonusVariation) &amp;amp;&amp;amp;&lt;br /&gt;
    character.hasOwnProperty(variation) &amp;amp;&amp;amp;&lt;br /&gt;
    character.bonusVariationMinValue &amp;lt; character.bonusVariationMaxValue&lt;br /&gt;
  );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createBattle(characters, battle) {&lt;br /&gt;
  var battleChoice = battle.battleChoice;&lt;br /&gt;
  var battleForm = battleChoice.form;&lt;br /&gt;
  var lastInvalidTime = 0;&lt;br /&gt;
&lt;br /&gt;
  battleForm.addEventListener(&amp;quot;change&amp;quot;, handleBattleFormChange);&lt;br /&gt;
  battleForm.addEventListener(&amp;quot;invalid&amp;quot;, handleBattleFormInvalid, true);&lt;br /&gt;
  battleForm.addEventListener(&amp;quot;submit&amp;quot;, handleBattleFormSubmit);&lt;br /&gt;
&lt;br /&gt;
  function handleBattleFormChange(event) {&lt;br /&gt;
    var target = event.target;&lt;br /&gt;
    var { name: targetName, value: targetValue, type: targetType } = target;&lt;br /&gt;
&lt;br /&gt;
    if (targetType !== &amp;quot;radio&amp;quot;) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (targetName === &amp;quot;attackType&amp;quot;) {&lt;br /&gt;
      battleChoice.attackType.selectedText =&lt;br /&gt;
        target.previousElementSibling.textContent;&lt;br /&gt;
    } else {&lt;br /&gt;
      updateBattleChoiceButton(battleChoice, targetName, targetValue);&lt;br /&gt;
&lt;br /&gt;
      if (targetName === &amp;quot;attacker&amp;quot;) {&lt;br /&gt;
        filterAttackTypeSelection(characters, battleChoice, targetValue);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function handleBattleFormInvalid(event) {&lt;br /&gt;
    var currentTime = Date.now();&lt;br /&gt;
&lt;br /&gt;
    if (currentTime - lastInvalidTime &amp;lt; 100) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    lastInvalidTime = currentTime;&lt;br /&gt;
&lt;br /&gt;
    var target = event.target;&lt;br /&gt;
    var modal = target.closest(&amp;quot;.modal&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (!modal) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var dataModal = modal.dataset.modal;&lt;br /&gt;
&lt;br /&gt;
    if (!dataModal) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var category = dataModal.split(&amp;quot;-&amp;quot;)[0];&lt;br /&gt;
&lt;br /&gt;
    if (isValueInArray(category, battleChoice.categories)) {&lt;br /&gt;
      battleChoice[category].button.click();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function handleBattleFormSubmit(event) {&lt;br /&gt;
    event.preventDefault();&lt;br /&gt;
&lt;br /&gt;
    // auto save&lt;br /&gt;
    if (characters.unsavedChanges) {&lt;br /&gt;
      characters.saveButton.click();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var battleInfo = new FormData(event.target);&lt;br /&gt;
    var attackerData = battleInfo.get(&amp;quot;attacker&amp;quot;);&lt;br /&gt;
    var attackType = battleInfo.get(&amp;quot;attackType&amp;quot;);&lt;br /&gt;
    var victimData = battleInfo.get(&amp;quot;victim&amp;quot;);&lt;br /&gt;
    var attackerVariation;&lt;br /&gt;
    var victimVariation;&lt;br /&gt;
&lt;br /&gt;
    if (!attackerData &amp;amp;&amp;amp; !attackType &amp;amp;&amp;amp; !victimData) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var { nameOrVnum: attackerNameOrVnum, isCharacter: attackerIsPlayer } =&lt;br /&gt;
      parseTypeAndName(attackerData);&lt;br /&gt;
    var { nameOrVnum: victimNameOrVnum, isCharacter: victimIsPlayer } =&lt;br /&gt;
      parseTypeAndName(victimData);&lt;br /&gt;
&lt;br /&gt;
    if (attackerIsPlayer) {&lt;br /&gt;
      var attacker = copyObject(characters.savedCharacters[attackerNameOrVnum]);&lt;br /&gt;
      attackerVariation = attacker.bonusVariation;&lt;br /&gt;
    } else {&lt;br /&gt;
      var attacker = createMonster(&lt;br /&gt;
        attackerNameOrVnum,&lt;br /&gt;
        characters.translateMonsters&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (victimIsPlayer) {&lt;br /&gt;
      var victim = copyObject(characters.savedCharacters[victimNameOrVnum]);&lt;br /&gt;
      victimVariation = victim.bonusVariation;&lt;br /&gt;
    } else {&lt;br /&gt;
      var victim = createMonster(&lt;br /&gt;
        victimNameOrVnum,&lt;br /&gt;
        characters.translateMonsters,&lt;br /&gt;
        attacker&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (useBonusVariationMode(attacker, attackerVariation)) {&lt;br /&gt;
      damageWithVariation(&lt;br /&gt;
        attacker,&lt;br /&gt;
        victim,&lt;br /&gt;
        attackType,&lt;br /&gt;
        battle,&lt;br /&gt;
        attacker,&lt;br /&gt;
        attackerVariation&lt;br /&gt;
      );&lt;br /&gt;
    } else if (useBonusVariationMode(victim, victimVariation)) {&lt;br /&gt;
      damageWithVariation(&lt;br /&gt;
        attacker,&lt;br /&gt;
        victim,&lt;br /&gt;
        attackType,&lt;br /&gt;
        battle,&lt;br /&gt;
        victim,&lt;br /&gt;
        victimVariation&lt;br /&gt;
      );&lt;br /&gt;
    } else {&lt;br /&gt;
      damageWithoutVariation(attacker, victim, attackType, battle, characters);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createMapping() {&lt;br /&gt;
  return {&lt;br /&gt;
    typeFlag: [&lt;br /&gt;
      &amp;quot;animalBonus&amp;quot;, // 0&lt;br /&gt;
      &amp;quot;humanBonus&amp;quot;, // 1&lt;br /&gt;
      &amp;quot;orcBonus&amp;quot;, // 2&lt;br /&gt;
      &amp;quot;mysticBonus&amp;quot;, // 3&lt;br /&gt;
      &amp;quot;undeadBonus&amp;quot;, // 4&lt;br /&gt;
      &amp;quot;insectBonus&amp;quot;, // 5&lt;br /&gt;
      &amp;quot;desertBonus&amp;quot;, // 6&lt;br /&gt;
      &amp;quot;devilBonus&amp;quot;, // 7&lt;br /&gt;
      &amp;quot;zodiacBonus&amp;quot;, // 8&lt;br /&gt;
    ],&lt;br /&gt;
    raceBonus: {&lt;br /&gt;
      warrior: &amp;quot;warriorBonus&amp;quot;,&lt;br /&gt;
      sura: &amp;quot;suraBonus&amp;quot;,&lt;br /&gt;
      ninja: &amp;quot;ninjaBonus&amp;quot;,&lt;br /&gt;
      shaman: &amp;quot;shamanBonus&amp;quot;,&lt;br /&gt;
      lycan: &amp;quot;lycanBonus&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    raceResistance: {&lt;br /&gt;
      warrior: &amp;quot;warriorResistance&amp;quot;,&lt;br /&gt;
      sura: &amp;quot;suraResistance&amp;quot;,&lt;br /&gt;
      ninja: &amp;quot;ninjaResistance&amp;quot;,&lt;br /&gt;
      shaman: &amp;quot;shamanResistance&amp;quot;,&lt;br /&gt;
      lycan: &amp;quot;lycanResistance&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    defenseWeapon: [&lt;br /&gt;
      &amp;quot;swordDefense&amp;quot;, // 0&lt;br /&gt;
      &amp;quot;daggerDefense&amp;quot;, // 1&lt;br /&gt;
      &amp;quot;arrowDefense&amp;quot;, // 2&lt;br /&gt;
      &amp;quot;twoHandedSwordDefense&amp;quot;, // 3&lt;br /&gt;
      &amp;quot;bellDefense&amp;quot;, // 4&lt;br /&gt;
      &amp;quot;clawDefense&amp;quot;, // 5&lt;br /&gt;
      &amp;quot;fanDefense&amp;quot;, // 6&lt;br /&gt;
      &amp;quot;swordDefense&amp;quot;, // 7&lt;br /&gt;
      &amp;quot;fistDefense&amp;quot;, // 8&lt;br /&gt;
    ],&lt;br /&gt;
    breakWeapon: [&lt;br /&gt;
      &amp;quot;breakSwordDefense&amp;quot;, // 0&lt;br /&gt;
      &amp;quot;breakDaggerDefense&amp;quot;, // 1&lt;br /&gt;
      &amp;quot;breakArrowDefense&amp;quot;, // 2&lt;br /&gt;
      &amp;quot;breakTwoHandedSwordDefense&amp;quot;, // 3&lt;br /&gt;
      &amp;quot;breakBellDefense&amp;quot;, // 4&lt;br /&gt;
      &amp;quot;breakClawDefense&amp;quot;, // 5&lt;br /&gt;
      &amp;quot;breakFanDefense&amp;quot;, // 6&lt;br /&gt;
      &amp;quot;breakSwordDefense&amp;quot;, // 7&lt;br /&gt;
    ],&lt;br /&gt;
    elementBonus: [&lt;br /&gt;
      &amp;quot;fireBonus&amp;quot;, // 0&lt;br /&gt;
      &amp;quot;iceBonus&amp;quot;, // 1&lt;br /&gt;
      &amp;quot;windBonus&amp;quot;, // 2&lt;br /&gt;
      &amp;quot;lightningBonus&amp;quot;, // 3&lt;br /&gt;
      &amp;quot;earthBonus&amp;quot;, // 4&lt;br /&gt;
      &amp;quot;darknessBonus&amp;quot;, // 5&lt;br /&gt;
    ],&lt;br /&gt;
    elementResistance: [&lt;br /&gt;
      &amp;quot;fireResistance&amp;quot;, // 0&lt;br /&gt;
      &amp;quot;iceResistance&amp;quot;, // 1&lt;br /&gt;
      &amp;quot;windResistance&amp;quot;, // 2&lt;br /&gt;
      &amp;quot;lightningResistance&amp;quot;, // 3&lt;br /&gt;
      &amp;quot;earthResistance&amp;quot;, // 4&lt;br /&gt;
      &amp;quot;darknessResistance&amp;quot;, // 5&lt;br /&gt;
    ],&lt;br /&gt;
    attackType: [&lt;br /&gt;
      &amp;quot;normalHit&amp;quot;,&lt;br /&gt;
      &amp;quot;criticalHit&amp;quot;,&lt;br /&gt;
      &amp;quot;piercingHit&amp;quot;,&lt;br /&gt;
      &amp;quot;criticalPiercingHit&amp;quot;,&lt;br /&gt;
    ],&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createConstants() {&lt;br /&gt;
  var constants = {&lt;br /&gt;
    polymorphPowerTable: [&lt;br /&gt;
      10, 11, 11, 12, 13, 13, 14, 15, 16, 17, 18, 19, 20, 22, 23, 24, 26, 27,&lt;br /&gt;
      29, 31, 33, 35, 37, 39, 41, 44, 46, 49, 52, 55, 59, 62, 66, 70, 74, 79,&lt;br /&gt;
      84, 89, 94, 100, 0,&lt;br /&gt;
    ],&lt;br /&gt;
    skillPowerTable: [&lt;br /&gt;
      0, 0.05, 0.06, 0.08, 0.1, 0.12, 0.14, 0.16, 0.18, 0.2, 0.22, 0.24, 0.26,&lt;br /&gt;
      0.28, 0.3, 0.32, 0.34, 0.36, 0.38, 0.4, 0.5, 0.52, 0.54, 0.56, 0.58, 0.6,&lt;br /&gt;
      0.63, 0.66, 0.69, 0.72, 0.82, 0.85, 0.88, 0.91, 0.94, 0.98, 1.02, 1.06,&lt;br /&gt;
      1.1, 1.15, 1.25,&lt;br /&gt;
    ],&lt;br /&gt;
    marriageTable: {&lt;br /&gt;
      harmonyEarrings: [4, 5, 6, 8],&lt;br /&gt;
      loveEarrings: [4, 5, 6, 8],&lt;br /&gt;
      harmonyBracelet: [4, 5, 6, 8],&lt;br /&gt;
      loveNecklace: [20, 25, 30, 40],&lt;br /&gt;
      harmonyNecklace: [12, 16, 20, 30],&lt;br /&gt;
    },&lt;br /&gt;
    allowedWeaponsPerRace: {&lt;br /&gt;
      warrior: [0, 3, 8],&lt;br /&gt;
      ninja: [0, 1, 2, 8],&lt;br /&gt;
      sura: [0, 7, 8],&lt;br /&gt;
      shaman: [4, 6, 8],&lt;br /&gt;
      lycan: [5, 8],&lt;br /&gt;
    },&lt;br /&gt;
  };&lt;br /&gt;
  return constants;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initResultTableHistory(battle) {&lt;br /&gt;
  var {&lt;br /&gt;
    tableResultHistory,&lt;br /&gt;
    savedFights,&lt;br /&gt;
    deleteFightTemplate,&lt;br /&gt;
    numberFormats: { default: numberFormat },&lt;br /&gt;
  } = battle;&lt;br /&gt;
  var startIndex = 3;&lt;br /&gt;
&lt;br /&gt;
  if (savedFights.length) {&lt;br /&gt;
    hideElement(tableResultHistory.rows[1]);&lt;br /&gt;
&lt;br /&gt;
    for (var savedFight of savedFights) {&lt;br /&gt;
      addRowToTableResultHistory(&lt;br /&gt;
        tableResultHistory,&lt;br /&gt;
        savedFight,&lt;br /&gt;
        deleteFightTemplate,&lt;br /&gt;
        numberFormat&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  tableResultHistory.addEventListener(&amp;quot;click&amp;quot;, function (event) {&lt;br /&gt;
    var deleteButton = event.target.closest(&amp;quot;.svg-icon-delete&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (deleteButton) {&lt;br /&gt;
      var row = deleteButton.closest(&amp;quot;tr&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
      if (row) {&lt;br /&gt;
        savedFights.splice(row.rowIndex - startIndex, 1);&lt;br /&gt;
        updateSavedFights(savedFights);&lt;br /&gt;
&lt;br /&gt;
        row.remove();&lt;br /&gt;
&lt;br /&gt;
        if (tableResultHistory.rows.length === startIndex) {&lt;br /&gt;
          showElement(tableResultHistory.rows[1]);&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initDamageChart(battle, currentLanguage, defaultText) {&lt;br /&gt;
  const { reduceChartPointsContainer, reduceChartPoints } = battle;&lt;br /&gt;
  const { default: defaultFormat, percent: percentFormat } =&lt;br /&gt;
    battle.numberFormats;&lt;br /&gt;
  const customPlugins = {&lt;br /&gt;
    id: &amp;quot;customPlugins&amp;quot;,&lt;br /&gt;
    afterDraw(chart) {&lt;br /&gt;
      const missPercentage = chart.data.missPercentage;&lt;br /&gt;
&lt;br /&gt;
      if (!missPercentage) {&lt;br /&gt;
        return;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      const {&lt;br /&gt;
        ctx,&lt;br /&gt;
        chartArea: { top, right },&lt;br /&gt;
      } = chart;&lt;br /&gt;
      ctx.save();&lt;br /&gt;
      const text =&lt;br /&gt;
        defaultText.miss + &amp;quot; : &amp;quot; + percentFormat.format(missPercentage);&lt;br /&gt;
      const padding = 4;&lt;br /&gt;
      const fontSize = 14;&lt;br /&gt;
&lt;br /&gt;
      ctx.font = fontSize + &amp;quot;px Helvetica Neue&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
      const textWidth = ctx.measureText(text).width;&lt;br /&gt;
      const xPosition = right - textWidth - 5;&lt;br /&gt;
      const yPosition = top + 5;&lt;br /&gt;
&lt;br /&gt;
      ctx.fillStyle = &amp;quot;rgba(255, 0, 0, 0.2)&amp;quot;;&lt;br /&gt;
      ctx.fillRect(&lt;br /&gt;
        xPosition - padding,&lt;br /&gt;
        yPosition - padding,&lt;br /&gt;
        textWidth + 2 * padding,&lt;br /&gt;
        fontSize + 2 * padding&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      ctx.strokeStyle = &amp;quot;red&amp;quot;;&lt;br /&gt;
      ctx.strokeRect(&lt;br /&gt;
        xPosition - padding,&lt;br /&gt;
        yPosition - padding,&lt;br /&gt;
        textWidth + 2 * padding,&lt;br /&gt;
        fontSize + 2 * padding&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      ctx.fillStyle = &amp;quot;#666&amp;quot;;&lt;br /&gt;
      ctx.textBaseline = &amp;quot;top&amp;quot;;&lt;br /&gt;
      ctx.fillText(text, xPosition, yPosition + 1);&lt;br /&gt;
&lt;br /&gt;
      ctx.restore();&lt;br /&gt;
    },&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  Chart.register(customPlugins);&lt;br /&gt;
&lt;br /&gt;
  const ctx = battle.plotDamage.getContext(&amp;quot;2d&amp;quot;);&lt;br /&gt;
  const maxLabelsInTooltip = 10;&lt;br /&gt;
  const nullLabelText = &amp;quot; ...&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  const chart = new Chart(ctx, {&lt;br /&gt;
    type: &amp;quot;scatter&amp;quot;,&lt;br /&gt;
    data: {&lt;br /&gt;
      missPercentage: 0,&lt;br /&gt;
      datasets: [],&lt;br /&gt;
    },&lt;br /&gt;
    options: {&lt;br /&gt;
      locale: currentLanguage,&lt;br /&gt;
      responsive: true,&lt;br /&gt;
      maintainAspectRatio: false,&lt;br /&gt;
      plugins: {&lt;br /&gt;
        legend: {&lt;br /&gt;
          display: true,&lt;br /&gt;
          onHover: function (e) {&lt;br /&gt;
            e.native.target.style.cursor = &amp;quot;pointer&amp;quot;;&lt;br /&gt;
          },&lt;br /&gt;
          onLeave: function (e) {&lt;br /&gt;
            e.native.target.style.cursor = &amp;quot;default&amp;quot;;&lt;br /&gt;
          },&lt;br /&gt;
          onClick: function (e, legendItem, legend) {&lt;br /&gt;
            const currentIndex = legendItem.datasetIndex;&lt;br /&gt;
            const ci = legend.chart;&lt;br /&gt;
            const isCurrentDatasetVisible = ci.isDatasetVisible(currentIndex);&lt;br /&gt;
            const datasets = ci.data.datasets;&lt;br /&gt;
            const isReducePointsChecked = reduceChartPoints.checked;&lt;br /&gt;
            let hideReducePoints = true;&lt;br /&gt;
&lt;br /&gt;
            datasets[currentIndex].hidden = isCurrentDatasetVisible;&lt;br /&gt;
            legendItem.hidden = isCurrentDatasetVisible;&lt;br /&gt;
&lt;br /&gt;
            for (const index in datasets) {&lt;br /&gt;
              if (ci.isDatasetVisible(index) &amp;amp;&amp;amp; datasets[index].canBeReduced) {&lt;br /&gt;
                showElement(reduceChartPointsContainer);&lt;br /&gt;
                hideReducePoints = false;&lt;br /&gt;
                break;&lt;br /&gt;
              }&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            if (hideReducePoints) {&lt;br /&gt;
              hideElement(reduceChartPointsContainer);&lt;br /&gt;
              handleChartAnimations(ci, true);&lt;br /&gt;
            } else {&lt;br /&gt;
              handleChartAnimations(ci, isReducePointsChecked);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            ci.update();&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        title: {&lt;br /&gt;
          display: true,&lt;br /&gt;
          text: defaultText.damageRepartition,&lt;br /&gt;
          font: {&lt;br /&gt;
            size: 20,&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        tooltip: {&lt;br /&gt;
          callbacks: {&lt;br /&gt;
            label: function (context) {&lt;br /&gt;
              if (context.label === null) {&lt;br /&gt;
                return nullLabelText;&lt;br /&gt;
              }&lt;br /&gt;
&lt;br /&gt;
              const xValue = defaultFormat.format(context.parsed.x);&lt;br /&gt;
              const yValue = percentFormat.format(context.parsed.y);&lt;br /&gt;
              const label =&lt;br /&gt;
                &amp;quot; &amp;quot; +&lt;br /&gt;
                context.dataset.label +&lt;br /&gt;
                &amp;quot; : (&amp;quot; +&lt;br /&gt;
                xValue +&lt;br /&gt;
                &amp;quot;, &amp;quot; +&lt;br /&gt;
                yValue +&lt;br /&gt;
                &amp;quot;)&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
              return label;&lt;br /&gt;
            },&lt;br /&gt;
            beforeBody: function (tooltipItems) {&lt;br /&gt;
              if (tooltipItems.length &amp;gt; maxLabelsInTooltip + 1) {&lt;br /&gt;
                tooltipItems.splice(maxLabelsInTooltip + 1);&lt;br /&gt;
                tooltipItems[maxLabelsInTooltip].label = null;&lt;br /&gt;
              }&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          caretPadding: 10,&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
      scales: {&lt;br /&gt;
        x: {&lt;br /&gt;
          type: &amp;quot;linear&amp;quot;,&lt;br /&gt;
          position: &amp;quot;bottom&amp;quot;,&lt;br /&gt;
          title: {&lt;br /&gt;
            display: true,&lt;br /&gt;
            text: defaultText.damage,&lt;br /&gt;
            font: {&lt;br /&gt;
              size: 16,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          ticks: {&lt;br /&gt;
            callback: function (value) {&lt;br /&gt;
              return Number.isInteger(value) ? value : &amp;quot;&amp;quot;;&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        y: {&lt;br /&gt;
          title: {&lt;br /&gt;
            display: true,&lt;br /&gt;
            text: defaultText.percentage,&lt;br /&gt;
            font: {&lt;br /&gt;
              size: 16,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          ticks: {&lt;br /&gt;
            format: {&lt;br /&gt;
              style: &amp;quot;percent&amp;quot;,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
      elements: {&lt;br /&gt;
        point: {&lt;br /&gt;
          borderWidth: 1,&lt;br /&gt;
          radius: 3,&lt;br /&gt;
          hitRadius: 3,&lt;br /&gt;
          hoverRadius: 6,&lt;br /&gt;
          hoverBorderWidth: 2,&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
    },&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  const datasetsStyle = [&lt;br /&gt;
    {&lt;br /&gt;
      name: &amp;quot;normalHit&amp;quot;,&lt;br /&gt;
      canBeReduced: false,&lt;br /&gt;
      label: defaultText.normalHit,&lt;br /&gt;
      backgroundColor: &amp;quot;rgba(75, 192, 192, 0.2)&amp;quot;,&lt;br /&gt;
      borderColor: &amp;quot;rgba(75, 192, 192, 1)&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      name: &amp;quot;piercingHit&amp;quot;,&lt;br /&gt;
      canBeReduced: false,&lt;br /&gt;
      label: defaultText.piercingHit,&lt;br /&gt;
      backgroundColor: &amp;quot;rgba(192, 192, 75, 0.2)&amp;quot;,&lt;br /&gt;
      borderColor: &amp;quot;rgba(192, 192, 75, 1)&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      name: &amp;quot;criticalHit&amp;quot;,&lt;br /&gt;
      canBeReduced: false,&lt;br /&gt;
      label: defaultText.criticalHit,&lt;br /&gt;
      backgroundColor: &amp;quot;rgba(192, 75, 192, 0.2)&amp;quot;,&lt;br /&gt;
      borderColor: &amp;quot;rgba(192, 75, 192, 1)&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      name: &amp;quot;criticalPiercingHit&amp;quot;,&lt;br /&gt;
      canBeReduced: false,&lt;br /&gt;
      label: defaultText.criticalPiercingHit,&lt;br /&gt;
      backgroundColor: &amp;quot;rgba(75, 75, 192, 0.2)&amp;quot;,&lt;br /&gt;
      borderColor: &amp;quot;rgba(75, 75, 192, 1)&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
  ];&lt;br /&gt;
  battle.damageChart = {&lt;br /&gt;
    chart: chart,&lt;br /&gt;
    datasetsStyle: datasetsStyle,&lt;br /&gt;
    maxPoints: 500,&lt;br /&gt;
    reduceChartPointsContainer: reduceChartPointsContainer,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initBonusVariationChart(battle, currentLanguage, defaultText) {&lt;br /&gt;
  const { plotBonusVariation } = battle;&lt;br /&gt;
&lt;br /&gt;
  const ctx = plotBonusVariation.getContext(&amp;quot;2d&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  const chart = new Chart(ctx, {&lt;br /&gt;
    type: &amp;quot;line&amp;quot;,&lt;br /&gt;
    data: {&lt;br /&gt;
      datasets: [&lt;br /&gt;
        {&lt;br /&gt;
          label: defaultText.averageDamage,&lt;br /&gt;
          backgroundColor: &amp;quot;rgba(75, 192, 192, 0.2)&amp;quot;,&lt;br /&gt;
          borderColor: &amp;quot;rgba(75, 192, 192, 1)&amp;quot;,&lt;br /&gt;
          fill: true,&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          label: defaultText.damageAugmentation,&lt;br /&gt;
          backgroundColor: &amp;quot;rgba(192, 192, 75, 0.2)&amp;quot;,&lt;br /&gt;
          borderColor: &amp;quot;rgba(192, 192, 75, 1)&amp;quot;,&lt;br /&gt;
          hidden: true,&lt;br /&gt;
          yTicksFormat: { style: &amp;quot;percent&amp;quot; },&lt;br /&gt;
          fill: true,&lt;br /&gt;
        },&lt;br /&gt;
      ],&lt;br /&gt;
    },&lt;br /&gt;
    options: {&lt;br /&gt;
      locale: currentLanguage,&lt;br /&gt;
      responsive: true,&lt;br /&gt;
      maintainAspectRatio: false,&lt;br /&gt;
      plugins: {&lt;br /&gt;
        legend: {&lt;br /&gt;
          display: true,&lt;br /&gt;
          onHover: function (e) {&lt;br /&gt;
            e.native.target.style.cursor = &amp;quot;pointer&amp;quot;;&lt;br /&gt;
          },&lt;br /&gt;
          onLeave: function (e) {&lt;br /&gt;
            e.native.target.style.cursor = &amp;quot;default&amp;quot;;&lt;br /&gt;
          },&lt;br /&gt;
          onClick: function (e, legendItem, legend) {&lt;br /&gt;
            var currentIndex = legendItem.datasetIndex;&lt;br /&gt;
            var ci = legend.chart;&lt;br /&gt;
            var datasets = ci.data.datasets;&lt;br /&gt;
            var isCurrentDatasetVisible = ci.isDatasetVisible(currentIndex);&lt;br /&gt;
            var yAxis = ci.options.scales.y;&lt;br /&gt;
&lt;br /&gt;
            var otherIndex = currentIndex === 0 ? 1 : 0;&lt;br /&gt;
            var visibleDataset = isCurrentDatasetVisible&lt;br /&gt;
              ? datasets[otherIndex]&lt;br /&gt;
              : datasets[currentIndex];&lt;br /&gt;
&lt;br /&gt;
            datasets[currentIndex].hidden = isCurrentDatasetVisible;&lt;br /&gt;
            datasets[otherIndex].hidden = !isCurrentDatasetVisible;&lt;br /&gt;
&lt;br /&gt;
            yAxis.title.text = visibleDataset.label;&lt;br /&gt;
            yAxis.ticks.format = visibleDataset.yTicksFormat;&lt;br /&gt;
&lt;br /&gt;
            ci.update();&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        title: {&lt;br /&gt;
          display: true,&lt;br /&gt;
          text: defaultText.bonusVariationTitle.split(&amp;quot;[[]]&amp;quot;),&lt;br /&gt;
          font: {&lt;br /&gt;
            size: 18,&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        tooltip: {&lt;br /&gt;
          caretPadding: 10,&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
      scales: {&lt;br /&gt;
        x: {&lt;br /&gt;
          type: &amp;quot;linear&amp;quot;,&lt;br /&gt;
          position: &amp;quot;bottom&amp;quot;,&lt;br /&gt;
          title: {&lt;br /&gt;
            display: true,&lt;br /&gt;
            text: &amp;quot;Bonus&amp;quot;,&lt;br /&gt;
            font: {&lt;br /&gt;
              size: 16,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          ticks: {&lt;br /&gt;
            callback: function (value) {&lt;br /&gt;
              if (Number.isInteger(value)) {&lt;br /&gt;
                return Number(value);&lt;br /&gt;
              }&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        y: {&lt;br /&gt;
          title: {&lt;br /&gt;
            display: true,&lt;br /&gt;
            text: defaultText.averageDamage,&lt;br /&gt;
            font: {&lt;br /&gt;
              size: 16,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
      elements: {&lt;br /&gt;
        point: {&lt;br /&gt;
          borderWidth: 1,&lt;br /&gt;
          radius: 3,&lt;br /&gt;
          hitRadius: 3,&lt;br /&gt;
          hoverRadius: 6,&lt;br /&gt;
          hoverBorderWidth: 2,&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
    },&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  battle.bonusVariationChart = chart;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterAttackTypeSelection(characters, battleChoice, targetValue) {&lt;br /&gt;
  var { nameOrVnum: attackerNameOrVnum, isCharacter: isAttackerPlayer } =&lt;br /&gt;
    parseTypeAndName(targetValue);&lt;br /&gt;
&lt;br /&gt;
  if (isAttackerPlayer) {&lt;br /&gt;
    var attacker = characters.savedCharacters[attackerNameOrVnum];&lt;br /&gt;
    filterAttackTypeSelectionCharacter(attacker, battleChoice.attackType);&lt;br /&gt;
  } else {&lt;br /&gt;
    filterAttackTypeSelectionMonster(battleChoice.attackType);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addBattleData(battle) {&lt;br /&gt;
  var errorElements = document.querySelectorAll(&amp;quot;[data-error]&amp;quot;);&lt;br /&gt;
  var { elements: attackTypeElements, container: attackTypeContainer } =&lt;br /&gt;
    battle.battleChoice.attackType;&lt;br /&gt;
  var attackTypeChilds = attackTypeContainer.children;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; errorElements.length; index++) {&lt;br /&gt;
    var errorElement = errorElements[index];&lt;br /&gt;
    battle.errorInformation[errorElement.dataset.error] = errorElement;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (var index = 1; index &amp;lt; attackTypeChilds.length - 1; index++) {&lt;br /&gt;
    var attackTypeChild = attackTypeChilds[index];&lt;br /&gt;
    var input = attackTypeChild.querySelector(&amp;quot;input&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    attackTypeElements.push({&lt;br /&gt;
      container: attackTypeChild,&lt;br /&gt;
      input: input,&lt;br /&gt;
      inputClass: input.dataset.class,&lt;br /&gt;
      inputValue: input.value,&lt;br /&gt;
    });&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createDamageCalculatorInformation(&lt;br /&gt;
  defaultLang,&lt;br /&gt;
  currentLanguage,&lt;br /&gt;
  defaultText&lt;br /&gt;
) {&lt;br /&gt;
  const characters = {&lt;br /&gt;
    unsavedChanges: false,&lt;br /&gt;
    savedCharacters: {},&lt;br /&gt;
    currentCharacter: null,&lt;br /&gt;
    savedMonsters: getSavedMonsters(),&lt;br /&gt;
    monsterElements: {},&lt;br /&gt;
    characterCreation: document.getElementById(&amp;quot;character-creation&amp;quot;),&lt;br /&gt;
    addNewCharacterButton: document.getElementById(&amp;quot;add-new-character&amp;quot;),&lt;br /&gt;
    dropZone: document.getElementById(&amp;quot;character-drop-zone&amp;quot;),&lt;br /&gt;
    characterInput: document.getElementById(&amp;quot;character-input&amp;quot;),&lt;br /&gt;
    newCharacterTemplate: document.getElementById(&amp;quot;new-character-template&amp;quot;)&lt;br /&gt;
      .children[0],&lt;br /&gt;
    charactersContainer: document.getElementById(&amp;quot;characters-container&amp;quot;),&lt;br /&gt;
    monsterButtonTemplates: document.getElementById(&amp;quot;monster-button-templates&amp;quot;),&lt;br /&gt;
    monsterTemplate: document.getElementById(&amp;quot;new-monster-template&amp;quot;)&lt;br /&gt;
      .children[0],&lt;br /&gt;
    monstersContainer: document.getElementById(&amp;quot;monsters-container&amp;quot;),&lt;br /&gt;
    monsteriFrame: document.getElementById(&amp;quot;monster-iframe&amp;quot;),&lt;br /&gt;
    stoneiFrame: document.getElementById(&amp;quot;stone-iframe&amp;quot;),&lt;br /&gt;
    saveButton: document.getElementById(&amp;quot;save-character&amp;quot;),&lt;br /&gt;
    weaponCategory: document.getElementById(&amp;quot;weapon-category&amp;quot;),&lt;br /&gt;
    weaponDisplay: document.getElementById(&amp;quot;weapon-display&amp;quot;),&lt;br /&gt;
    randomAttackValue: document.getElementById(&amp;quot;random-attack-value&amp;quot;),&lt;br /&gt;
    randomMagicAttackValue: document.getElementById(&lt;br /&gt;
      &amp;quot;random-magic-attack-value&amp;quot;&lt;br /&gt;
    ),&lt;br /&gt;
    toggleSiblings: {},&lt;br /&gt;
    polymorphDisplay: document.getElementById(&amp;quot;polymorph-display&amp;quot;),&lt;br /&gt;
    bonusVariation: {&lt;br /&gt;
      tabButton: document.getElementById(&amp;quot;Variation&amp;quot;),&lt;br /&gt;
      checkbox: document.getElementById(&amp;quot;use-bonus-variation&amp;quot;),&lt;br /&gt;
      input: document.getElementById(&amp;quot;bonus-variation&amp;quot;),&lt;br /&gt;
      inputName: document.getElementById(&amp;quot;bonus-variation-name&amp;quot;),&lt;br /&gt;
      container: document.getElementById(&amp;quot;bonus-variation-creation&amp;quot;),&lt;br /&gt;
      minValue: document.getElementById(&amp;quot;bonus-variation-min-value&amp;quot;),&lt;br /&gt;
      maxValue: document.getElementById(&amp;quot;bonus-variation-max-value&amp;quot;),&lt;br /&gt;
      disabledText: document.getElementById(&amp;quot;bonus-variation-disabled&amp;quot;),&lt;br /&gt;
      selectedText: document.getElementById(&amp;quot;bonus-variation-selected&amp;quot;),&lt;br /&gt;
      displaySpan: document.getElementById(&amp;quot;bonus-variation-display&amp;quot;),&lt;br /&gt;
    },&lt;br /&gt;
    skillElementsToFilter: document.querySelectorAll(&lt;br /&gt;
      &amp;quot;#skill-container [data-class]&amp;quot;&lt;br /&gt;
    ),&lt;br /&gt;
    currentLanguage: currentLanguage,&lt;br /&gt;
    translateMonsters: defaultLang !== currentLanguage,&lt;br /&gt;
    defaultText: defaultText,&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  for (const [pseudo, character] of Object.entries(getSavedCharacters())) {&lt;br /&gt;
    characters.savedCharacters[pseudo] = character;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  document.querySelectorAll(&amp;quot;.toggle-sibling&amp;quot;).forEach(function (element) {&lt;br /&gt;
    const target = element.dataset.target;&lt;br /&gt;
    const sibling = document.getElementById(target);&lt;br /&gt;
    characters.toggleSiblings[element.name] = sibling;&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  const constants = createConstants();&lt;br /&gt;
&lt;br /&gt;
  const battle = {&lt;br /&gt;
    savedFights: getSavedFights(),&lt;br /&gt;
    battleChoice: {&lt;br /&gt;
      resetAttackType: false,&lt;br /&gt;
      form: document.getElementById(&amp;quot;create-battle&amp;quot;),&lt;br /&gt;
      template: document.getElementById(&amp;quot;battle-selection-template&amp;quot;)&lt;br /&gt;
        .children[0],&lt;br /&gt;
      raceToImage: {&lt;br /&gt;
        warrior: &amp;quot;/images/0/0f/Bandeaurougehomme.png&amp;quot;,&lt;br /&gt;
        ninja: &amp;quot;/images/0/0e/Queuedechevalclair.png&amp;quot;,&lt;br /&gt;
        sura: &amp;quot;/images/3/37/Couperespectablerouge.png&amp;quot;,&lt;br /&gt;
        shaman: &amp;quot;/images/6/6a/Coupeeleganteclairfemme.png&amp;quot;,&lt;br /&gt;
        lycan: &amp;quot;/images/4/4e/Protectionfrontalerouge.png&amp;quot;,&lt;br /&gt;
      },&lt;br /&gt;
      categories: [&amp;quot;attacker&amp;quot;, &amp;quot;victim&amp;quot;],&lt;br /&gt;
      translateMonsters: defaultLang !== currentLanguage,&lt;br /&gt;
      attacker: {&lt;br /&gt;
        character: {&lt;br /&gt;
          count: 0,&lt;br /&gt;
          container: document.getElementById(&amp;quot;attacker-selection-characters&amp;quot;),&lt;br /&gt;
          elements: {},&lt;br /&gt;
        },&lt;br /&gt;
        monster: {&lt;br /&gt;
          count: 0,&lt;br /&gt;
          container: document.getElementById(&amp;quot;attacker-selection-monsters&amp;quot;),&lt;br /&gt;
          elements: {},&lt;br /&gt;
        },&lt;br /&gt;
        button: document.getElementById(&amp;quot;attacker-trigger&amp;quot;),&lt;br /&gt;
        defaultButtonContent: document.getElementById(&lt;br /&gt;
          &amp;quot;attacker-default-button-content&amp;quot;&lt;br /&gt;
        ),&lt;br /&gt;
        buttonContent: document.getElementById(&amp;quot;attacker-button-content&amp;quot;),&lt;br /&gt;
        container: document.getElementById(&amp;quot;attacker-selection&amp;quot;),&lt;br /&gt;
        selected: null,&lt;br /&gt;
      },&lt;br /&gt;
      victim: {&lt;br /&gt;
        character: {&lt;br /&gt;
          count: 0,&lt;br /&gt;
          container: document.getElementById(&amp;quot;victim-selection-characters&amp;quot;),&lt;br /&gt;
          elements: {},&lt;br /&gt;
        },&lt;br /&gt;
        monster: {&lt;br /&gt;
          count: 0,&lt;br /&gt;
          container: document.getElementById(&amp;quot;victim-selection-monsters&amp;quot;),&lt;br /&gt;
          elements: {},&lt;br /&gt;
        },&lt;br /&gt;
        stone: {&lt;br /&gt;
          count: 0,&lt;br /&gt;
          container: document.getElementById(&amp;quot;victim-selection-stones&amp;quot;),&lt;br /&gt;
          elements: {},&lt;br /&gt;
        },&lt;br /&gt;
        button: document.getElementById(&amp;quot;victim-trigger&amp;quot;),&lt;br /&gt;
        defaultButtonContent: document.getElementById(&lt;br /&gt;
          &amp;quot;victim-default-button-content&amp;quot;&lt;br /&gt;
        ),&lt;br /&gt;
        buttonContent: document.getElementById(&amp;quot;victim-button-content&amp;quot;),&lt;br /&gt;
        selected: null,&lt;br /&gt;
      },&lt;br /&gt;
      attackType: {&lt;br /&gt;
        container: document.getElementById(&amp;quot;attack-type-selection&amp;quot;),&lt;br /&gt;
        elements: [],&lt;br /&gt;
        defaultInput: document.getElementById(&amp;quot;physical-attack&amp;quot;),&lt;br /&gt;
        selectedText: &amp;quot;&amp;quot;,&lt;br /&gt;
      },&lt;br /&gt;
    },&lt;br /&gt;
    damageWeightedByType: {},&lt;br /&gt;
    scatterDataByType: {},&lt;br /&gt;
    damageByBonus: [],&lt;br /&gt;
    tableResultFight: document.getElementById(&amp;quot;result-table-fight&amp;quot;),&lt;br /&gt;
    tableResultHistory: document.getElementById(&amp;quot;result-table-history&amp;quot;),&lt;br /&gt;
    deleteFightTemplate: document.getElementById(&amp;quot;delete-fight-template&amp;quot;)&lt;br /&gt;
      .children[0],&lt;br /&gt;
    errorInformation: {},&lt;br /&gt;
    fightResultTitle: document.getElementById(&amp;quot;fight-result-title&amp;quot;),&lt;br /&gt;
    fightResultContainer: document.getElementById(&amp;quot;fight-result-container&amp;quot;),&lt;br /&gt;
    downLoadRawData: document.getElementById(&amp;quot;download-raw-data&amp;quot;),&lt;br /&gt;
    downLoadRawDataVariation: document.getElementById(&lt;br /&gt;
      &amp;quot;download-raw-data-variation&amp;quot;&lt;br /&gt;
    ),&lt;br /&gt;
    bonusVariationResultContainer: document.getElementById(&lt;br /&gt;
      &amp;quot;bonus-variation-result-container&amp;quot;&lt;br /&gt;
    ),&lt;br /&gt;
    reduceChartPointsContainer: document.getElementById(&lt;br /&gt;
      &amp;quot;reduce-chart-points-container&amp;quot;&lt;br /&gt;
    ),&lt;br /&gt;
    reduceChartPoints: document.getElementById(&amp;quot;reduce-chart-points&amp;quot;),&lt;br /&gt;
    plotDamage: document.getElementById(&amp;quot;plot-damage&amp;quot;),&lt;br /&gt;
    plotBonusVariation: document.getElementById(&amp;quot;plot-bonus-variation&amp;quot;),&lt;br /&gt;
    chartDescriptionContainer: document.getElementById(&lt;br /&gt;
      &amp;quot;chart-description-container&amp;quot;&lt;br /&gt;
    ),&lt;br /&gt;
    damageInfoContainer: document.getElementById(&amp;quot;damage-info-container&amp;quot;),&lt;br /&gt;
    uniqueDamageCounters: document.querySelectorAll(&amp;quot;.unique-damage-counter&amp;quot;),&lt;br /&gt;
    possibleDamageCounter: document.getElementById(&amp;quot;possible-damage-counter&amp;quot;),&lt;br /&gt;
    damageTime: document.getElementById(&amp;quot;damage-time&amp;quot;),&lt;br /&gt;
    displayTime: document.getElementById(&amp;quot;display-time&amp;quot;),&lt;br /&gt;
    simulationCounter: document.getElementById(&amp;quot;simulation-counter&amp;quot;),&lt;br /&gt;
    simulationTime: document.getElementById(&amp;quot;simulation-time&amp;quot;),&lt;br /&gt;
    numberFormats: {&lt;br /&gt;
      default: new Intl.NumberFormat(currentLanguage, {&lt;br /&gt;
        minimumFractionDigits: 0,&lt;br /&gt;
        maximumFractionDigits: 1,&lt;br /&gt;
      }),&lt;br /&gt;
      percent: new Intl.NumberFormat(currentLanguage, {&lt;br /&gt;
        style: &amp;quot;percent&amp;quot;,&lt;br /&gt;
        maximumFractionDigits: 3,&lt;br /&gt;
      }),&lt;br /&gt;
      second: new Intl.NumberFormat(currentLanguage, {&lt;br /&gt;
        style: &amp;quot;unit&amp;quot;,&lt;br /&gt;
        unit: &amp;quot;second&amp;quot;,&lt;br /&gt;
        unitDisplay: &amp;quot;long&amp;quot;,&lt;br /&gt;
        maximumFractionDigits: 3,&lt;br /&gt;
      }),&lt;br /&gt;
    },&lt;br /&gt;
    mapping: createMapping(),&lt;br /&gt;
    constants: constants,&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  addBattleData(battle);&lt;br /&gt;
  initResultTableHistory(battle);&lt;br /&gt;
  initDamageChart(battle, currentLanguage, defaultText);&lt;br /&gt;
  initBonusVariationChart(battle, currentLanguage, defaultText);&lt;br /&gt;
  reduceChartPointsListener(battle);&lt;br /&gt;
  downloadRawDataListener(battle);&lt;br /&gt;
&lt;br /&gt;
  return [characters, battle];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function parseText(input) {&lt;br /&gt;
  const regex = /\[\[(.*?)\]\]|([^\[]+)/g;&lt;br /&gt;
  const result = [];&lt;br /&gt;
&lt;br /&gt;
  input.replace(regex, (_, matchA, matchText) =&amp;gt; {&lt;br /&gt;
    if (matchA !== undefined) {&lt;br /&gt;
      result.push({&lt;br /&gt;
        text: matchA,&lt;br /&gt;
        category: matchA === &amp;quot;&amp;quot; ? &amp;quot;NOTRANSLATE&amp;quot; : &amp;quot;A&amp;quot;,&lt;br /&gt;
      });&lt;br /&gt;
    } else if (matchText) {&lt;br /&gt;
      result.push({ text: matchText, category: &amp;quot;#text&amp;quot; });&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  return result;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function translateText(general) {&lt;br /&gt;
  const nodesToTranslate = [&amp;quot;A&amp;quot;, &amp;quot;I&amp;quot;, &amp;quot;B&amp;quot;];&lt;br /&gt;
&lt;br /&gt;
  for (const element of document.querySelectorAll(&amp;quot;[data-t]&amp;quot;)) {&lt;br /&gt;
    const translateText = general[element.dataset.t];&lt;br /&gt;
&lt;br /&gt;
    if (!translateText) continue;&lt;br /&gt;
&lt;br /&gt;
    const childNodes = element.childNodes;&lt;br /&gt;
    const numChildren = childNodes.length;&lt;br /&gt;
&lt;br /&gt;
    if (numChildren === 1) {&lt;br /&gt;
      childNodes[0].textContent = translateText;&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    const parsedText = parseText(translateText);&lt;br /&gt;
    const numParsed = parsedText.length;&lt;br /&gt;
&lt;br /&gt;
    let childIndex = 0;&lt;br /&gt;
    let textIndex = 0;&lt;br /&gt;
&lt;br /&gt;
    while (childIndex &amp;lt; numChildren) {&lt;br /&gt;
      const child = childNodes[childIndex];&lt;br /&gt;
&lt;br /&gt;
      if (textIndex === numParsed) {&lt;br /&gt;
        console.warn(&amp;quot;Bad translation for element&amp;quot;, element);&lt;br /&gt;
        break;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      const parsed = parsedText[textIndex];&lt;br /&gt;
&lt;br /&gt;
      let childName = child.nodeName;&lt;br /&gt;
      const isNodeToTranslate = nodesToTranslate.includes(childName);&lt;br /&gt;
&lt;br /&gt;
      if (&lt;br /&gt;
        (childName === &amp;quot;A&amp;quot; &amp;amp;&amp;amp; child.firstChild?.nodeName === &amp;quot;IMG&amp;quot;) ||&lt;br /&gt;
        !(isNodeToTranslate || childName === &amp;quot;#text&amp;quot;) ||&lt;br /&gt;
        child.dataset?.notranslate&lt;br /&gt;
      ) {&lt;br /&gt;
        childName = &amp;quot;NOTRANSLATE&amp;quot;;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (&lt;br /&gt;
        childName === parsed.category ||&lt;br /&gt;
        (parsed.category === &amp;quot;A&amp;quot; &amp;amp;&amp;amp; isNodeToTranslate)&lt;br /&gt;
      ) {&lt;br /&gt;
        if (childName !== &amp;quot;NOTRANSLATE&amp;quot;) {&lt;br /&gt;
          child.textContent = parsed.text;&lt;br /&gt;
        }&lt;br /&gt;
        childIndex++;&lt;br /&gt;
        textIndex++;&lt;br /&gt;
      } else if (childName === &amp;quot;NOTRANSLATE&amp;quot;) {&lt;br /&gt;
        childIndex++;&lt;br /&gt;
      } else if (isNodeToTranslate) {&lt;br /&gt;
        element.insertBefore(document.createTextNode(parsed.text), child);&lt;br /&gt;
        textIndex++;&lt;br /&gt;
      } else {&lt;br /&gt;
        child.textContent = &amp;quot;&amp;quot;;&lt;br /&gt;
        childIndex++;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (textIndex &amp;lt; parsedText.length) {&lt;br /&gt;
      const textNode = document.createTextNode(parsedText[textIndex].text);&lt;br /&gt;
      element.appendChild(textNode);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function translateWeapons(weapons) {&lt;br /&gt;
  const characterCreation = document.getElementById(&amp;quot;character-creation&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  for (const weaponInput of characterCreation.elements[&amp;quot;weapon&amp;quot;]) {&lt;br /&gt;
    const weaponTranslation = weapons[weaponInput.value];&lt;br /&gt;
&lt;br /&gt;
    if (weaponTranslation) {&lt;br /&gt;
      weaponInput.parentElement.lastElementChild.textContent =&lt;br /&gt;
        weaponTranslation;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleSpecialIndexes(generalTranslations, specialIndexes) {&lt;br /&gt;
  const specialTranslations = {};&lt;br /&gt;
&lt;br /&gt;
  translation.special = specialTranslations;&lt;br /&gt;
&lt;br /&gt;
  for (const [generalIndex, specialKey] of Object.entries(specialIndexes)) {&lt;br /&gt;
    const translatedValue = generalTranslations[generalIndex];&lt;br /&gt;
&lt;br /&gt;
    if (translatedValue) {&lt;br /&gt;
      specialTranslations[specialKey] = translatedValue;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  translation.mapping = {&lt;br /&gt;
    &amp;quot;Demi-humain&amp;quot;: specialTranslations.halfHuman,&lt;br /&gt;
    Mal: specialTranslations.devil,&lt;br /&gt;
    Désert: specialTranslations.desert,&lt;br /&gt;
    Animal: specialTranslations.animal,&lt;br /&gt;
    Orc: specialTranslations.orc,&lt;br /&gt;
    Mystique: specialTranslations.mystic,&lt;br /&gt;
    &amp;quot;Mort-vivant&amp;quot;: specialTranslations.undead,&lt;br /&gt;
    Insecte: specialTranslations.insect,&lt;br /&gt;
    Zodiaque: specialTranslations.zodiac,&lt;br /&gt;
    &amp;quot;Aucun type&amp;quot;: specialTranslations.noType,&lt;br /&gt;
    Mêlée: specialTranslations.melee,&lt;br /&gt;
    Flèche: specialTranslations.arrow,&lt;br /&gt;
    Magique: specialTranslations.magic,&lt;br /&gt;
    DC: specialTranslations.skill,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function translateTitle() {&lt;br /&gt;
  const translatedTitle = translation.special.pageTitle;&lt;br /&gt;
&lt;br /&gt;
  if (translatedTitle) {&lt;br /&gt;
    document.querySelector(&amp;quot;h1&amp;quot;).textContent = translatedTitle;&lt;br /&gt;
    document.querySelector(&amp;quot;ul.subpage&amp;quot;).lastElementChild.textContent =&lt;br /&gt;
      translatedTitle;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function translateSummary(attempts = 5) {&lt;br /&gt;
  const tocContainer = document.getElementById(&amp;quot;toc&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (!tocContainer) {&lt;br /&gt;
    if (attempts &amp;gt; 0) {&lt;br /&gt;
      console.log(`Translating summary... Attempts left: ${attempts}`);&lt;br /&gt;
      setTimeout(() =&amp;gt; translateSummary(attempts - 1), 1000);&lt;br /&gt;
    }&lt;br /&gt;
    return;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  const { toc, hide } = translation.special;&lt;br /&gt;
&lt;br /&gt;
  const heading = tocContainer.querySelector(&amp;quot;h2&amp;quot;);&lt;br /&gt;
  const toggleLink = tocContainer.querySelector(&amp;quot;a.togglelink&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (heading) heading.textContent = toc;&lt;br /&gt;
  if (toggleLink) toggleLink.textContent = hide;&lt;br /&gt;
&lt;br /&gt;
  for (const link of tocContainer.querySelectorAll(&amp;quot;ul a&amp;quot;)) {&lt;br /&gt;
    const hash = link.hash.substring(1);&lt;br /&gt;
    const title = document.getElementById(hash);&lt;br /&gt;
&lt;br /&gt;
    if (title) {&lt;br /&gt;
      const toctext = link.querySelector(&amp;quot;span.toctext&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
      if (toctext?.firstElementChild) {&lt;br /&gt;
        toctext.firstElementChild.textContent = title.textContent;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function translateDefaultText(defaultText) {&lt;br /&gt;
  const specialTranslations = translation.special;&lt;br /&gt;
&lt;br /&gt;
  for (const key of Object.keys(defaultText)) {&lt;br /&gt;
    if (specialTranslations.hasOwnProperty(key)) {&lt;br /&gt;
      defaultText[key] = specialTranslations[key];&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function translatePage(defaultText, currentLanguage) {&lt;br /&gt;
  const mwContent = document.querySelector(&amp;quot;.mw-content-ltr&amp;quot;);&lt;br /&gt;
  const { general, weapons } = translation;&lt;br /&gt;
  const specialIndexes = {&lt;br /&gt;
    471: &amp;quot;placeholder&amp;quot;,&lt;br /&gt;
    473: &amp;quot;boss&amp;quot;,&lt;br /&gt;
    474: &amp;quot;pageTitle&amp;quot;,&lt;br /&gt;
    475: &amp;quot;toc&amp;quot;,&lt;br /&gt;
    476: &amp;quot;hide&amp;quot;,&lt;br /&gt;
    502: &amp;quot;unsavedWarning&amp;quot;,&lt;br /&gt;
    503: &amp;quot;deleteWarning&amp;quot;,&lt;br /&gt;
    504: &amp;quot;pseudo&amp;quot;,&lt;br /&gt;
    481: &amp;quot;damage&amp;quot;,&lt;br /&gt;
    505: &amp;quot;percentage&amp;quot;,&lt;br /&gt;
    506: &amp;quot;miss&amp;quot;,&lt;br /&gt;
    507: &amp;quot;normalHit&amp;quot;,&lt;br /&gt;
    508: &amp;quot;criticalHit&amp;quot;,&lt;br /&gt;
    509: &amp;quot;piercingHit&amp;quot;,&lt;br /&gt;
    510: &amp;quot;criticalPiercingHit&amp;quot;,&lt;br /&gt;
    511: &amp;quot;damageRepartition&amp;quot;,&lt;br /&gt;
    512: &amp;quot;averageDamage&amp;quot;,&lt;br /&gt;
    513: &amp;quot;damageAugmentation&amp;quot;,&lt;br /&gt;
    514: &amp;quot;bonusVariationTitle&amp;quot;,&lt;br /&gt;
    489: &amp;quot;halfHuman&amp;quot;,&lt;br /&gt;
    490: &amp;quot;devil&amp;quot;,&lt;br /&gt;
    491: &amp;quot;desert&amp;quot;,&lt;br /&gt;
    492: &amp;quot;animal&amp;quot;,&lt;br /&gt;
    493: &amp;quot;orc&amp;quot;,&lt;br /&gt;
    494: &amp;quot;mystic&amp;quot;,&lt;br /&gt;
    495: &amp;quot;undead&amp;quot;,&lt;br /&gt;
    496: &amp;quot;insect&amp;quot;,&lt;br /&gt;
    497: &amp;quot;zodiac&amp;quot;,&lt;br /&gt;
    515: &amp;quot;noType&amp;quot;,&lt;br /&gt;
    498: &amp;quot;melee&amp;quot;,&lt;br /&gt;
    499: &amp;quot;arrow&amp;quot;,&lt;br /&gt;
    500: &amp;quot;magic&amp;quot;,&lt;br /&gt;
    516: &amp;quot;skill&amp;quot;,&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  translateText(general);&lt;br /&gt;
  translateWeapons(weapons);&lt;br /&gt;
  handleSpecialIndexes(general, specialIndexes);&lt;br /&gt;
  translateTitle();&lt;br /&gt;
  translateSummary();&lt;br /&gt;
  translateDefaultText(defaultText);&lt;br /&gt;
&lt;br /&gt;
  if (mwContent) {&lt;br /&gt;
    mwContent.setAttribute(&amp;quot;lang&amp;quot;, currentLanguage);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getDefaultText() {&lt;br /&gt;
  return {&lt;br /&gt;
    unsavedWarning:&lt;br /&gt;
      &amp;quot;Voulez-vous continuer ? Les dernières modifications ne seront pas sauvegardées.&amp;quot;,&lt;br /&gt;
    deleteWarning:&lt;br /&gt;
      &amp;quot;Voulez-vous vraiment supprimer définitivement le personnage [[]] ?&amp;quot;,&lt;br /&gt;
    pseudo: &amp;quot;Pseudo&amp;quot;,&lt;br /&gt;
    damage: &amp;quot;Dégâts&amp;quot;,&lt;br /&gt;
    percentage: &amp;quot;Pourcentage&amp;quot;,&lt;br /&gt;
    miss: &amp;quot;Miss&amp;quot;,&lt;br /&gt;
    normalHit: &amp;quot;Coup classique&amp;quot;,&lt;br /&gt;
    criticalHit: &amp;quot;Coup critique&amp;quot;,&lt;br /&gt;
    piercingHit: &amp;quot;Coup perçant&amp;quot;,&lt;br /&gt;
    criticalPiercingHit: &amp;quot;Coup critique perçant&amp;quot;,&lt;br /&gt;
    damageRepartition: &amp;quot;Distribution des dégâts&amp;quot;,&lt;br /&gt;
    averageDamage: &amp;quot;Dégâts moyens&amp;quot;,&lt;br /&gt;
    damageAugmentation: &amp;quot;Augmentation des dégâts&amp;quot;,&lt;br /&gt;
    bonusVariationTitle:&lt;br /&gt;
      &amp;quot;Évolution des dégâts moyens[[]]par rapport à la valeur d'un bonus&amp;quot;,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setLanguage(radios, lang, url, reload = false) {&lt;br /&gt;
  url.searchParams.set(&amp;quot;lang&amp;quot;, lang);&lt;br /&gt;
  updateLastLang(lang);&lt;br /&gt;
&lt;br /&gt;
  if (reload) {&lt;br /&gt;
    window.location.href = url.toString();&lt;br /&gt;
  } else {&lt;br /&gt;
    radios.value = lang;&lt;br /&gt;
    history.replaceState(null, &amp;quot;&amp;quot;, url);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getCurrentLanguage(defaultLang) {&lt;br /&gt;
  const url = new URL(window.location.href);&lt;br /&gt;
  const URLlang = url.searchParams.get(&amp;quot;lang&amp;quot;);&lt;br /&gt;
  const lastLang = getLastLang();&lt;br /&gt;
  const browserLang = navigator.language.split(&amp;quot;-&amp;quot;)[0];&lt;br /&gt;
  const languageSelection = document.getElementById(&amp;quot;language-selection&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (!languageSelection) {&lt;br /&gt;
    return defaultLang;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  const radios = languageSelection.elements[&amp;quot;country&amp;quot;];&lt;br /&gt;
&lt;br /&gt;
  if (!radios) {&lt;br /&gt;
    return defaultLang;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  languageSelection.addEventListener(&amp;quot;change&amp;quot;, changeLanguage);&lt;br /&gt;
&lt;br /&gt;
  function changeLanguage(event) {&lt;br /&gt;
    const newLang = event.target.value;&lt;br /&gt;
    const newUrl = new URL(window.location.href);&lt;br /&gt;
    setLanguage(radios, newLang, newUrl, true);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  const allowedLanguages = Array.from(radios).map((input) =&amp;gt; input.value);&lt;br /&gt;
&lt;br /&gt;
  for (const lang of [URLlang, lastLang, browserLang]) {&lt;br /&gt;
    if (allowedLanguages.includes(lang)) {&lt;br /&gt;
      setLanguage(radios, lang, url);&lt;br /&gt;
      return lang;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return defaultLang;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadStyle(src) {&lt;br /&gt;
  var link = document.createElement(&amp;quot;link&amp;quot;);&lt;br /&gt;
  link.href = src;&lt;br /&gt;
  link.rel = &amp;quot;stylesheet&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  document.head.appendChild(link);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
async function addScript(src) {&lt;br /&gt;
  return new Promise((resolve, reject) =&amp;gt; {&lt;br /&gt;
    const script = document.createElement(&amp;quot;script&amp;quot;);&lt;br /&gt;
    script.src = src;&lt;br /&gt;
    script.async = true;&lt;br /&gt;
&lt;br /&gt;
    script.onload = () =&amp;gt; resolve();&lt;br /&gt;
    script.onerror = () =&amp;gt; reject(new Error(`Failed to load script: ${src}`));&lt;br /&gt;
&lt;br /&gt;
    document.head.appendChild(script);&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
(async function () {&lt;br /&gt;
  const basePath = &amp;quot;/index.php?title=Utilisateur:Ankhseram/&amp;quot;;&lt;br /&gt;
  const dataScript = `${basePath}WeaponsAndMonsters.js&amp;amp;action=raw&amp;amp;ctype=text/javascript`;&lt;br /&gt;
  const simulatorStyle = `${basePath}SimulatorStyle.css&amp;amp;action=raw&amp;amp;ctype=text/css`;&lt;br /&gt;
  const chartLibrary = &amp;quot;https://cdn.jsdelivr.net/npm/chart.js&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  const defaultLang = &amp;quot;fr&amp;quot;;&lt;br /&gt;
  const defaultText = getDefaultText();&lt;br /&gt;
  const currentLanguage = getCurrentLanguage(defaultLang);&lt;br /&gt;
&lt;br /&gt;
  loadStyle(simulatorStyle);&lt;br /&gt;
&lt;br /&gt;
  let translationScript;&lt;br /&gt;
&lt;br /&gt;
  if (currentLanguage !== defaultLang) {&lt;br /&gt;
    translationScript = `${basePath}Calculator/${currentLanguage}.js&amp;amp;action=raw&amp;amp;ctype=text/javascript`;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  const scriptsToLoad = [addScript(chartLibrary), addScript(dataScript)];&lt;br /&gt;
&lt;br /&gt;
  if (translationScript) {&lt;br /&gt;
    scriptsToLoad.push(addScript(translationScript));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  await Promise.all(scriptsToLoad);&lt;br /&gt;
&lt;br /&gt;
  if (translationScript) {&lt;br /&gt;
    translatePage(defaultText, currentLanguage);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  const [characters, battle] = createDamageCalculatorInformation(&lt;br /&gt;
    defaultLang,&lt;br /&gt;
    currentLanguage,&lt;br /&gt;
    defaultText&lt;br /&gt;
  );&lt;br /&gt;
  characterManagement(characters, battle);&lt;br /&gt;
  monsterManagement(characters, battle);&lt;br /&gt;
  updateBattleChoice(characters, battle.battleChoice);&lt;br /&gt;
  createBattle(characters, battle);&lt;br /&gt;
})();&lt;/div&gt;</summary>
		<author><name>Dexter</name></author>
		
	</entry>
	<entry>
		<id>https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Script/Calculator.js&amp;diff=107981</id>
		<title>MediaWiki:Script/Calculator.js</title>
		<link rel="alternate" type="text/html" href="https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Script/Calculator.js&amp;diff=107981"/>
		<updated>2025-07-22T14:51:31Z</updated>

		<summary type="html">&lt;p&gt;Dexter : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;function removeAccent(str) {&lt;br /&gt;
  return str.normalize(&amp;quot;NFD&amp;quot;).replace(/[\u0300-\u036f]/g, &amp;quot;&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function pseudoFormat(str) {&lt;br /&gt;
  return removeAccent(str).replace(/[^A-Za-z0-9 \(\)\+_-]+/g, &amp;quot;&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isValueInArray(value, array) {&lt;br /&gt;
  return array.indexOf(value) !== -1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function splitFirst(value, delimiter) {&lt;br /&gt;
  var parts = value.split(delimiter);&lt;br /&gt;
  var first = parts[0];&lt;br /&gt;
  var rest = parts.slice(1).join(delimiter);&lt;br /&gt;
  return [first, rest];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function copyObject(object) {&lt;br /&gt;
  var copy = {};&lt;br /&gt;
  for (var key in object) {&lt;br /&gt;
    copy[key] = object[key];&lt;br /&gt;
  }&lt;br /&gt;
  return copy;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function compareNumbers(a, b) {&lt;br /&gt;
  return b - a;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isChecked(attribute) {&lt;br /&gt;
  return attribute === &amp;quot;on&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function floorMultiplication(firstFactor, secondFactor) {&lt;br /&gt;
  return Math.floor((firstFactor * secondFactor).toFixed(8));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function truncateNumber(number, precision) {&lt;br /&gt;
  return Math.floor(number * 10 ** precision) / 10 ** precision;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function newChangeEvent() {&lt;br /&gt;
  return new Event(&amp;quot;change&amp;quot;, { bubbles: true });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function openTargetTab(target) {&lt;br /&gt;
  var tabberContainer = target.closest(&amp;quot;.tabber-container&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (!tabberContainer) {&lt;br /&gt;
    return;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var [buttonsContainer, tabsContainer] = tabberContainer.children;&lt;br /&gt;
  var buttons = buttonsContainer.children;&lt;br /&gt;
  var tabs = tabsContainer.children;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; tabs.length; index++) {&lt;br /&gt;
    var tab = tabs[index];&lt;br /&gt;
    if (tab.contains(target) &amp;amp;&amp;amp; !tab.checkVisibility()) {&lt;br /&gt;
      buttons[index].click();&lt;br /&gt;
      break;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function openTargetCollapsible(target) {&lt;br /&gt;
  var collapsible = target.closest(&amp;quot;.improved-collapsible&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (!collapsible) {&lt;br /&gt;
    return;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var span = collapsible.firstElementChild;&lt;br /&gt;
&lt;br /&gt;
  if (!span.classList.contains(&amp;quot;mw-collapsible-toggle-expanded&amp;quot;)) {&lt;br /&gt;
    span.click();&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function editTableResultRow(row, valuesToDisplay, numberFormat) {&lt;br /&gt;
  row.innerHTML = &amp;quot;&amp;quot;;&lt;br /&gt;
  for (var index = 0; index &amp;lt; valuesToDisplay.length; index++) {&lt;br /&gt;
    var cell = row.insertCell();&lt;br /&gt;
    var textContent;&lt;br /&gt;
&lt;br /&gt;
    if (index &amp;gt;= 3) {&lt;br /&gt;
      textContent = numberFormat.format(valuesToDisplay[index]);&lt;br /&gt;
    } else {&lt;br /&gt;
      textContent = valuesToDisplay[index];&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    cell.textContent = textContent;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return row;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addRowToTableResultHistory(&lt;br /&gt;
  tableResultHistory,&lt;br /&gt;
  valuesToDisplay,&lt;br /&gt;
  deleteFightTemplate,&lt;br /&gt;
  numberFormat&lt;br /&gt;
) {&lt;br /&gt;
  var row = tableResultHistory.insertRow();&lt;br /&gt;
  editTableResultRow(row, valuesToDisplay, numberFormat);&lt;br /&gt;
  var cell = row.insertCell();&lt;br /&gt;
  cell.appendChild(deleteFightTemplate.cloneNode(true));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function processSavedDamage(savedDamage, damageWeightedByType, battleValues) {&lt;br /&gt;
  const { damageTypeWeights, attackTypeMapping } = battleValues;&lt;br /&gt;
&lt;br /&gt;
  for (const key in savedDamage) {&lt;br /&gt;
    const [weight, damageByType] = savedDamage[key];&lt;br /&gt;
&lt;br /&gt;
    for (let index = 0; index &amp;lt; 4; index++) {&lt;br /&gt;
      const damageWeighted = damageWeightedByType[attackTypeMapping[index]];&lt;br /&gt;
      const damageByTypeIndex = damageByType[index];&lt;br /&gt;
&lt;br /&gt;
      if (damageByTypeIndex.length === 0) continue;&lt;br /&gt;
&lt;br /&gt;
      const currentWeight =&lt;br /&gt;
        (weight * damageTypeWeights[index]) / damageByTypeIndex.length;&lt;br /&gt;
&lt;br /&gt;
      for (const damage of damageByTypeIndex) {&lt;br /&gt;
        damageWeighted[damage] = (damageWeighted[damage] || 0) + currentWeight;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcMeanDamage(damageWeightedByType, totalCardinal) {&lt;br /&gt;
  var sumDamage = 0;&lt;br /&gt;
&lt;br /&gt;
  for (var damageTypeName in damageWeightedByType) {&lt;br /&gt;
    if (damageTypeName === &amp;quot;miss&amp;quot;) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var damageWeighted = damageWeightedByType[damageTypeName];&lt;br /&gt;
&lt;br /&gt;
    for (var damage in damageWeighted) {&lt;br /&gt;
      sumDamage += damage * damageWeighted[damage];&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return sumDamage / totalCardinal;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function prepareDamageData(damageWeightedByType, attackValues) {&lt;br /&gt;
  const totalCardinal = attackValues.totalCardinal;&lt;br /&gt;
  const scatterDataByType = {};&lt;br /&gt;
  const criticalAttackRange = attackValues.criticalAttackRange;&lt;br /&gt;
&lt;br /&gt;
  let minDamage = Infinity;&lt;br /&gt;
  let maxDamage = 0;&lt;br /&gt;
  let sumDamage = 0;&lt;br /&gt;
&lt;br /&gt;
  let possibleDamageCount = 0;&lt;br /&gt;
  let possibleDamageCountTemp = 0;&lt;br /&gt;
  let uniqueDamageCount = 0;&lt;br /&gt;
&lt;br /&gt;
  for (const damageTypeName in damageWeightedByType) {&lt;br /&gt;
    if (damageTypeName === &amp;quot;miss&amp;quot;) {&lt;br /&gt;
      scatterDataByType.miss = damageWeightedByType.miss;&lt;br /&gt;
      possibleDamageCount++;&lt;br /&gt;
      uniqueDamageCount++;&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
    const damageWeighted = damageWeightedByType[damageTypeName];&lt;br /&gt;
    const scatterData = [];&lt;br /&gt;
&lt;br /&gt;
    scatterDataByType[damageTypeName] = scatterData;&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      (damageTypeName === &amp;quot;criticalHit&amp;quot; ||&lt;br /&gt;
        damageTypeName === &amp;quot;criticalPiercingHit&amp;quot;) &amp;amp;&amp;amp;&lt;br /&gt;
      criticalAttackRange&lt;br /&gt;
    ) {&lt;br /&gt;
      possibleDamageCountTemp =&lt;br /&gt;
        attackValues.possibleDamageCount * criticalAttackRange.length;&lt;br /&gt;
    } else {&lt;br /&gt;
      possibleDamageCountTemp = attackValues.possibleDamageCount;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    for (let damage in damageWeighted) {&lt;br /&gt;
      damage = +damage;&lt;br /&gt;
&lt;br /&gt;
      if (damage &amp;lt; minDamage) {&lt;br /&gt;
        minDamage = damage;&lt;br /&gt;
      }&lt;br /&gt;
      if (damage &amp;gt; maxDamage) {&lt;br /&gt;
        maxDamage = damage;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      const weight = damageWeighted[damage];&lt;br /&gt;
      const probability = weight / totalCardinal;&lt;br /&gt;
&lt;br /&gt;
      sumDamage += damage * weight;&lt;br /&gt;
      damageWeighted[damage] = probability;&lt;br /&gt;
      scatterData.push({ x: damage, y: probability });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    const scatterDataLength = scatterData.length;&lt;br /&gt;
&lt;br /&gt;
    if (!scatterDataLength) {&lt;br /&gt;
      delete scatterDataByType[damageTypeName];&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    possibleDamageCount += possibleDamageCountTemp;&lt;br /&gt;
    uniqueDamageCount += scatterDataLength;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (minDamage === Infinity) {&lt;br /&gt;
    minDamage = 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  attackValues.possibleDamageCount = possibleDamageCount;&lt;br /&gt;
&lt;br /&gt;
  return [&lt;br /&gt;
    sumDamage / totalCardinal,&lt;br /&gt;
    minDamage,&lt;br /&gt;
    maxDamage,&lt;br /&gt;
    scatterDataByType,&lt;br /&gt;
    uniqueDamageCount,&lt;br /&gt;
  ];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function aggregateDamage(scatterData, maxPoints) {&lt;br /&gt;
  var dataLength = scatterData.length;&lt;br /&gt;
  var remainingData = dataLength;&lt;br /&gt;
  var aggregateScatterData = [];&lt;br /&gt;
&lt;br /&gt;
  for (var groupIndex = 0; groupIndex &amp;lt; maxPoints; groupIndex++) {&lt;br /&gt;
    var groupLength = Math.floor(remainingData / (maxPoints - groupIndex));&lt;br /&gt;
    var startIndex = dataLength - remainingData;&lt;br /&gt;
    var aggregateDamage = 0;&lt;br /&gt;
    var aggregateProbability = 0;&lt;br /&gt;
&lt;br /&gt;
    for (var index = startIndex; index &amp;lt; startIndex + groupLength; index++) {&lt;br /&gt;
      var { x: damage, y: probability } = scatterData[index];&lt;br /&gt;
      aggregateDamage += damage * probability;&lt;br /&gt;
      aggregateProbability += probability;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    aggregateScatterData.push({&lt;br /&gt;
      x: aggregateDamage / aggregateProbability,&lt;br /&gt;
      y: aggregateProbability,&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    remainingData -= groupLength;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return aggregateScatterData;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addToDamageChart(battle, scatterDataByType) {&lt;br /&gt;
  const { chart, datasetsStyle, maxPoints, reduceChartPointsContainer } =&lt;br /&gt;
    battle.damageChart;&lt;br /&gt;
  const isReducePointsChecked = battle.reduceChartPoints.checked;&lt;br /&gt;
  const datasets = chart.data.datasets;&lt;br /&gt;
&lt;br /&gt;
  let isFirstDataset = true;&lt;br /&gt;
&lt;br /&gt;
  datasets.length = 0;&lt;br /&gt;
&lt;br /&gt;
  for (let index = 0; index &amp;lt; datasetsStyle.length; index++) {&lt;br /&gt;
    const dataset = copyObject(datasetsStyle[index]);&lt;br /&gt;
&lt;br /&gt;
    if (!scatterDataByType.hasOwnProperty(dataset.name)) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    const scatterData = scatterDataByType[dataset.name];&lt;br /&gt;
    const canBeReduced = scatterData.length &amp;gt; 2 * maxPoints;&lt;br /&gt;
&lt;br /&gt;
    dataset.hidden = !isFirstDataset;&lt;br /&gt;
    dataset.canBeReduced = canBeReduced;&lt;br /&gt;
&lt;br /&gt;
    if (canBeReduced &amp;amp;&amp;amp; isReducePointsChecked) {&lt;br /&gt;
      dataset.data = aggregateDamage(scatterData, maxPoints);&lt;br /&gt;
    } else {&lt;br /&gt;
      dataset.data = scatterData;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isFirstDataset) {&lt;br /&gt;
      isFirstDataset = false;&lt;br /&gt;
&lt;br /&gt;
      if (canBeReduced) {&lt;br /&gt;
        showElement(reduceChartPointsContainer);&lt;br /&gt;
&lt;br /&gt;
        if (!isReducePointsChecked) {&lt;br /&gt;
          handleChartAnimations(chart, false);&lt;br /&gt;
        }&lt;br /&gt;
      } else {&lt;br /&gt;
        hideElement(reduceChartPointsContainer);&lt;br /&gt;
        handleChartAnimations(chart, true);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    datasets.push(dataset);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  chart.data.missPercentage = scatterDataByType.miss;&lt;br /&gt;
  chart.update();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addToBonusVariationChart(&lt;br /&gt;
  damageByBonus,&lt;br /&gt;
  augmentationByBonus,&lt;br /&gt;
  xLabel,&lt;br /&gt;
  chart&lt;br /&gt;
) {&lt;br /&gt;
  chart.data.datasets[0].data = damageByBonus;&lt;br /&gt;
  chart.data.datasets[1].data = augmentationByBonus;&lt;br /&gt;
  chart.options.scales.x.title.text = xLabel;&lt;br /&gt;
  chart.update();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleChartAnimations(chart, addAnimations) {&lt;br /&gt;
  chart.options.animation = addAnimations;&lt;br /&gt;
  chart.options.animations.colors = addAnimations;&lt;br /&gt;
  chart.options.animations.x = addAnimations;&lt;br /&gt;
  chart.options.transitions.active.animation.duration = addAnimations * 1000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateDamageChartDescription(battle, uniqueDamageCount) {&lt;br /&gt;
  const {&lt;br /&gt;
    chartDescriptionContainer,&lt;br /&gt;
    uniqueDamageCounters,&lt;br /&gt;
    numberFormats: { default: defaultFormat },&lt;br /&gt;
  } = battle;&lt;br /&gt;
&lt;br /&gt;
  if (uniqueDamageCount &amp;gt; 1) {&lt;br /&gt;
    uniqueDamageCounters.forEach(function (element) {&lt;br /&gt;
      element.textContent = defaultFormat.format(uniqueDamageCount);&lt;br /&gt;
    });&lt;br /&gt;
    showElement(chartDescriptionContainer);&lt;br /&gt;
  } else {&lt;br /&gt;
    hideElement(chartDescriptionContainer);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getMonsterName(monsterVnum) {&lt;br /&gt;
  var monsterAttributes = monsterData[monsterVnum];&lt;br /&gt;
  return monsterAttributes[monsterAttributes.length - 1];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getTranslatedMonsterName(monsterVnum) {&lt;br /&gt;
  return translation.monsters[monsterVnum];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterClass(selectedRace, classChoice, selectValueIsChanged = false) {&lt;br /&gt;
  for (var radioNode of classChoice) {&lt;br /&gt;
    var radioGrandParent = radioNode.parentElement.parentElement;&lt;br /&gt;
&lt;br /&gt;
    if (radioNode.getAttribute(&amp;quot;data-race&amp;quot;) === selectedRace) {&lt;br /&gt;
      if (!selectValueIsChanged) {&lt;br /&gt;
        radioNode.checked = true;&lt;br /&gt;
        selectValueIsChanged = true;&lt;br /&gt;
      }&lt;br /&gt;
      showElement(radioGrandParent);&lt;br /&gt;
    } else {&lt;br /&gt;
      hideElement(radioGrandParent);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterWeapon(&lt;br /&gt;
  selectedRace,&lt;br /&gt;
  weaponElement,&lt;br /&gt;
  weaponCategory,&lt;br /&gt;
  allowedWeaponsPerRace,&lt;br /&gt;
  selectValueIsChanged = false&lt;br /&gt;
) {&lt;br /&gt;
  var allowedWeapons = allowedWeaponsPerRace[selectedRace];&lt;br /&gt;
&lt;br /&gt;
  if (!selectValueIsChanged) {&lt;br /&gt;
    var weaponType = createWeapon(weaponElement.value).type;&lt;br /&gt;
&lt;br /&gt;
    if (!isValueInArray(weaponType, allowedWeapons)) {&lt;br /&gt;
      weaponElement.value = 0;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var children = weaponCategory.children;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; children.length; index++) {&lt;br /&gt;
    var child = children[index];&lt;br /&gt;
&lt;br /&gt;
    if (isValueInArray(index, allowedWeapons)) {&lt;br /&gt;
      showElement(child);&lt;br /&gt;
    } else {&lt;br /&gt;
      hideElement(child);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function changePolymorphValues(characterCreation, monsterVnum, monsterImage) {&lt;br /&gt;
  var { polymorphMonster, polymorphMonsterImage } = characterCreation;&lt;br /&gt;
&lt;br /&gt;
  polymorphMonster.value = monsterVnum;&lt;br /&gt;
  polymorphMonsterImage.value = monsterImage;&lt;br /&gt;
&lt;br /&gt;
  polymorphMonster.dispatchEvent(newChangeEvent());&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function resetImageFromWiki(image) {&lt;br /&gt;
  image.removeAttribute(&amp;quot;srcset&amp;quot;);&lt;br /&gt;
  image.removeAttribute(&amp;quot;data-file-width&amp;quot;);&lt;br /&gt;
  image.removeAttribute(&amp;quot;data-file-height&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleImageFromWiki(image, newSrc) {&lt;br /&gt;
  image.src = newSrc;&lt;br /&gt;
  image.alt = newSrc.split(&amp;quot;/&amp;quot;).pop();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handlePolymorphDisplay(characters, monsterVnum, monsterSrc) {&lt;br /&gt;
  var { translateMonsters, polymorphDisplay } = characters;&lt;br /&gt;
  var oldImage = polymorphDisplay.firstChild;&lt;br /&gt;
  var oldLink = oldImage.nextElementSibling;&lt;br /&gt;
  var monsterName = getMonsterName(monsterVnum);&lt;br /&gt;
  var displayName = translateMonsters&lt;br /&gt;
    ? getTranslatedMonsterName(monsterVnum)&lt;br /&gt;
    : monsterName;&lt;br /&gt;
  var newLink = createWikiLink(monsterName, displayName);&lt;br /&gt;
&lt;br /&gt;
  resetImageFromWiki(oldImage);&lt;br /&gt;
  handleImageFromWiki(oldImage, monsterSrc);&lt;br /&gt;
&lt;br /&gt;
  polymorphDisplay.replaceChild(newLink, oldLink);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createWikiLink(pageName, displayName) {&lt;br /&gt;
  var wikiLink = document.createElement(&amp;quot;a&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  wikiLink.href = mw.util.getUrl(pageName);&lt;br /&gt;
  wikiLink.title = pageName;&lt;br /&gt;
  wikiLink.textContent = displayName || pageName;&lt;br /&gt;
&lt;br /&gt;
  return wikiLink;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSelectedWeapon(weaponCategory) {&lt;br /&gt;
  return weaponCategory.querySelector(&amp;quot;input[type='radio']:checked&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleWeaponDisplay(&lt;br /&gt;
  weaponCategory,&lt;br /&gt;
  weaponDisplay,&lt;br /&gt;
  weaponVnum,&lt;br /&gt;
  newWeapon&lt;br /&gt;
) {&lt;br /&gt;
  var newWeapon = newWeapon || getSelectedWeapon(weaponCategory);&lt;br /&gt;
&lt;br /&gt;
  var newImage = newWeapon.nextElementSibling;&lt;br /&gt;
  var newText = document.createElement(&amp;quot;span&amp;quot;);&lt;br /&gt;
  var oldImage = weaponDisplay.firstChild;&lt;br /&gt;
  var oldText = oldImage.nextElementSibling;&lt;br /&gt;
  var weaponTooltip = newImage.nextElementSibling;&lt;br /&gt;
  var originalWeaponName = weaponTooltip.dataset.o;&lt;br /&gt;
  var weaponName = weaponTooltip.textContent;&lt;br /&gt;
&lt;br /&gt;
  if (weaponVnum == 0) {&lt;br /&gt;
    newText.textContent = weaponName;&lt;br /&gt;
  } else {&lt;br /&gt;
    var weaponLink = createWikiLink(originalWeaponName, weaponName);&lt;br /&gt;
    newText.appendChild(weaponLink);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  weaponDisplay.replaceChild(newImage.cloneNode(), oldImage);&lt;br /&gt;
  weaponDisplay.replaceChild(newText, oldText);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterUpgrade(&lt;br /&gt;
  weaponUpgrade,&lt;br /&gt;
  weaponVnum,&lt;br /&gt;
  randomAttackValue,&lt;br /&gt;
  randomMagicAttackValue&lt;br /&gt;
) {&lt;br /&gt;
  var weapon = createWeapon(weaponVnum);&lt;br /&gt;
  var currentUpgrade = Number(weaponUpgrade.value);&lt;br /&gt;
  var weaponUpgradeChildren = weaponUpgrade.children;&lt;br /&gt;
&lt;br /&gt;
  if (weapon.isSerpent) {&lt;br /&gt;
    showElement(randomAttackValue);&lt;br /&gt;
&lt;br /&gt;
    if (weapon.isMagic) {&lt;br /&gt;
      showElement(randomMagicAttackValue);&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    hideElement(randomAttackValue);&lt;br /&gt;
    hideElement(randomMagicAttackValue);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (weapon.maxUpgrade &amp;lt; 1) {&lt;br /&gt;
    hideElement(weaponUpgrade.parentElement);&lt;br /&gt;
  } else {&lt;br /&gt;
    showElement(weaponUpgrade.parentElement);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (var upgrade = 0; upgrade &amp;lt;= weapon.maxUpgrade; upgrade++) {&lt;br /&gt;
    showElement(weaponUpgradeChildren[upgrade]);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (&lt;br /&gt;
    var upgrade = weapon.maxUpgrade + 1;&lt;br /&gt;
    upgrade &amp;lt; weaponUpgradeChildren.length;&lt;br /&gt;
    upgrade++&lt;br /&gt;
  ) {&lt;br /&gt;
    hideElement(weaponUpgradeChildren[upgrade]);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (currentUpgrade &amp;gt; weapon.maxUpgrade) {&lt;br /&gt;
    weaponUpgrade.value = weapon.maxUpgrade;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterCheckbox(checkbox, element) {&lt;br /&gt;
  if (checkbox.checked) {&lt;br /&gt;
    showElement(element);&lt;br /&gt;
  } else {&lt;br /&gt;
    hideElement(element);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterSkills(selectedClass, skillElementsToFilter) {&lt;br /&gt;
  for (var element of skillElementsToFilter) {&lt;br /&gt;
    if (isValueInArray(selectedClass, element.dataset.class)) {&lt;br /&gt;
      showElement(element);&lt;br /&gt;
    } else {&lt;br /&gt;
      hideElement(element);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterForm(characters, battle) {&lt;br /&gt;
  var { saveButton, characterCreation, toggleSiblings } = characters;&lt;br /&gt;
  var allowedWeaponsPerRace = battle.constants.allowedWeaponsPerRace;&lt;br /&gt;
  var battleChoice = battle.battleChoice;&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;change&amp;quot;, function (event) {&lt;br /&gt;
    var target = event.target;&lt;br /&gt;
    var targetName = target.name;&lt;br /&gt;
&lt;br /&gt;
    saveButtonOrange(saveButton);&lt;br /&gt;
    characters.unsavedChanges = true;&lt;br /&gt;
&lt;br /&gt;
    switch (targetName) {&lt;br /&gt;
      case &amp;quot;race&amp;quot;:&lt;br /&gt;
        var selectedRace = target.value;&lt;br /&gt;
        var classChoice = characterCreation.class;&lt;br /&gt;
        var weaponElement = characterCreation.weapon;&lt;br /&gt;
&lt;br /&gt;
        filterClass(selectedRace, classChoice);&lt;br /&gt;
        filterWeapon(&lt;br /&gt;
          selectedRace,&lt;br /&gt;
          weaponElement,&lt;br /&gt;
          characters.weaponCategory,&lt;br /&gt;
          allowedWeaponsPerRace&lt;br /&gt;
        );&lt;br /&gt;
        handleWeaponDisplay(&lt;br /&gt;
          characters.weaponCategory,&lt;br /&gt;
          characters.weaponDisplay,&lt;br /&gt;
          weaponElement.value&lt;br /&gt;
        );&lt;br /&gt;
        filterUpgrade(&lt;br /&gt;
          characterCreation.weaponUpgrade,&lt;br /&gt;
          weaponElement.value,&lt;br /&gt;
          characters.randomAttackValue,&lt;br /&gt;
          characters.randomMagicAttackValue&lt;br /&gt;
        );&lt;br /&gt;
        filterSkills(classChoice.value, characters.skillElementsToFilter);&lt;br /&gt;
        handleBonusVariationUpdate(&lt;br /&gt;
          characterCreation,&lt;br /&gt;
          characters.bonusVariation,&lt;br /&gt;
          true&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        battleChoice.resetAttackType = true;&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;class&amp;quot;:&lt;br /&gt;
        filterSkills(target.value, characters.skillElementsToFilter);&lt;br /&gt;
        handleBonusVariationUpdate(&lt;br /&gt;
          characterCreation,&lt;br /&gt;
          characters.bonusVariation,&lt;br /&gt;
          true&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        battleChoice.resetAttackType = true;&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;weapon&amp;quot;:&lt;br /&gt;
        var weaponElement = characterCreation.weapon;&lt;br /&gt;
&lt;br /&gt;
        handleWeaponDisplay(&lt;br /&gt;
          characters.weaponCategory,&lt;br /&gt;
          characters.weaponDisplay,&lt;br /&gt;
          weaponElement.value,&lt;br /&gt;
          target&lt;br /&gt;
        );&lt;br /&gt;
        filterUpgrade(&lt;br /&gt;
          characterCreation.weaponUpgrade,&lt;br /&gt;
          target.value,&lt;br /&gt;
          characters.randomAttackValue,&lt;br /&gt;
          characters.randomMagicAttackValue&lt;br /&gt;
        );&lt;br /&gt;
        handleBonusVariationUpdate(&lt;br /&gt;
          characterCreation,&lt;br /&gt;
          characters.bonusVariation&lt;br /&gt;
        );&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;isRiding&amp;quot;:&lt;br /&gt;
        battleChoice.resetAttackType = true;&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;isPolymorph&amp;quot;:&lt;br /&gt;
        battleChoice.resetAttackType = true;&lt;br /&gt;
        break;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (toggleSiblings.hasOwnProperty(targetName)) {&lt;br /&gt;
      filterCheckbox(target, toggleSiblings[targetName]);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      targetName.startsWith(&amp;quot;attackSkill&amp;quot;) ||&lt;br /&gt;
      targetName.startsWith(&amp;quot;horseSkill&amp;quot;)&lt;br /&gt;
    ) {&lt;br /&gt;
      battleChoice.resetAttackType = true;&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addUniquePseudo(characterDataObject, savedCharactersPseudo) {&lt;br /&gt;
  var characterPseudo = String(characterDataObject.name);&lt;br /&gt;
  var originalPseudo = characterPseudo;&lt;br /&gt;
  var count = 0;&lt;br /&gt;
&lt;br /&gt;
  var regex = /(.*)(\d)$/;&lt;br /&gt;
  var match = characterPseudo.match(regex);&lt;br /&gt;
&lt;br /&gt;
  if (match) {&lt;br /&gt;
    originalPseudo = match[1];&lt;br /&gt;
    count = match[2];&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  while (isValueInArray(characterPseudo, savedCharactersPseudo)) {&lt;br /&gt;
    characterPseudo = originalPseudo + count;&lt;br /&gt;
    count++;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  characterDataObject.name = characterPseudo;&lt;br /&gt;
  return [characterDataObject, characterPseudo];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function convertToNumber(value) {&lt;br /&gt;
  var valueNumber = Number(value);&lt;br /&gt;
  return isNaN(valueNumber) ? value : valueNumber;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getLocalStorageValue(key, defaultValue) {&lt;br /&gt;
  var storedValue = localStorage.getItem(key);&lt;br /&gt;
&lt;br /&gt;
  if (storedValue) {&lt;br /&gt;
    return JSON.parse(storedValue);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return defaultValue;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSavedCharacters() {&lt;br /&gt;
  return getLocalStorageValue(&amp;quot;mt2-calc.characters.saved&amp;quot;, {});&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSavedMonsters() {&lt;br /&gt;
  return getLocalStorageValue(&amp;quot;mt2-calc.monsters.saved&amp;quot;, {});&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSavedFights() {&lt;br /&gt;
  return getLocalStorageValue(&amp;quot;mt2-calc.fights.saved&amp;quot;, []);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getLastLang() {&lt;br /&gt;
  return getLocalStorageValue(&amp;quot;mt2-calc.language.last-used&amp;quot;, &amp;quot;&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveToLocalStorage(key, value) {&lt;br /&gt;
  localStorage.setItem(key, JSON.stringify(value));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateSavedCharacters(savedCharacters) {&lt;br /&gt;
  saveToLocalStorage(&amp;quot;mt2-calc.characters.saved&amp;quot;, savedCharacters);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateSavedMonsters(savedMonsters) {&lt;br /&gt;
  saveToLocalStorage(&amp;quot;mt2-calc.monsters.saved&amp;quot;, savedMonsters);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateSavedFights(savedFights) {&lt;br /&gt;
  saveToLocalStorage(&amp;quot;mt2-calc.fights.saved&amp;quot;, savedFights);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateLastLang(lang) {&lt;br /&gt;
  saveToLocalStorage(&amp;quot;mt2-calc.language.last-used&amp;quot;, lang);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveCharacter(&lt;br /&gt;
  savedCharacters,&lt;br /&gt;
  characterCreation,&lt;br /&gt;
  battle,&lt;br /&gt;
  newCharacter,&lt;br /&gt;
  characterDataObject&lt;br /&gt;
) {&lt;br /&gt;
  if (!characterDataObject) {&lt;br /&gt;
    var characterData = new FormData(characterCreation);&lt;br /&gt;
    var characterDataObject = {};&lt;br /&gt;
&lt;br /&gt;
    characterData.forEach(function (value, key) {&lt;br /&gt;
      characterDataObject[key] = convertToNumber(value);&lt;br /&gt;
    });&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var characterPseudo = characterDataObject.name;&lt;br /&gt;
  var { battleChoice } = battle;&lt;br /&gt;
&lt;br /&gt;
  savedCharacters[characterPseudo] = characterDataObject;&lt;br /&gt;
  updateSavedCharacters(savedCharacters);&lt;br /&gt;
&lt;br /&gt;
  if (newCharacter) {&lt;br /&gt;
    addBattleChoice(battleChoice, characterPseudo, characterDataObject);&lt;br /&gt;
  } else {&lt;br /&gt;
    updateBattleChoiceImage(&lt;br /&gt;
      battleChoice,&lt;br /&gt;
      characterPseudo,&lt;br /&gt;
      characterDataObject.race&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (battleChoice.resetAttackType) {&lt;br /&gt;
    if (isCharacterSelected(characterPseudo, battleChoice.attacker.selected)) {&lt;br /&gt;
      filterAttackTypeSelectionCharacter(&lt;br /&gt;
        characterDataObject,&lt;br /&gt;
        battleChoice.attackType&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
    battleChoice.resetAttackType = false;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveButtonGreen(saveButton) {&lt;br /&gt;
  saveButton.classList.remove(&amp;quot;unsaved-character&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveButtonOrange(saveButton) {&lt;br /&gt;
  saveButton.classList.add(&amp;quot;unsaved-character&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function characterCreationListener(characters, battle) {&lt;br /&gt;
  var { characterCreation, saveButton, weaponCategory } = characters;&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;submit&amp;quot;, handleSubmitForm);&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;invalid&amp;quot;, handleInvalidInput, true);&lt;br /&gt;
  document.addEventListener(&amp;quot;keydown&amp;quot;, handleSaveShortcut);&lt;br /&gt;
  weaponCategory.addEventListener(&amp;quot;mouseover&amp;quot;, handleTooltipOverflow);&lt;br /&gt;
&lt;br /&gt;
  function handleSubmitForm(event) {&lt;br /&gt;
    event.preventDefault();&lt;br /&gt;
&lt;br /&gt;
    if (characters.unsavedChanges) {&lt;br /&gt;
      saveCharacter(characters.savedCharacters, characterCreation, battle);&lt;br /&gt;
      saveButtonGreen(saveButton);&lt;br /&gt;
      characters.unsavedChanges = false;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function handleInvalidInput(event) {&lt;br /&gt;
    var target = event.target;&lt;br /&gt;
&lt;br /&gt;
    if (target.checkVisibility()) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var autoCorrectInput = target.closest(&amp;quot;.auto-correct-input&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      autoCorrectInput &amp;amp;&amp;amp;&lt;br /&gt;
      autoCorrectInput.classList.contains(&amp;quot;tabber-noactive&amp;quot;)&lt;br /&gt;
    ) {&lt;br /&gt;
      target.value = target.defaultValue;&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    openTargetTab(target);&lt;br /&gt;
    openTargetCollapsible(target);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function handleSaveShortcut(event) {&lt;br /&gt;
    if (event.ctrlKey &amp;amp;&amp;amp; event.key === &amp;quot;s&amp;quot;) {&lt;br /&gt;
      event.preventDefault();&lt;br /&gt;
      saveButton.click();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function handleTooltipOverflow(event) {&lt;br /&gt;
    var label = event.target.closest(&amp;quot;label&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (label) {&lt;br /&gt;
      var tooltip = label.lastChild;&lt;br /&gt;
&lt;br /&gt;
      if (tooltip.classList.contains(&amp;quot;popContenu&amp;quot;)) {&lt;br /&gt;
        var tooltipRect = tooltip.getBoundingClientRect();&lt;br /&gt;
        var modalRect = weaponCategory.getBoundingClientRect();&lt;br /&gt;
&lt;br /&gt;
        if (tooltipRect.right &amp;gt; modalRect.right) {&lt;br /&gt;
          tooltip.style.left = &amp;quot;-100%&amp;quot;;&lt;br /&gt;
        } else if (tooltipRect.left &amp;lt; modalRect.left) {&lt;br /&gt;
          tooltip.style.left = &amp;quot;200%&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function downloadData(content, type, filename) {&lt;br /&gt;
  var link = document.createElement(&amp;quot;a&amp;quot;);&lt;br /&gt;
  var blob = new Blob([content], { type: type });&lt;br /&gt;
  var blobURL = URL.createObjectURL(blob);&lt;br /&gt;
&lt;br /&gt;
  link.href = blobURL;&lt;br /&gt;
  link.download = filename;&lt;br /&gt;
  document.body.appendChild(link);&lt;br /&gt;
&lt;br /&gt;
  link.click();&lt;br /&gt;
  document.body.removeChild(link);&lt;br /&gt;
  URL.revokeObjectURL(blobURL);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function uploadCharacter(&lt;br /&gt;
  selectedFiles,&lt;br /&gt;
  characters,&lt;br /&gt;
  characterTemplate,&lt;br /&gt;
  charactersContainer,&lt;br /&gt;
  battle&lt;br /&gt;
) {&lt;br /&gt;
  var selectFilesLength = selectedFiles.length;&lt;br /&gt;
  var defaultPseudo = characters.defaultText.pseudo;&lt;br /&gt;
&lt;br /&gt;
  for (var fileIndex = 0; fileIndex &amp;lt; selectFilesLength; fileIndex++) {&lt;br /&gt;
    var selectedFile = selectedFiles[fileIndex];&lt;br /&gt;
&lt;br /&gt;
    if (selectedFile.type === &amp;quot;text/plain&amp;quot;) {&lt;br /&gt;
      var reader = new FileReader();&lt;br /&gt;
      reader.onload = function (e) {&lt;br /&gt;
        var fileContent = e.target.result;&lt;br /&gt;
        try {&lt;br /&gt;
          var characterDataObject = JSON.parse(fileContent);&lt;br /&gt;
&lt;br /&gt;
          if (characterDataObject.hasOwnProperty(&amp;quot;name&amp;quot;)) {&lt;br /&gt;
            var characterPseudo = String(characterDataObject.name);&lt;br /&gt;
&lt;br /&gt;
            hideElement(characters.characterCreation);&lt;br /&gt;
            characterPseudo = validPseudo(characterPseudo, defaultPseudo);&lt;br /&gt;
&lt;br /&gt;
            [characterDataObject, characterPseudo] = addUniquePseudo(&lt;br /&gt;
              characterDataObject,&lt;br /&gt;
              Object.keys(characters.savedCharacters)&lt;br /&gt;
            );&lt;br /&gt;
            var selectedCharacter = handleNewCharacter(&lt;br /&gt;
              characters,&lt;br /&gt;
              characterTemplate,&lt;br /&gt;
              charactersContainer,&lt;br /&gt;
              battle,&lt;br /&gt;
              characterPseudo&lt;br /&gt;
            )[0];&lt;br /&gt;
&lt;br /&gt;
            if (selectFilesLength === 1) {&lt;br /&gt;
              updateForm(&lt;br /&gt;
                characterDataObject,&lt;br /&gt;
                characters.characterCreation,&lt;br /&gt;
                characters,&lt;br /&gt;
                selectedCharacter,&lt;br /&gt;
                battle&lt;br /&gt;
              );&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            saveCharacter(&lt;br /&gt;
              characters.savedCharacters,&lt;br /&gt;
              characters.characterCreation,&lt;br /&gt;
              battle,&lt;br /&gt;
              true,&lt;br /&gt;
              characterDataObject&lt;br /&gt;
            );&lt;br /&gt;
          }&lt;br /&gt;
        } catch (error) {&lt;br /&gt;
          console.warn(error);&lt;br /&gt;
          if (error.name === &amp;quot;TypeError&amp;quot;) {&lt;br /&gt;
            // delete the character&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
      };&lt;br /&gt;
      reader.readAsText(selectedFile);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleUploadCharacter(&lt;br /&gt;
  characters,&lt;br /&gt;
  characterTemplate,&lt;br /&gt;
  charactersContainer,&lt;br /&gt;
  battle&lt;br /&gt;
) {&lt;br /&gt;
  var characterInput = characters.characterInput;&lt;br /&gt;
  var dropZone = characters.dropZone;&lt;br /&gt;
&lt;br /&gt;
  characterInput.accept = &amp;quot;.txt&amp;quot;;&lt;br /&gt;
  characterInput.multiple = true;&lt;br /&gt;
  dropZone.setAttribute(&amp;quot;tabindex&amp;quot;, &amp;quot;0&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  dropZone.addEventListener(&amp;quot;click&amp;quot;, function () {&lt;br /&gt;
    characterInput.click();&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  dropZone.addEventListener(&amp;quot;dragover&amp;quot;, function (event) {&lt;br /&gt;
    event.preventDefault();&lt;br /&gt;
    dropZone.classList.add(&amp;quot;drop-zone--dragover&amp;quot;);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  [&amp;quot;dragleave&amp;quot;, &amp;quot;dragend&amp;quot;].forEach(function (type) {&lt;br /&gt;
    dropZone.addEventListener(type, function () {&lt;br /&gt;
      dropZone.classList.remove(&amp;quot;drop-zone--dragover&amp;quot;);&lt;br /&gt;
    });&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  dropZone.addEventListener(&amp;quot;drop&amp;quot;, function (event) {&lt;br /&gt;
    event.preventDefault();&lt;br /&gt;
    uploadCharacter(&lt;br /&gt;
      event.dataTransfer.files,&lt;br /&gt;
      characters,&lt;br /&gt;
      characterTemplate,&lt;br /&gt;
      charactersContainer,&lt;br /&gt;
      battle&lt;br /&gt;
    );&lt;br /&gt;
    dropZone.classList.remove(&amp;quot;drop-zone--dragover&amp;quot;);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  characterInput.addEventListener(&amp;quot;change&amp;quot;, function (event) {&lt;br /&gt;
    uploadCharacter(&lt;br /&gt;
      event.target.files,&lt;br /&gt;
      characters,&lt;br /&gt;
      characterTemplate,&lt;br /&gt;
      charactersContainer,&lt;br /&gt;
      battle&lt;br /&gt;
    );&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function deleteCharacter(characters, pseudo, element, battle) {&lt;br /&gt;
  delete characters.savedCharacters[pseudo];&lt;br /&gt;
  element.remove();&lt;br /&gt;
&lt;br /&gt;
  updateSavedCharacters(characters.savedCharacters);&lt;br /&gt;
  removeBattleChoice(battle.battleChoice, pseudo, &amp;quot;character&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (&lt;br /&gt;
    !Object.keys(characters.savedCharacters).length ||&lt;br /&gt;
    characters.characterCreation.name.value === pseudo&lt;br /&gt;
  ) {&lt;br /&gt;
    saveButtonGreen(characters.saveButton);&lt;br /&gt;
    characters.unsavedChanges = false;&lt;br /&gt;
    hideElement(characters.characterCreation);&lt;br /&gt;
    showElement(characters.characterCreation.previousElementSibling);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function deleteMonster(characters, battle, monsterVnum) {&lt;br /&gt;
  var monsterElements = characters.monsterElements;&lt;br /&gt;
  var monsterType = characters.savedMonsters[monsterVnum].category;&lt;br /&gt;
&lt;br /&gt;
  if (monsterElements.hasOwnProperty(monsterVnum)) {&lt;br /&gt;
    monsterElements[monsterVnum].remove();&lt;br /&gt;
    delete monsterElements[monsterVnum];&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  delete characters.savedMonsters[monsterVnum];&lt;br /&gt;
&lt;br /&gt;
  updateSavedMonsters(characters.savedMonsters);&lt;br /&gt;
  removeBattleChoice(battle.battleChoice, monsterVnum, monsterType);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleStyle(characters, selectedElement) {&lt;br /&gt;
  var currentCharacter = characters.currentCharacter;&lt;br /&gt;
&lt;br /&gt;
  if (currentCharacter) {&lt;br /&gt;
    currentCharacter.classList.remove(&amp;quot;selected-character&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  selectedElement.classList.add(&amp;quot;selected-character&amp;quot;);&lt;br /&gt;
  characters.currentCharacter = selectedElement;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateForm(&lt;br /&gt;
  formData,&lt;br /&gt;
  characterCreation,&lt;br /&gt;
  characters,&lt;br /&gt;
  selectedElement,&lt;br /&gt;
  battle&lt;br /&gt;
) {&lt;br /&gt;
  saveButtonGreen(characters.saveButton);&lt;br /&gt;
  hideElement(characterCreation.previousElementSibling);&lt;br /&gt;
  showElement(characterCreation);&lt;br /&gt;
  handleStyle(characters, selectedElement);&lt;br /&gt;
&lt;br /&gt;
  characterCreation.reset();&lt;br /&gt;
&lt;br /&gt;
  for (var [name, value] of Object.entries(formData)) {&lt;br /&gt;
    var formElement = characterCreation[name];&lt;br /&gt;
&lt;br /&gt;
    if (!formElement) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (formElement.type === &amp;quot;checkbox&amp;quot;) {&lt;br /&gt;
      if (isChecked(value)) {&lt;br /&gt;
        formElement.checked = true;&lt;br /&gt;
      }&lt;br /&gt;
    } else {&lt;br /&gt;
      formElement.value = value;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  var selectedRace = characterCreation.race.value;&lt;br /&gt;
  var classChoice = characterCreation.class;&lt;br /&gt;
  var weaponElement = characterCreation.weapon;&lt;br /&gt;
&lt;br /&gt;
  filterClass(selectedRace, classChoice, true);&lt;br /&gt;
  filterWeapon(&lt;br /&gt;
    selectedRace,&lt;br /&gt;
    weaponElement,&lt;br /&gt;
    characters.weaponCategory,&lt;br /&gt;
    battle.constants.allowedWeaponsPerRace,&lt;br /&gt;
    true&lt;br /&gt;
  );&lt;br /&gt;
  handlePolymorphDisplay(&lt;br /&gt;
    characters,&lt;br /&gt;
    characterCreation.polymorphMonster.value,&lt;br /&gt;
    characterCreation.polymorphMonsterImage.value&lt;br /&gt;
  );&lt;br /&gt;
  handleWeaponDisplay(&lt;br /&gt;
    characters.weaponCategory,&lt;br /&gt;
    characters.weaponDisplay,&lt;br /&gt;
    weaponElement.value&lt;br /&gt;
  );&lt;br /&gt;
  filterUpgrade(&lt;br /&gt;
    characterCreation.weaponUpgrade,&lt;br /&gt;
    weaponElement.value,&lt;br /&gt;
    characters.randomAttackValue,&lt;br /&gt;
    characters.randomMagicAttackValue&lt;br /&gt;
  );&lt;br /&gt;
  for (var [targetName, sibling] of Object.entries(characters.toggleSiblings)) {&lt;br /&gt;
    filterCheckbox(characterCreation[targetName], sibling);&lt;br /&gt;
  }&lt;br /&gt;
  filterSkills(classChoice.value, characters.skillElementsToFilter);&lt;br /&gt;
  handleBonusVariationUpdate(characterCreation, characters.bonusVariation);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleClickOnCharacter(&lt;br /&gt;
  spanInput,&lt;br /&gt;
  target,&lt;br /&gt;
  characters,&lt;br /&gt;
  characterElement,&lt;br /&gt;
  battle,&lt;br /&gt;
  edition&lt;br /&gt;
) {&lt;br /&gt;
  var displayedPseudo = characters.characterCreation.name.value;&lt;br /&gt;
  var pseudo = spanInput.dataset.name;&lt;br /&gt;
  var { unsavedWarning, deleteWarning } = characters.defaultText;&lt;br /&gt;
&lt;br /&gt;
  if (edition) {&lt;br /&gt;
    if (!characters.unsavedChanges) {&lt;br /&gt;
      updateForm(&lt;br /&gt;
        characters.savedCharacters[pseudo],&lt;br /&gt;
        characters.characterCreation,&lt;br /&gt;
        characters,&lt;br /&gt;
        characterElement,&lt;br /&gt;
        battle&lt;br /&gt;
      );&lt;br /&gt;
    } else if (displayedPseudo === pseudo) {&lt;br /&gt;
      // pass&lt;br /&gt;
    } else {&lt;br /&gt;
      var result = confirm(unsavedWarning);&lt;br /&gt;
&lt;br /&gt;
      if (result) {&lt;br /&gt;
        updateForm(&lt;br /&gt;
          characters.savedCharacters[pseudo],&lt;br /&gt;
          characters.characterCreation,&lt;br /&gt;
          characters,&lt;br /&gt;
          characterElement,&lt;br /&gt;
          battle&lt;br /&gt;
        );&lt;br /&gt;
        characters.unsavedChanges = false;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    if (target.tagName === &amp;quot;path&amp;quot;) {&lt;br /&gt;
      target = target.parentElement;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    switch (target.dataset.icon) {&lt;br /&gt;
      case &amp;quot;duplicate&amp;quot;:&lt;br /&gt;
        if (!characters.unsavedChanges) {&lt;br /&gt;
          addNewCharacter(&lt;br /&gt;
            characters,&lt;br /&gt;
            characters.newCharacterTemplate,&lt;br /&gt;
            characters.charactersContainer,&lt;br /&gt;
            battle,&lt;br /&gt;
            pseudo&lt;br /&gt;
          );&lt;br /&gt;
        } else {&lt;br /&gt;
          var result = confirm(unsavedWarning);&lt;br /&gt;
&lt;br /&gt;
          if (result) {&lt;br /&gt;
            addNewCharacter(&lt;br /&gt;
              characters,&lt;br /&gt;
              characters.newCharacterTemplate,&lt;br /&gt;
              characters.charactersContainer,&lt;br /&gt;
              battle,&lt;br /&gt;
              pseudo&lt;br /&gt;
            );&lt;br /&gt;
            saveButtonGreen(characters.saveButton);&lt;br /&gt;
            characters.unsavedChanges = false;&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
        break;&lt;br /&gt;
&lt;br /&gt;
      case &amp;quot;download&amp;quot;:&lt;br /&gt;
        var character = characters.savedCharacters[pseudo];&lt;br /&gt;
        downloadData(&lt;br /&gt;
          JSON.stringify(character),&lt;br /&gt;
          &amp;quot;text/plain&amp;quot;,&lt;br /&gt;
          character.name + &amp;quot;.txt&amp;quot;&lt;br /&gt;
        );&lt;br /&gt;
        break;&lt;br /&gt;
&lt;br /&gt;
      case &amp;quot;delete&amp;quot;:&lt;br /&gt;
        var result = confirm(deleteWarning.replace(&amp;quot;[[]]&amp;quot;, pseudo));&lt;br /&gt;
        if (result) {&lt;br /&gt;
          deleteCharacter(characters, pseudo, characterElement, battle);&lt;br /&gt;
        }&lt;br /&gt;
        break;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleNewCharacter(&lt;br /&gt;
  characters,&lt;br /&gt;
  characterTemplate,&lt;br /&gt;
  charactersContainer,&lt;br /&gt;
  battle,&lt;br /&gt;
  pseudo&lt;br /&gt;
) {&lt;br /&gt;
  var newCharacterTemplate = characterTemplate.cloneNode(true);&lt;br /&gt;
  var spanInput = newCharacterTemplate.querySelector(&amp;quot;span.input&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  newCharacterTemplate.setAttribute(&amp;quot;tabindex&amp;quot;, &amp;quot;0&amp;quot;);&lt;br /&gt;
  charactersContainer.appendChild(newCharacterTemplate);&lt;br /&gt;
&lt;br /&gt;
  if (pseudo) {&lt;br /&gt;
    spanInput.textContent = pseudo;&lt;br /&gt;
    spanInput.setAttribute(&amp;quot;data-name&amp;quot;, pseudo);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  newCharacterTemplate.addEventListener(&amp;quot;click&amp;quot;, function (event) {&lt;br /&gt;
    var target = event.target;&lt;br /&gt;
&lt;br /&gt;
    if (target.tagName === &amp;quot;path&amp;quot; || target.tagName === &amp;quot;svg&amp;quot;) {&lt;br /&gt;
      handleClickOnCharacter(&lt;br /&gt;
        spanInput,&lt;br /&gt;
        target,&lt;br /&gt;
        characters,&lt;br /&gt;
        newCharacterTemplate,&lt;br /&gt;
        battle&lt;br /&gt;
      );&lt;br /&gt;
    } else {&lt;br /&gt;
      handleClickOnCharacter(&lt;br /&gt;
        spanInput,&lt;br /&gt;
        null,&lt;br /&gt;
        characters,&lt;br /&gt;
        newCharacterTemplate,&lt;br /&gt;
        battle,&lt;br /&gt;
        true&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  newCharacterTemplate.addEventListener(&amp;quot;keydown&amp;quot;, function (event) {&lt;br /&gt;
    if (event.keyCode === 13) {&lt;br /&gt;
      event.target.click();&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  return [newCharacterTemplate, spanInput];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function validPseudo(pseudo, defaultPseudo) {&lt;br /&gt;
  var newPseudo = pseudoFormat(pseudo);&lt;br /&gt;
&lt;br /&gt;
  if (!newPseudo) {&lt;br /&gt;
    return pseudoFormat(defaultPseudo);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return newPseudo;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addNewCharacter(&lt;br /&gt;
  characters,&lt;br /&gt;
  characterTemplate,&lt;br /&gt;
  charactersContainer,&lt;br /&gt;
  battle,&lt;br /&gt;
  pseudoToDuplicate&lt;br /&gt;
) {&lt;br /&gt;
  function editAndSetCharacterPseudoInput(selectedCharacter, spanInput) {&lt;br /&gt;
    var maxPseudoLength = 20;&lt;br /&gt;
    var defaultPseudo = characters.defaultText.pseudo;&lt;br /&gt;
&lt;br /&gt;
    var selection = window.getSelection();&lt;br /&gt;
    var range = document.createRange();&lt;br /&gt;
&lt;br /&gt;
    if (pseudoToDuplicate) {&lt;br /&gt;
      spanInput.textContent = pseudoToDuplicate;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    spanInput.contentEditable = true;&lt;br /&gt;
    spanInput.focus();&lt;br /&gt;
    range.selectNodeContents(spanInput);&lt;br /&gt;
    selection.removeAllRanges();&lt;br /&gt;
    selection.addRange(range);&lt;br /&gt;
&lt;br /&gt;
    function pseudoValidation() {&lt;br /&gt;
      var characterPseudo = validPseudo(spanInput.textContent, defaultPseudo);&lt;br /&gt;
      var characterDataObject = { name: characterPseudo };&lt;br /&gt;
&lt;br /&gt;
      if (pseudoToDuplicate) {&lt;br /&gt;
        characterDataObject = copyObject(&lt;br /&gt;
          characters.savedCharacters[pseudoToDuplicate]&lt;br /&gt;
        );&lt;br /&gt;
        characterDataObject.name = characterPseudo;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      [characterDataObject, characterPseudo] = addUniquePseudo(&lt;br /&gt;
        characterDataObject,&lt;br /&gt;
        Object.keys(characters.savedCharacters)&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      selection.removeAllRanges();&lt;br /&gt;
      spanInput.contentEditable = false;&lt;br /&gt;
      spanInput.textContent = characterPseudo;&lt;br /&gt;
      spanInput.setAttribute(&amp;quot;data-name&amp;quot;, characterPseudo);&lt;br /&gt;
&lt;br /&gt;
      updateForm(&lt;br /&gt;
        characterDataObject,&lt;br /&gt;
        characters.characterCreation,&lt;br /&gt;
        characters,&lt;br /&gt;
        selectedCharacter,&lt;br /&gt;
        battle&lt;br /&gt;
      );&lt;br /&gt;
      saveCharacter(&lt;br /&gt;
        characters.savedCharacters,&lt;br /&gt;
        characters.characterCreation,&lt;br /&gt;
        battle,&lt;br /&gt;
        true&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handleMaxLength(event) {&lt;br /&gt;
      if (spanInput.textContent.length &amp;gt; maxPseudoLength) {&lt;br /&gt;
        spanInput.textContent = spanInput.textContent.slice(0, maxPseudoLength);&lt;br /&gt;
        range.setStart(spanInput.childNodes[0], maxPseudoLength);&lt;br /&gt;
        selection.removeAllRanges();&lt;br /&gt;
        selection.addRange(range);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handleBlur() {&lt;br /&gt;
      spanInput.removeEventListener(&amp;quot;blur&amp;quot;, handleBlur);&lt;br /&gt;
      spanInput.removeEventListener(&amp;quot;input&amp;quot;, handleMaxLength);&lt;br /&gt;
      pseudoValidation();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handleKeyDown(event) {&lt;br /&gt;
      if (event.key === &amp;quot;Enter&amp;quot;) {&lt;br /&gt;
        event.preventDefault();&lt;br /&gt;
&lt;br /&gt;
        spanInput.removeEventListener(&amp;quot;keydown&amp;quot;, handleKeyDown);&lt;br /&gt;
        spanInput.removeEventListener(&amp;quot;blur&amp;quot;, handleBlur);&lt;br /&gt;
        spanInput.removeEventListener(&amp;quot;input&amp;quot;, handleMaxLength);&lt;br /&gt;
&lt;br /&gt;
        pseudoValidation();&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    spanInput.addEventListener(&amp;quot;input&amp;quot;, handleMaxLength);&lt;br /&gt;
    spanInput.addEventListener(&amp;quot;keydown&amp;quot;, handleKeyDown);&lt;br /&gt;
    spanInput.addEventListener(&amp;quot;blur&amp;quot;, handleBlur);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  hideElement(characters.characterCreation);&lt;br /&gt;
  var [selectedCharacter, spanInput] = handleNewCharacter(&lt;br /&gt;
    characters,&lt;br /&gt;
    characterTemplate,&lt;br /&gt;
    charactersContainer,&lt;br /&gt;
    battle&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  editAndSetCharacterPseudoInput(selectedCharacter, spanInput);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleFocus() {&lt;br /&gt;
  var tooltipLinks = document.querySelectorAll(&amp;quot;div.tooltip a&amp;quot;);&lt;br /&gt;
  tooltipLinks.forEach(function (link) {&lt;br /&gt;
    link.setAttribute(&amp;quot;tabindex&amp;quot;, -1);&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function resetBonusVariation(bonusVariation) {&lt;br /&gt;
  function resetInput(input) {&lt;br /&gt;
    input.removeAttribute(&amp;quot;min&amp;quot;);&lt;br /&gt;
    input.removeAttribute(&amp;quot;max&amp;quot;);&lt;br /&gt;
    input.defaultValue = 0;&lt;br /&gt;
    input.value = input.defaultValue;&lt;br /&gt;
  }&lt;br /&gt;
  var { minValue, maxValue, checkbox, container, disabledText, selectedText } =&lt;br /&gt;
    bonusVariation;&lt;br /&gt;
&lt;br /&gt;
  resetInput(minValue);&lt;br /&gt;
  resetInput(maxValue);&lt;br /&gt;
  showElement(disabledText);&lt;br /&gt;
  hideElement(selectedText);&lt;br /&gt;
  hideElement(container);&lt;br /&gt;
  checkbox.checked = false;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleBonusVariationUpdate(&lt;br /&gt;
  characterCreation,&lt;br /&gt;
  bonusVariation,&lt;br /&gt;
  resetSkill&lt;br /&gt;
) {&lt;br /&gt;
  var selectedBonus = characterCreation.bonusVariation.value;&lt;br /&gt;
  var displayName = characterCreation.bonusVariationName.value;&lt;br /&gt;
&lt;br /&gt;
  if (&lt;br /&gt;
    resetSkill &amp;amp;&amp;amp;&lt;br /&gt;
    (selectedBonus.startsWith(&amp;quot;attackSkill&amp;quot;) ||&lt;br /&gt;
      selectedBonus.startsWith(&amp;quot;horseSkill&amp;quot;) ||&lt;br /&gt;
      selectedBonus.startsWith(&amp;quot;skillBonus&amp;quot;))&lt;br /&gt;
  ) {&lt;br /&gt;
    resetBonusVariation(bonusVariation);&lt;br /&gt;
    return;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (&lt;br /&gt;
    characterCreation.hasOwnProperty(selectedBonus) &amp;amp;&amp;amp;&lt;br /&gt;
    selectedBonus != 0 &amp;amp;&amp;amp;&lt;br /&gt;
    displayName != 0&lt;br /&gt;
  ) {&lt;br /&gt;
    handleBonusVariation(&lt;br /&gt;
      characterCreation[selectedBonus],&lt;br /&gt;
      bonusVariation,&lt;br /&gt;
      displayName&lt;br /&gt;
    );&lt;br /&gt;
  } else {&lt;br /&gt;
    resetBonusVariation(bonusVariation);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getTargetContent(targetParent, targetName, isSkill) {&lt;br /&gt;
  var targetContent = &amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  if (targetParent.children.length &amp;lt;= 1) {&lt;br /&gt;
    targetContent = targetParent.textContent;&lt;br /&gt;
  } else if (targetName === &amp;quot;weaponUpgrade&amp;quot;) {&lt;br /&gt;
    targetContent = targetParent.children[1].textContent;&lt;br /&gt;
  } else if (targetName === &amp;quot;level&amp;quot;) {&lt;br /&gt;
    targetContent = targetParent.textContent.replace(&amp;quot;Lv&amp;quot;, &amp;quot;&amp;quot;).trim();&lt;br /&gt;
  } else if (isSkill) {&lt;br /&gt;
    var container = targetParent.children[1];&lt;br /&gt;
&lt;br /&gt;
    for (var index = 0; index &amp;lt; container.children.length; index++) {&lt;br /&gt;
      var element = container.children[index];&lt;br /&gt;
&lt;br /&gt;
      if (element.checkVisibility()) {&lt;br /&gt;
        targetContent += element.textContent;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    for (var index = 1; index &amp;lt; targetParent.children.length; index++) {&lt;br /&gt;
      var element = targetParent.children[index];&lt;br /&gt;
&lt;br /&gt;
      if (element.checkVisibility()) {&lt;br /&gt;
        targetContent += element.textContent;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return targetContent.trim();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleBonusVariation(target, bonusVariation, displayName) {&lt;br /&gt;
  var {&lt;br /&gt;
    minValue,&lt;br /&gt;
    maxValue,&lt;br /&gt;
    checkbox,&lt;br /&gt;
    container,&lt;br /&gt;
    disabledText,&lt;br /&gt;
    selectedText,&lt;br /&gt;
    displaySpan,&lt;br /&gt;
  } = bonusVariation;&lt;br /&gt;
&lt;br /&gt;
  var {&lt;br /&gt;
    min: targetMin,&lt;br /&gt;
    max: targetMax,&lt;br /&gt;
    name: targetName,&lt;br /&gt;
    value: targetValue,&lt;br /&gt;
    parentElement: targetParent,&lt;br /&gt;
    tagName,&lt;br /&gt;
  } = target;&lt;br /&gt;
&lt;br /&gt;
  targetMin = Number(targetMin);&lt;br /&gt;
  targetMax = Number(targetMax);&lt;br /&gt;
  targetValue = Number(targetValue);&lt;br /&gt;
&lt;br /&gt;
  var isSkill = tagName === &amp;quot;SELECT&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  if (isSkill) {&lt;br /&gt;
    var options = target.options;&lt;br /&gt;
&lt;br /&gt;
    targetMin = options[0].value;&lt;br /&gt;
    targetMax = options[options.length - 1].value;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  minValue.min = targetMin;&lt;br /&gt;
  minValue.max = targetMax;&lt;br /&gt;
  minValue.defaultValue = targetMin;&lt;br /&gt;
&lt;br /&gt;
  maxValue.min = targetMin;&lt;br /&gt;
  maxValue.max = targetMax;&lt;br /&gt;
  maxValue.defaultValue = targetMin;&lt;br /&gt;
&lt;br /&gt;
  hideElement(disabledText);&lt;br /&gt;
  showElement(selectedText);&lt;br /&gt;
&lt;br /&gt;
  if (displayName) {&lt;br /&gt;
    minValue.value = Math.min(Math.max(minValue.value, targetMin), targetMax);&lt;br /&gt;
    maxValue.value = Math.max(Math.min(maxValue.value, targetMax), targetMin);&lt;br /&gt;
&lt;br /&gt;
    displaySpan.textContent = displayName;&lt;br /&gt;
  } else {&lt;br /&gt;
    var { input, inputName, tabButton } = bonusVariation;&lt;br /&gt;
    var targetContent = getTargetContent(targetParent, targetName, isSkill);&lt;br /&gt;
&lt;br /&gt;
    input.value = targetName;&lt;br /&gt;
    inputName.value = targetContent;&lt;br /&gt;
    displaySpan.textContent = targetContent;&lt;br /&gt;
&lt;br /&gt;
    minValue.value = Math.max(targetValue - 10, targetMin);&lt;br /&gt;
    maxValue.value = Math.min(targetValue + 10, targetMax);&lt;br /&gt;
&lt;br /&gt;
    showElement(container);&lt;br /&gt;
    checkbox.checked = true;&lt;br /&gt;
&lt;br /&gt;
    tabButton.click();&lt;br /&gt;
    tabButton.scrollIntoView(true);&lt;br /&gt;
&lt;br /&gt;
    input.dispatchEvent(newChangeEvent());&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function characterManagement(characters, battle) {&lt;br /&gt;
  var {&lt;br /&gt;
    newCharacterTemplate: characterTemplate,&lt;br /&gt;
    charactersContainer,&lt;br /&gt;
    addNewCharacterButton,&lt;br /&gt;
    saveButton,&lt;br /&gt;
    characterCreation,&lt;br /&gt;
    bonusVariation,&lt;br /&gt;
    defaultText: { unsavedWarning },&lt;br /&gt;
  } = characters;&lt;br /&gt;
&lt;br /&gt;
  Object.keys(characters.savedCharacters).forEach(function (pseudo) {&lt;br /&gt;
    handleNewCharacter(&lt;br /&gt;
      characters,&lt;br /&gt;
      characterTemplate,&lt;br /&gt;
      charactersContainer,&lt;br /&gt;
      battle,&lt;br /&gt;
      pseudo&lt;br /&gt;
    );&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  addNewCharacterButton.addEventListener(&amp;quot;click&amp;quot;, function (event) {&lt;br /&gt;
    if (!characters.unsavedChanges) {&lt;br /&gt;
      addNewCharacter(&lt;br /&gt;
        characters,&lt;br /&gt;
        characterTemplate,&lt;br /&gt;
        charactersContainer,&lt;br /&gt;
        battle&lt;br /&gt;
      );&lt;br /&gt;
    } else {&lt;br /&gt;
      var result = confirm(unsavedWarning);&lt;br /&gt;
&lt;br /&gt;
      if (result) {&lt;br /&gt;
        addNewCharacter(&lt;br /&gt;
          characters,&lt;br /&gt;
          characterTemplate,&lt;br /&gt;
          charactersContainer,&lt;br /&gt;
          battle&lt;br /&gt;
        );&lt;br /&gt;
        saveButtonGreen(saveButton);&lt;br /&gt;
        characters.unsavedChanges = false;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  handleUploadCharacter(&lt;br /&gt;
    characters,&lt;br /&gt;
    characterTemplate,&lt;br /&gt;
    charactersContainer,&lt;br /&gt;
    battle&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  function handleLongPress(target) {&lt;br /&gt;
    if (target.tagName !== &amp;quot;INPUT&amp;quot; &amp;amp;&amp;amp; target.tagName !== &amp;quot;SELECT&amp;quot;) {&lt;br /&gt;
      target = target.querySelector(&amp;quot;input&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      !target ||&lt;br /&gt;
      (target.type !== &amp;quot;number&amp;quot; &amp;amp;&amp;amp;&lt;br /&gt;
        !target.classList.contains(&amp;quot;skill-select&amp;quot;) &amp;amp;&amp;amp;&lt;br /&gt;
        target.name !== &amp;quot;weaponUpgrade&amp;quot;) ||&lt;br /&gt;
      target.classList.contains(&amp;quot;disabled-variation&amp;quot;)&lt;br /&gt;
    ) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    handleBonusVariation(target, bonusVariation, null);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;click&amp;quot;, function (event) {&lt;br /&gt;
    if (event.shiftKey || event.ctrlKey) {&lt;br /&gt;
      handleLongPress(event.target);&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  var longPressTimer;&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;touchstart&amp;quot;, function (event) {&lt;br /&gt;
    longPressTimer = setTimeout(function () {&lt;br /&gt;
      handleLongPress(event.target);&lt;br /&gt;
    }, 800);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;touchend&amp;quot;, function () {&lt;br /&gt;
    clearTimeout(longPressTimer);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;touchmove&amp;quot;, function () {&lt;br /&gt;
    clearTimeout(longPressTimer);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  filterForm(characters, battle);&lt;br /&gt;
  characterCreationListener(characters, battle);&lt;br /&gt;
  handleFocus();&lt;br /&gt;
&lt;br /&gt;
  window.addEventListener(&amp;quot;beforeunload&amp;quot;, function (event) {&lt;br /&gt;
    if (characters.unsavedChanges) {&lt;br /&gt;
      event.preventDefault();&lt;br /&gt;
      return &amp;quot;&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addMonsterElement(characters, battle, monsterVnum, iframeInfo) {&lt;br /&gt;
  var { monsterTemplate, monstersContainer } = characters;&lt;br /&gt;
  var monsterElement = monsterTemplate.cloneNode(true);&lt;br /&gt;
  var spanInput = monsterElement.querySelector(&amp;quot;span.input&amp;quot;);&lt;br /&gt;
  var deleteSvg = monsterElement.querySelector(&amp;quot;svg&amp;quot;);&lt;br /&gt;
  var monsterName = getMonsterName(monsterVnum);&lt;br /&gt;
  var displayName = characters.translateMonsters&lt;br /&gt;
    ? getTranslatedMonsterName(monsterVnum)&lt;br /&gt;
    : monsterName;&lt;br /&gt;
  var link = createWikiLink(monsterName, displayName);&lt;br /&gt;
&lt;br /&gt;
  monsterElement.setAttribute(&amp;quot;tabindex&amp;quot;, &amp;quot;0&amp;quot;);&lt;br /&gt;
  spanInput.appendChild(link);&lt;br /&gt;
  monstersContainer.appendChild(monsterElement);&lt;br /&gt;
  characters.monsterElements[monsterVnum] = monsterElement;&lt;br /&gt;
&lt;br /&gt;
  deleteSvg.addEventListener(&amp;quot;click&amp;quot;, function () {&lt;br /&gt;
    var monster = characters.savedMonsters[monsterVnum];&lt;br /&gt;
    iframeInfo[monster.category].shouldBeUpdated = true;&lt;br /&gt;
&lt;br /&gt;
    deleteMonster(characters, battle, monsterVnum);&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addNewMonster(&lt;br /&gt;
  characters,&lt;br /&gt;
  battle,&lt;br /&gt;
  monsterVnum,&lt;br /&gt;
  monsterImage,&lt;br /&gt;
  iframeInfo,&lt;br /&gt;
  category&lt;br /&gt;
) {&lt;br /&gt;
  if (isValueInArray(monsterVnum, Object.keys(characters.savedMonsters)))&lt;br /&gt;
    return;&lt;br /&gt;
&lt;br /&gt;
  var newMonster = {&lt;br /&gt;
    image: monsterImage,&lt;br /&gt;
    category: category,&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  characters.savedMonsters[monsterVnum] = newMonster;&lt;br /&gt;
&lt;br /&gt;
  addMonsterElement(characters, battle, monsterVnum, iframeInfo);&lt;br /&gt;
  updateSavedMonsters(characters.savedMonsters);&lt;br /&gt;
  addBattleChoice(battle.battleChoice, monsterVnum, newMonster, true);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function translateiFrame(iframeDoc) {&lt;br /&gt;
  const filterName = iframeDoc.getElementById(&amp;quot;filter-name&amp;quot;);&lt;br /&gt;
  const { general, special } = translation;&lt;br /&gt;
  const translatedPlaceholder = special.placeholder;&lt;br /&gt;
&lt;br /&gt;
  if (filterName &amp;amp;&amp;amp; translatedPlaceholder) {&lt;br /&gt;
    filterName.placeholder = translatedPlaceholder;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (const element of iframeDoc.querySelectorAll(&amp;quot;[data-t]&amp;quot;)) {&lt;br /&gt;
    const translateText = general[element.dataset.t];&lt;br /&gt;
&lt;br /&gt;
    if (translateText) {&lt;br /&gt;
      element.textContent = translateText;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function translateMonsterCard(card, cardNameElement, monsterVnum) {&lt;br /&gt;
  const mapping = translation.mapping;&lt;br /&gt;
  const levelElement = card.querySelector(&amp;quot;[data-level]&amp;quot;);&lt;br /&gt;
  const typeElement = card.querySelector(&amp;quot;[data-type] a&amp;quot;);&lt;br /&gt;
  const damageElements = card.querySelectorAll(&amp;quot;[data-damage] a&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  cardNameElement.textContent = getTranslatedMonsterName(monsterVnum);&lt;br /&gt;
&lt;br /&gt;
  levelElement.textContent = levelElement.textContent.replace(&lt;br /&gt;
    &amp;quot;Boss&amp;quot;,&lt;br /&gt;
    translation.special.boss&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  if (typeElement) {&lt;br /&gt;
    typeElement.textContent = mapping[typeElement.textContent];&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  damageElements.forEach((damageElement) =&amp;gt; {&lt;br /&gt;
    damageElement.textContent = mapping[damageElement.textContent];&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addButtonsToCardsAndTranslate(&lt;br /&gt;
  characters,&lt;br /&gt;
  iframeDoc,&lt;br /&gt;
  iframeInfo,&lt;br /&gt;
  category&lt;br /&gt;
) {&lt;br /&gt;
  const buttonTemplates = characters.monsterButtonTemplates.children[0];&lt;br /&gt;
  const cardToEdit = iframeDoc.getElementById(&amp;quot;cards-container&amp;quot;).children;&lt;br /&gt;
  const { nameToVnum } = iframeInfo;&lt;br /&gt;
  const vnumToButtons = iframeInfo[category].vnumToButtons;&lt;br /&gt;
  const translateMonsters = characters.translateMonsters;&lt;br /&gt;
&lt;br /&gt;
  for (let cardIndex = 0; cardIndex &amp;lt; cardToEdit.length; cardIndex++) {&lt;br /&gt;
    const card = cardToEdit[cardIndex];&lt;br /&gt;
    const cardNameElement = card.querySelector(&amp;quot;[data-name]&amp;quot;).firstChild;&lt;br /&gt;
    const buttonTemplatesClone = buttonTemplates.cloneNode(true);&lt;br /&gt;
    const cardName = cardNameElement.title.replace(/\s/g, &amp;quot; &amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (!nameToVnum.hasOwnProperty(cardName)) {&lt;br /&gt;
      card.style.display = &amp;quot;none&amp;quot;;&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    const monsterVnum = nameToVnum[cardName];&lt;br /&gt;
&lt;br /&gt;
    buttonTemplatesClone.dataset.monsterId = monsterVnum;&lt;br /&gt;
    card.lastElementChild.appendChild(buttonTemplatesClone);&lt;br /&gt;
    vnumToButtons[monsterVnum] = buttonTemplatesClone.children;&lt;br /&gt;
&lt;br /&gt;
    if (translateMonsters) {&lt;br /&gt;
      translateMonsterCard(card, cardNameElement, monsterVnum);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (translateMonsters) {&lt;br /&gt;
    translateiFrame(iframeDoc);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateiFrameButtons(characters, iframeInfo, category) {&lt;br /&gt;
  var addedMonsters = Object.keys(characters.savedMonsters);&lt;br /&gt;
  var { currentiFrameIsMonster } = iframeInfo;&lt;br /&gt;
  var vnumToButtons = iframeInfo[category].vnumToButtons;&lt;br /&gt;
  var isPolymorphModal = category === &amp;quot;monster&amp;quot; &amp;amp;&amp;amp; !currentiFrameIsMonster;&lt;br /&gt;
&lt;br /&gt;
  for (var monsterVnum in vnumToButtons) {&lt;br /&gt;
    var [addButton, deleteButton, selectButton] = vnumToButtons[monsterVnum];&lt;br /&gt;
&lt;br /&gt;
    if (isPolymorphModal) {&lt;br /&gt;
      hideElement(addButton);&lt;br /&gt;
      hideElement(deleteButton);&lt;br /&gt;
      showElement(selectButton);&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isValueInArray(monsterVnum, addedMonsters)) {&lt;br /&gt;
      hideElement(addButton);&lt;br /&gt;
      showElement(deleteButton);&lt;br /&gt;
      hideElement(selectButton);&lt;br /&gt;
    } else {&lt;br /&gt;
      showElement(addButton);&lt;br /&gt;
      hideElement(deleteButton);&lt;br /&gt;
      hideElement(selectButton);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  iframeInfo.lastiFrameIsMonster = currentiFrameIsMonster;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getMonsterImage(buttonsContainer) {&lt;br /&gt;
  var elder = buttonsContainer.parentElement.firstElementChild;&lt;br /&gt;
  var image = elder.querySelector(&amp;quot;img&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (image) {&lt;br /&gt;
    return image.getAttribute(&amp;quot;src&amp;quot;) || &amp;quot;&amp;quot;;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return &amp;quot;&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleiFrame(iframeInfo, category) {&lt;br /&gt;
  var { characters, battle } = iframeInfo;&lt;br /&gt;
  var iframeInfoCategory = iframeInfo[category];&lt;br /&gt;
  var { iframe, pageName, vnumToButtons } = iframeInfoCategory;&lt;br /&gt;
  var loadingAnimation = iframeInfoCategory.iframe.previousElementSibling;&lt;br /&gt;
&lt;br /&gt;
  iframe.src = mw.util.getUrl(pageName);&lt;br /&gt;
&lt;br /&gt;
  window.addEventListener(&amp;quot;message&amp;quot;, function (event) {&lt;br /&gt;
    if (&lt;br /&gt;
      event.origin !== window.origin ||&lt;br /&gt;
      event.data?.type !== &amp;quot;filterReady&amp;quot; ||&lt;br /&gt;
      event.data.category !== category&lt;br /&gt;
    ) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
    var iframeDoc = iframe.contentDocument || iframe.contentWindow.document;&lt;br /&gt;
    var htmlElement = iframeDoc.documentElement;&lt;br /&gt;
    var iframeBody = iframeDoc.body;&lt;br /&gt;
    var content = iframeDoc.getElementById(&amp;quot;show-after-loading&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    htmlElement.setAttribute(&amp;quot;lang&amp;quot;, characters.currentLanguage);&lt;br /&gt;
    iframeBody.firstElementChild.replaceWith(content);&lt;br /&gt;
&lt;br /&gt;
    iframeBody.style.background = &amp;quot;transparent&amp;quot;;&lt;br /&gt;
    iframeBody.style.paddingRight = &amp;quot;10px&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    addButtonsToCardsAndTranslate(characters, iframeDoc, iframeInfo, category);&lt;br /&gt;
    updateiFrameButtons(characters, iframeInfo, category);&lt;br /&gt;
&lt;br /&gt;
    iframeInfoCategory.loadIsFinished = true;&lt;br /&gt;
&lt;br /&gt;
    hideElement(loadingAnimation);&lt;br /&gt;
    showElement(iframe);&lt;br /&gt;
&lt;br /&gt;
    iframeDoc.addEventListener(&amp;quot;click&amp;quot;, handleButtonClick);&lt;br /&gt;
&lt;br /&gt;
    function handleButtonClick(event) {&lt;br /&gt;
      var target = event.target;&lt;br /&gt;
      var link = target.closest(&amp;quot;a&amp;quot;);&lt;br /&gt;
      var buttonsContainer = target.closest(&amp;quot;.handle-monster&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
      if (link) {&lt;br /&gt;
        event.preventDefault();&lt;br /&gt;
        window.open(link.href, &amp;quot;_blank&amp;quot;);&lt;br /&gt;
      } else if (buttonsContainer) {&lt;br /&gt;
        var { monsterId: monsterVnum } = buttonsContainer.dataset;&lt;br /&gt;
&lt;br /&gt;
        // polymorph iframe&lt;br /&gt;
        if (category === &amp;quot;monster&amp;quot; &amp;amp;&amp;amp; !iframeInfo.currentiFrameIsMonster) {&lt;br /&gt;
          var monsterImage = getMonsterImage(buttonsContainer);&lt;br /&gt;
          changePolymorphValues(&lt;br /&gt;
            characters.characterCreation,&lt;br /&gt;
            monsterVnum,&lt;br /&gt;
            monsterImage&lt;br /&gt;
          );&lt;br /&gt;
          handlePolymorphDisplay(characters, monsterVnum, monsterImage);&lt;br /&gt;
          iframe.dispatchEvent(newChangeEvent());&lt;br /&gt;
        } else {&lt;br /&gt;
          var addedMonsters = Object.keys(characters.savedMonsters);&lt;br /&gt;
          var [addButton, deleteButton] = vnumToButtons[monsterVnum];&lt;br /&gt;
&lt;br /&gt;
          if (isValueInArray(monsterVnum, addedMonsters)) {&lt;br /&gt;
            deleteMonster(characters, battle, monsterVnum);&lt;br /&gt;
            showElement(addButton);&lt;br /&gt;
            hideElement(deleteButton);&lt;br /&gt;
          } else {&lt;br /&gt;
            var monsterImage = getMonsterImage(buttonsContainer);&lt;br /&gt;
            addNewMonster(&lt;br /&gt;
              characters,&lt;br /&gt;
              battle,&lt;br /&gt;
              monsterVnum,&lt;br /&gt;
              monsterImage,&lt;br /&gt;
              iframeInfo,&lt;br /&gt;
              category&lt;br /&gt;
            );&lt;br /&gt;
            hideElement(addButton);&lt;br /&gt;
            showElement(deleteButton);&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getNameToVnumMapping() {&lt;br /&gt;
  var nameToVnum = {};&lt;br /&gt;
&lt;br /&gt;
  for (var monsterVnum in monsterData) {&lt;br /&gt;
    nameToVnum[monsterData[monsterVnum][monsterData[monsterVnum].length - 1]] =&lt;br /&gt;
      monsterVnum;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return nameToVnum;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function monsterManagement(characters, battle) {&lt;br /&gt;
  var { monsteriFrame, stoneiFrame } = characters;&lt;br /&gt;
  var monsterVnums = Object.keys(monsterData);&lt;br /&gt;
&lt;br /&gt;
  var iframeInfo = {&lt;br /&gt;
    lastiFrameIsMonster: false,&lt;br /&gt;
    currentiFrameIsMonster: false,&lt;br /&gt;
    characters: characters,&lt;br /&gt;
    battle: battle,&lt;br /&gt;
    nameToVnum: getNameToVnumMapping(),&lt;br /&gt;
    monster: {&lt;br /&gt;
      isLoaded: false,&lt;br /&gt;
      loadIsFinished: false,&lt;br /&gt;
      shouldBeUpdated: false,&lt;br /&gt;
      vnumToButtons: {},&lt;br /&gt;
      pageName: &amp;quot;Monstres&amp;quot;,&lt;br /&gt;
      iframe: monsteriFrame,&lt;br /&gt;
    },&lt;br /&gt;
    stone: {&lt;br /&gt;
      isLoaded: false,&lt;br /&gt;
      loadIsFinished: false,&lt;br /&gt;
      shouldBeUpdated: false,&lt;br /&gt;
      vnumToButtons: {},&lt;br /&gt;
      pageName: &amp;quot;Pierres Metin&amp;quot;,&lt;br /&gt;
      iframe: stoneiFrame,&lt;br /&gt;
    },&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  document.addEventListener(&amp;quot;modalOpen&amp;quot;, function (event) {&lt;br /&gt;
    var modalName = event.detail.name;&lt;br /&gt;
&lt;br /&gt;
    if (modalName === &amp;quot;monster&amp;quot; || modalName === &amp;quot;stone&amp;quot;) {&lt;br /&gt;
      handleModal(event.target, modalName);&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  function handleModal(target, modalName) {&lt;br /&gt;
    var iframeInfoCategory = iframeInfo[modalName];&lt;br /&gt;
&lt;br /&gt;
    if (modalName === &amp;quot;monster&amp;quot;) {&lt;br /&gt;
      var isMonsteriFrame = target.id === &amp;quot;add-new-monster&amp;quot;;&lt;br /&gt;
      iframeInfo.currentiFrameIsMonster = isMonsteriFrame;&lt;br /&gt;
&lt;br /&gt;
      if (&lt;br /&gt;
        iframeInfoCategory.loadIsFinished &amp;amp;&amp;amp;&lt;br /&gt;
        ((isMonsteriFrame &amp;amp;&amp;amp; !iframeInfo.lastiFrameIsMonster) ||&lt;br /&gt;
          (!isMonsteriFrame &amp;amp;&amp;amp; iframeInfo.lastiFrameIsMonster))&lt;br /&gt;
      ) {&lt;br /&gt;
        iframeInfoCategory.shouldBeUpdated = true;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!iframeInfoCategory.isLoaded) {&lt;br /&gt;
      handleiFrame(iframeInfo, modalName);&lt;br /&gt;
      iframeInfoCategory.isLoaded = true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      iframeInfoCategory.loadIsFinished &amp;amp;&amp;amp;&lt;br /&gt;
      iframeInfoCategory.shouldBeUpdated&lt;br /&gt;
    ) {&lt;br /&gt;
      updateiFrameButtons(characters, iframeInfo, modalName);&lt;br /&gt;
      iframeInfoCategory.shouldBeUpdated = false;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  Object.keys(characters.savedMonsters)&lt;br /&gt;
    .slice()&lt;br /&gt;
    .forEach(function (monsterVnum) {&lt;br /&gt;
      if (isValueInArray(monsterVnum, monsterVnums)) {&lt;br /&gt;
        addMonsterElement(characters, battle, monsterVnum, iframeInfo);&lt;br /&gt;
      } else {&lt;br /&gt;
        deleteMonster(characters, battle, monsterVnum);&lt;br /&gt;
      }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function hideAttackType(container, input, attackType) {&lt;br /&gt;
  hideElement(container);&lt;br /&gt;
&lt;br /&gt;
  if (input.checked) {&lt;br /&gt;
    var defaultInput = attackType.defaultInput;&lt;br /&gt;
&lt;br /&gt;
    input.checked = false;&lt;br /&gt;
    defaultInput.checked = true;&lt;br /&gt;
    defaultInput.dispatchEvent(newChangeEvent());&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterAttackTypeSelectionCharacter(attacker, attackType) {&lt;br /&gt;
  var attackerClass = attacker.class;&lt;br /&gt;
  var attackerIsNotPolymorph = !isPolymorph(attacker);&lt;br /&gt;
  var { elements: attackTypeElements } = attackType;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; attackTypeElements.length; index++) {&lt;br /&gt;
    var { container, input, inputClass, inputValue } =&lt;br /&gt;
      attackTypeElements[index];&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      attackerIsNotPolymorph &amp;amp;&amp;amp;&lt;br /&gt;
      attacker[inputValue] &amp;amp;&amp;amp;&lt;br /&gt;
      (attackerClass === inputClass ||&lt;br /&gt;
        (inputValue.startsWith(&amp;quot;horseSkill&amp;quot;) &amp;amp;&amp;amp;&lt;br /&gt;
          isRiding(attacker) &amp;amp;&amp;amp;&lt;br /&gt;
          (!inputClass || isValueInArray(attackerClass, inputClass))))&lt;br /&gt;
    ) {&lt;br /&gt;
      showElement(container);&lt;br /&gt;
    } else {&lt;br /&gt;
      hideAttackType(container, input, attackType);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterAttackTypeSelectionMonster(attackType) {&lt;br /&gt;
  var attackTypeElements = attackType.elements;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; attackTypeElements.length; index++) {&lt;br /&gt;
    var { container, input } = attackTypeElements[index];&lt;br /&gt;
    hideAttackType(container, input, attackType);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function removeBattleElement(battleChoice, nameOrVnum, category, type) {&lt;br /&gt;
  var elements = battleChoice[category][type].elements;&lt;br /&gt;
&lt;br /&gt;
  if (elements.hasOwnProperty(nameOrVnum)) {&lt;br /&gt;
    elements[nameOrVnum].container.remove();&lt;br /&gt;
    delete elements[nameOrVnum];&lt;br /&gt;
    battleChoice[category][type].count--;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function removeBattleChoice(battleChoice, nameOrVnum, type) {&lt;br /&gt;
  battleChoice.categories.forEach(function (category) {&lt;br /&gt;
    if (category === &amp;quot;attacker&amp;quot; &amp;amp;&amp;amp; type === &amp;quot;stone&amp;quot;) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
    var selected = battleChoice[category].selected;&lt;br /&gt;
&lt;br /&gt;
    if (selected) {&lt;br /&gt;
      var { type: selectedType, nameOrVnum: selectedNameOrVnum } =&lt;br /&gt;
        parseTypeAndName(selected);&lt;br /&gt;
&lt;br /&gt;
      if (nameOrVnum === selectedNameOrVnum &amp;amp;&amp;amp; type === selectedType) {&lt;br /&gt;
        resetBattleChoiceButton(battleChoice, category);&lt;br /&gt;
        battleChoice[category].selected = null;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    removeBattleElement(battleChoice, nameOrVnum, category, type);&lt;br /&gt;
    updateBattleChoiceText(battleChoice, category, type);&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addBattleElement(&lt;br /&gt;
  battleChoice,&lt;br /&gt;
  pseudoOrVnum,&lt;br /&gt;
  characterOrMonster,&lt;br /&gt;
  category,&lt;br /&gt;
  isMonster&lt;br /&gt;
) {&lt;br /&gt;
  var { template, raceToImage, translateMonsters } = battleChoice;&lt;br /&gt;
  var battleChoiceCategory = battleChoice[category];&lt;br /&gt;
  var templateClone = template.cloneNode(true);&lt;br /&gt;
  var label = templateClone.firstElementChild;&lt;br /&gt;
  var [input, image, span] = label.children;&lt;br /&gt;
  var imageSrc;&lt;br /&gt;
  var name;&lt;br /&gt;
  var type;&lt;br /&gt;
&lt;br /&gt;
  if (isMonster) {&lt;br /&gt;
    type = characterOrMonster.category;&lt;br /&gt;
&lt;br /&gt;
    if (type === &amp;quot;stone&amp;quot; &amp;amp;&amp;amp; category === &amp;quot;attacker&amp;quot;) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
    imageSrc = characterOrMonster.image;&lt;br /&gt;
    name = translateMonsters&lt;br /&gt;
      ? getTranslatedMonsterName(pseudoOrVnum)&lt;br /&gt;
      : getMonsterName(pseudoOrVnum);&lt;br /&gt;
  } else {&lt;br /&gt;
    type = &amp;quot;character&amp;quot;;&lt;br /&gt;
    imageSrc = raceToImage[characterOrMonster.race];&lt;br /&gt;
    name = pseudoOrVnum;&lt;br /&gt;
    label.classList.add(&amp;quot;notranslate&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var value = type + &amp;quot;-&amp;quot; + pseudoOrVnum;&lt;br /&gt;
  var id = category + &amp;quot;-&amp;quot; + value;&lt;br /&gt;
  var currentBattleChoice = battleChoiceCategory[type];&lt;br /&gt;
&lt;br /&gt;
  label.setAttribute(&amp;quot;for&amp;quot;, id);&lt;br /&gt;
  input.value = value;&lt;br /&gt;
  input.id = id;&lt;br /&gt;
  input.name = category;&lt;br /&gt;
  span.textContent = name;&lt;br /&gt;
&lt;br /&gt;
  handleImageFromWiki(image, imageSrc);&lt;br /&gt;
&lt;br /&gt;
  currentBattleChoice.container.appendChild(templateClone);&lt;br /&gt;
  currentBattleChoice.count++;&lt;br /&gt;
  currentBattleChoice.elements[pseudoOrVnum] = {&lt;br /&gt;
    container: templateClone,&lt;br /&gt;
    image: image,&lt;br /&gt;
    name: name,&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  updateBattleChoiceText(battleChoice, category, type);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addBattleChoice(&lt;br /&gt;
  battleChoice,&lt;br /&gt;
  pseudoOrVnum,&lt;br /&gt;
  characterOrMonster,&lt;br /&gt;
  isMonster = false&lt;br /&gt;
) {&lt;br /&gt;
  addBattleElement(&lt;br /&gt;
    battleChoice,&lt;br /&gt;
    pseudoOrVnum,&lt;br /&gt;
    characterOrMonster,&lt;br /&gt;
    &amp;quot;attacker&amp;quot;,&lt;br /&gt;
    isMonster&lt;br /&gt;
  );&lt;br /&gt;
  addBattleElement(&lt;br /&gt;
    battleChoice,&lt;br /&gt;
    pseudoOrVnum,&lt;br /&gt;
    characterOrMonster,&lt;br /&gt;
    &amp;quot;victim&amp;quot;,&lt;br /&gt;
    isMonster&lt;br /&gt;
  );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateBattleChoiceImage(battleChoice, characterName, newRace) {&lt;br /&gt;
  var imageSrc = battleChoice.raceToImage[newRace];&lt;br /&gt;
&lt;br /&gt;
  battleChoice.categories.forEach(function (category) {&lt;br /&gt;
    handleImageFromWiki(&lt;br /&gt;
      battleChoice[category].character.elements[characterName].image,&lt;br /&gt;
      imageSrc&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    var selected = battleChoice[category].selected;&lt;br /&gt;
&lt;br /&gt;
    if (isCharacterSelected(characterName, selected)) {&lt;br /&gt;
      updateBattleChoiceButton(battleChoice, category, selected);&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateBattleChoiceText(battleChoice, category, type) {&lt;br /&gt;
  var { count, container } = battleChoice[category][type];&lt;br /&gt;
  var parentContainer = container.parentElement;&lt;br /&gt;
&lt;br /&gt;
  if (count === 0) {&lt;br /&gt;
    hideElement(parentContainer);&lt;br /&gt;
    showElement(parentContainer.nextElementSibling);&lt;br /&gt;
  } else if (count === 1) {&lt;br /&gt;
    showElement(parentContainer);&lt;br /&gt;
    hideElement(parentContainer.nextElementSibling);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateBattleChoice(characters, battleChoice) {&lt;br /&gt;
  var templateImage = battleChoice.template.querySelector(&amp;quot;img&amp;quot;);&lt;br /&gt;
  var attackerImage = battleChoice.attacker.buttonContent.querySelector(&amp;quot;img&amp;quot;);&lt;br /&gt;
  var victimImage = battleChoice.victim.buttonContent.querySelector(&amp;quot;img&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  resetImageFromWiki(templateImage);&lt;br /&gt;
  resetImageFromWiki(attackerImage);&lt;br /&gt;
  resetImageFromWiki(victimImage);&lt;br /&gt;
&lt;br /&gt;
  for (var [pseudo, character] of Object.entries(characters.savedCharacters)) {&lt;br /&gt;
    addBattleChoice(battleChoice, pseudo, character);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (var [vnum, monster] of Object.entries(characters.savedMonsters)) {&lt;br /&gt;
    addBattleChoice(battleChoice, vnum, monster, true);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateBattleChoiceButton(battleChoice, category, data) {&lt;br /&gt;
  var battleChoiceCategory = battleChoice[category];&lt;br /&gt;
  var { defaultButtonContent, buttonContent } = battleChoiceCategory;&lt;br /&gt;
  var [buttonImage, buttonSpan] = buttonContent.firstElementChild.children;&lt;br /&gt;
  var { type, nameOrVnum } = parseTypeAndName(data);&lt;br /&gt;
  var { name, image } = battleChoiceCategory[type].elements[nameOrVnum];&lt;br /&gt;
&lt;br /&gt;
  hideElement(defaultButtonContent);&lt;br /&gt;
  showElement(buttonContent);&lt;br /&gt;
&lt;br /&gt;
  buttonSpan.textContent = name;&lt;br /&gt;
  buttonImage.src = image.src;&lt;br /&gt;
  battleChoiceCategory.selected = data;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function resetBattleChoiceButton(battleChoice, category) {&lt;br /&gt;
  var { defaultButtonContent, buttonContent } = battleChoice[category];&lt;br /&gt;
&lt;br /&gt;
  showElement(defaultButtonContent);&lt;br /&gt;
  hideElement(buttonContent);&lt;br /&gt;
&lt;br /&gt;
  if (category === &amp;quot;attacker&amp;quot;) {&lt;br /&gt;
    filterAttackTypeSelectionMonster(battleChoice.attackType);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isPC(character) {&lt;br /&gt;
  if (character.race === 0 || character.race === 1) {&lt;br /&gt;
    return false;&lt;br /&gt;
  }&lt;br /&gt;
  return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isBoss(character) {&lt;br /&gt;
  return character.race === 0 &amp;amp;&amp;amp; character.rank &amp;gt;= 5;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isStone(character) {&lt;br /&gt;
  return character.race === 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isMeleeAttacker(monster) {&lt;br /&gt;
  return monster.attack == 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isRangeAttacker(monster) {&lt;br /&gt;
  return monster.attack == 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isMagicAttacker(monster) {&lt;br /&gt;
  return monster.attack == 2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isMagicClass(character) {&lt;br /&gt;
  return character.race === &amp;quot;shaman&amp;quot; || character.class === &amp;quot;black_magic&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isDispell(character, skillId) {&lt;br /&gt;
  return character.class === &amp;quot;weaponary&amp;quot; &amp;amp;&amp;amp; skillId === 6;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isPolymorph(character) {&lt;br /&gt;
  return isChecked(character.isPolymorph);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isRiding(character) {&lt;br /&gt;
  return isChecked(character.isRiding);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isBow(weaponType) {&lt;br /&gt;
  return weaponType === 2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcAttackFactor(attacker, victim) {&lt;br /&gt;
  function calcCoeffK(dex, level) {&lt;br /&gt;
    return Math.min(90, Math.floor((2 * dex + level) / 3));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var K1 = calcCoeffK(attacker.polymorphDex, attacker.level);&lt;br /&gt;
  var K2 = calcCoeffK(victim.polymorphDex, attacker.level);&lt;br /&gt;
&lt;br /&gt;
  var AR = (K1 + 210) / 300;&lt;br /&gt;
  var ER = (((2 * K2 + 5) / (K2 + 95)) * 3) / 10;&lt;br /&gt;
&lt;br /&gt;
  return truncateNumber(AR - ER, 8);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcMainAttackValue(attacker) {&lt;br /&gt;
  var leadership = 0;&lt;br /&gt;
  var weaponGrowth = 0;&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker)) {&lt;br /&gt;
    weaponGrowth = attacker.weapon.growth;&lt;br /&gt;
    leadership = attacker.leadership;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return 2 * (attacker.level + weaponGrowth) + leadership;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcStatAttackValue(character) {&lt;br /&gt;
  switch (character.race) {&lt;br /&gt;
    case &amp;quot;warrior&amp;quot;:&lt;br /&gt;
    case &amp;quot;sura&amp;quot;:&lt;br /&gt;
      return 2 * character.str;&lt;br /&gt;
    case &amp;quot;ninja&amp;quot;:&lt;br /&gt;
      return Math.floor((1 / 4) * (character.str + 7 * character.dex));&lt;br /&gt;
    case &amp;quot;shaman&amp;quot;:&lt;br /&gt;
      return Math.floor((1 / 3) * (5 * character.int + character.dex));&lt;br /&gt;
    case &amp;quot;lycan&amp;quot;:&lt;br /&gt;
      return character.vit + 2 * character.dex;&lt;br /&gt;
    default:&lt;br /&gt;
      return 2 * character.str;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcPvpCriticalAttackRange(minAttackValue, maxAttackValue, growth) {&lt;br /&gt;
  return Array.from(&lt;br /&gt;
    { length: maxAttackValue - minAttackValue + 1 },&lt;br /&gt;
    (_, index) =&amp;gt; (minAttackValue + growth + index) * 2&lt;br /&gt;
  );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcSecondaryAttackValue(attacker, isPlayerVsPlayer) {&lt;br /&gt;
  let attackValueOther = 0;&lt;br /&gt;
&lt;br /&gt;
  let minAttackValue = 0;&lt;br /&gt;
  let maxAttackValue = 0;&lt;br /&gt;
&lt;br /&gt;
  let minAttackValueSlash = 0;&lt;br /&gt;
  let maxAttackValueSlash = 0;&lt;br /&gt;
&lt;br /&gt;
  let type, isSerpent, growth;&lt;br /&gt;
&lt;br /&gt;
  let criticalAttackRange;&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker)) {&lt;br /&gt;
    ({ type, isSerpent, minAttackValue, maxAttackValue, growth } =&lt;br /&gt;
      attacker.weapon);&lt;br /&gt;
&lt;br /&gt;
    if (isSerpent) {&lt;br /&gt;
      minAttackValue = Math.max(0, attacker.minAttackValueRandom - growth);&lt;br /&gt;
      maxAttackValue = Math.max(&lt;br /&gt;
        minAttackValue,&lt;br /&gt;
        attacker.maxAttackValueRandom - growth&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    minAttackValueSlash = Math.min(&lt;br /&gt;
      attacker.minAttackValueSlash,&lt;br /&gt;
      attacker.maxAttackValueSlash&lt;br /&gt;
    );&lt;br /&gt;
    maxAttackValueSlash = Math.max(&lt;br /&gt;
      attacker.minAttackValueSlash,&lt;br /&gt;
      attacker.maxAttackValueSlash&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    attackValueOther += attacker.attackValue;&lt;br /&gt;
&lt;br /&gt;
    if (isBow(type) &amp;amp;&amp;amp; !isPolymorph(attacker)) {&lt;br /&gt;
      attackValueOther += 25;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isPlayerVsPlayer) {&lt;br /&gt;
      criticalAttackRange = calcPvpCriticalAttackRange(&lt;br /&gt;
        minAttackValue,&lt;br /&gt;
        maxAttackValue,&lt;br /&gt;
        growth&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    minAttackValue = attacker.minAttackValue;&lt;br /&gt;
    maxAttackValue = attacker.maxAttackValue;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  minAttackValue += attacker.minAttackValuePolymorph;&lt;br /&gt;
  maxAttackValue += attacker.maxAttackValuePolymorph;&lt;br /&gt;
&lt;br /&gt;
  attackValueOther += attacker.statAttackValue;&lt;br /&gt;
  attackValueOther += attacker.horseAttackValue;&lt;br /&gt;
&lt;br /&gt;
  const weaponInterval = maxAttackValue - minAttackValue + 1;&lt;br /&gt;
  const slashInterval = maxAttackValueSlash - minAttackValueSlash + 1;&lt;br /&gt;
&lt;br /&gt;
  const totalCardinal = weaponInterval * slashInterval * 1_000_000;&lt;br /&gt;
  const minInterval = Math.min(weaponInterval, slashInterval);&lt;br /&gt;
&lt;br /&gt;
  minAttackValue += minAttackValueSlash;&lt;br /&gt;
  maxAttackValue += maxAttackValueSlash;&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    minAttackValue: minAttackValue,&lt;br /&gt;
    maxAttackValue: maxAttackValue,&lt;br /&gt;
    attackValueOther: attackValueOther,&lt;br /&gt;
    totalCardinal: totalCardinal,&lt;br /&gt;
    weights: calcWeights(minAttackValue, maxAttackValue, minInterval),&lt;br /&gt;
    possibleDamageCount: maxAttackValue - minAttackValue + 1,&lt;br /&gt;
    criticalAttackRange: criticalAttackRange,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcMagicAttackValue(attacker, isPlayerVsPlayer) {&lt;br /&gt;
  let minMagicAttackValueSlash = 0;&lt;br /&gt;
  let maxMagicAttackValueSlash = 0;&lt;br /&gt;
&lt;br /&gt;
  let criticalAttackRange;&lt;br /&gt;
&lt;br /&gt;
  let {&lt;br /&gt;
    isSerpent,&lt;br /&gt;
    minMagicAttackValue,&lt;br /&gt;
    maxMagicAttackValue,&lt;br /&gt;
    minAttackValue,&lt;br /&gt;
    maxAttackValue,&lt;br /&gt;
    growth,&lt;br /&gt;
  } = attacker.weapon;&lt;br /&gt;
&lt;br /&gt;
  if (isSerpent) {&lt;br /&gt;
    minMagicAttackValue = Math.max(0, attacker.minMagicAttackValueRandom);&lt;br /&gt;
    maxMagicAttackValue = Math.max(&lt;br /&gt;
      minMagicAttackValue,&lt;br /&gt;
      attacker.maxMagicAttackValueRandom&lt;br /&gt;
    );&lt;br /&gt;
    minAttackValue = Math.max(0, attacker.minAttackValueRandom - growth);&lt;br /&gt;
    maxAttackValue = Math.max(&lt;br /&gt;
      minAttackValue,&lt;br /&gt;
      attacker.maxAttackValueRandom - growth&lt;br /&gt;
    );&lt;br /&gt;
  } else {&lt;br /&gt;
    minMagicAttackValue += growth;&lt;br /&gt;
    maxMagicAttackValue += growth;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (isPlayerVsPlayer) {&lt;br /&gt;
    criticalAttackRange = calcPvpCriticalAttackRange(&lt;br /&gt;
      minAttackValue,&lt;br /&gt;
      maxAttackValue,&lt;br /&gt;
      growth&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  minMagicAttackValueSlash = Math.min(&lt;br /&gt;
    attacker.minMagicAttackValueSlash,&lt;br /&gt;
    attacker.maxMagicAttackValueSlash&lt;br /&gt;
  );&lt;br /&gt;
  maxMagicAttackValueSlash = Math.max(&lt;br /&gt;
    attacker.minMagicAttackValueSlash,&lt;br /&gt;
    attacker.maxMagicAttackValueSlash&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  const weaponInterval = maxMagicAttackValue - minMagicAttackValue + 1;&lt;br /&gt;
  const slashInterval = maxMagicAttackValueSlash - minMagicAttackValueSlash + 1;&lt;br /&gt;
&lt;br /&gt;
  const totalCardinal = weaponInterval * slashInterval * 1_000_000;&lt;br /&gt;
  const minInterval = Math.min(weaponInterval, slashInterval);&lt;br /&gt;
&lt;br /&gt;
  minMagicAttackValue += minMagicAttackValueSlash;&lt;br /&gt;
  maxMagicAttackValue += maxMagicAttackValueSlash;&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    minMagicAttackValue: minMagicAttackValue,&lt;br /&gt;
    maxMagicAttackValue: maxMagicAttackValue,&lt;br /&gt;
    magicAttackValueAugmentation: getMagicAttackValueAugmentation(&lt;br /&gt;
      minMagicAttackValue,&lt;br /&gt;
      maxMagicAttackValue,&lt;br /&gt;
      attacker.magicAttackValue&lt;br /&gt;
    ),&lt;br /&gt;
    totalCardinal: totalCardinal,&lt;br /&gt;
    weights: calcWeights(minMagicAttackValue, maxMagicAttackValue, minInterval),&lt;br /&gt;
    possibleDamageCount: maxMagicAttackValue - minMagicAttackValue + 1,&lt;br /&gt;
    criticalAttackRange: criticalAttackRange,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getPolymorphPower(polymorphPoint, polymorphPowerTable) {&lt;br /&gt;
  return polymorphPowerTable[polymorphPoint];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSkillPower(skillPoint, skillPowerTable) {&lt;br /&gt;
  return skillPowerTable[skillPoint];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getMarriageBonusValue(character, marriageTable, itemName) {&lt;br /&gt;
  let index;&lt;br /&gt;
  const lovePoint = character.lovePoint;&lt;br /&gt;
&lt;br /&gt;
  if (lovePoint &amp;lt; 65) {&lt;br /&gt;
    index = 0;&lt;br /&gt;
  } else if (lovePoint &amp;lt; 80) {&lt;br /&gt;
    index = 1;&lt;br /&gt;
  } else if (lovePoint &amp;lt; 100) {&lt;br /&gt;
    index = 2;&lt;br /&gt;
  } else {&lt;br /&gt;
    index = 3;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return marriageTable[itemName][index];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcDamageWithPrimaryBonuses(damage, bonusValues) {&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.attackValueCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  damage += bonusValues.attackValueMarriage;&lt;br /&gt;
&lt;br /&gt;
  damage = Math.floor(&lt;br /&gt;
    (damage * bonusValues.monsterResistanceMarriageCoeff) / 100&lt;br /&gt;
  );&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.monsterResistanceCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  damage += Math.floor((damage * bonusValues.typeBonusCoeff) / 100);&lt;br /&gt;
  damage +=&lt;br /&gt;
    Math.floor((damage * bonusValues.raceBonusCoeff) / 100) -&lt;br /&gt;
    Math.floor((damage * bonusValues.raceResistanceCoeff) / 100);&lt;br /&gt;
  damage += Math.floor((damage * bonusValues.stoneBonusCoeff) / 100);&lt;br /&gt;
  damage += Math.floor((damage * bonusValues.monsterBonusCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  const elementBonusCoeff = bonusValues.elementBonusCoeff;&lt;br /&gt;
&lt;br /&gt;
  damage +=&lt;br /&gt;
    Math.trunc((damage * elementBonusCoeff[0]) / 10000) +&lt;br /&gt;
    Math.trunc((damage * elementBonusCoeff[1]) / 10000) +&lt;br /&gt;
    Math.trunc((damage * elementBonusCoeff[2]) / 10000) +&lt;br /&gt;
    Math.trunc((damage * elementBonusCoeff[3]) / 10000) +&lt;br /&gt;
    Math.trunc((damage * elementBonusCoeff[4]) / 10000) +&lt;br /&gt;
    Math.trunc((damage * elementBonusCoeff[5]) / 10000);&lt;br /&gt;
&lt;br /&gt;
  damage = Math.floor(damage * bonusValues.damageMultiplier);&lt;br /&gt;
&lt;br /&gt;
  return Math.max(0, damage);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcFinalDamage(&lt;br /&gt;
  finalDamage,&lt;br /&gt;
  damageWithPrimaryBonuses,&lt;br /&gt;
  bonusValues,&lt;br /&gt;
  criticalAttackRange,&lt;br /&gt;
  damageByType&lt;br /&gt;
) {&lt;br /&gt;
  for (let criticalIndex = 0; criticalIndex &amp;lt; 2; criticalIndex++) {&lt;br /&gt;
    if (bonusValues.skipCriticalStep[criticalIndex]) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
    let beforeCriticalDamage = finalDamage;&lt;br /&gt;
    let damageValues = criticalIndex&lt;br /&gt;
      ? criticalAttackRange || [finalDamage]&lt;br /&gt;
      : [0];&lt;br /&gt;
&lt;br /&gt;
    for (let index = 0, len = damageValues.length; index &amp;lt; len; index++) {&lt;br /&gt;
      let afterCriticalDamage = beforeCriticalDamage + damageValues[index];&lt;br /&gt;
&lt;br /&gt;
      for (let piercingIndex = 0; piercingIndex &amp;lt; 2; piercingIndex++) {&lt;br /&gt;
        if (bonusValues.skipPiercingStep[piercingIndex]) {&lt;br /&gt;
          continue;&lt;br /&gt;
        }&lt;br /&gt;
        let damage = afterCriticalDamage;&lt;br /&gt;
&lt;br /&gt;
        if (piercingIndex) {&lt;br /&gt;
          damage += Math.min(&lt;br /&gt;
            bonusValues.defenseBoost,&lt;br /&gt;
            damageWithPrimaryBonuses&lt;br /&gt;
          );&lt;br /&gt;
          damage += Math.floor(&lt;br /&gt;
            (damageWithPrimaryBonuses * bonusValues.extraPiercingHitCoeff) /&lt;br /&gt;
              1000&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        damage = Math.floor((damage * bonusValues.averageDamageCoeff) / 100);&lt;br /&gt;
        damage = Math.floor(&lt;br /&gt;
          (damage * bonusValues.averageDamageResistanceCoeff) / 100&lt;br /&gt;
        );&lt;br /&gt;
        damage = Math.floor((damage * bonusValues.skillDamageCoeff) / 100);&lt;br /&gt;
        damage = Math.floor(&lt;br /&gt;
          (damage * bonusValues.skillDamageResistanceCoeff) / 100&lt;br /&gt;
        );&lt;br /&gt;
        damage = Math.floor((damage * bonusValues.rankBonusCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
        if (bonusValues.useDarkProtection) {&lt;br /&gt;
          const { darkProtectionPoint, darkProtectionSp } = bonusValues;&lt;br /&gt;
&lt;br /&gt;
          const damageReduction = Math.floor(damage / 3);&lt;br /&gt;
          const spAbsorption = Math.floor(&lt;br /&gt;
            (damageReduction * darkProtectionPoint) / 100&lt;br /&gt;
          );&lt;br /&gt;
&lt;br /&gt;
          if (spAbsorption &amp;lt;= darkProtectionSp) {&lt;br /&gt;
            damage -= damageReduction;&lt;br /&gt;
          } else {&lt;br /&gt;
            damage -= Math.floor(&lt;br /&gt;
              (darkProtectionSp * 100) / darkProtectionPoint&lt;br /&gt;
            );&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        damage -= Math.floor(&lt;br /&gt;
          (damage * bonusValues.resistance90PercentHp) / 100&lt;br /&gt;
        );&lt;br /&gt;
        damage = Math.max(0, damage + bonusValues.defensePercent);&lt;br /&gt;
        damage += Math.min(&lt;br /&gt;
          300,&lt;br /&gt;
          Math.floor((damage * bonusValues.damageBonusCoeff) / 100)&lt;br /&gt;
        );&lt;br /&gt;
        damage = Math.floor((damage * bonusValues.empireMalusCoeff) / 10);&lt;br /&gt;
        damage = Math.floor((damage * bonusValues.sungMaStrBonusCoeff) / 10000);&lt;br /&gt;
        damage -= Math.floor(damage * bonusValues.sungmaStrMalusCoeff);&lt;br /&gt;
        damage = Math.floor(&lt;br /&gt;
          (damage * bonusValues.whiteDragonElixirCoeff) / 100&lt;br /&gt;
        );&lt;br /&gt;
        damage = Math.floor(&lt;br /&gt;
          (damage * bonusValues.steelDragonElixirCoeff) / 100&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        damageByType[criticalIndex + 2 * piercingIndex].push(damage);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveFinalDamage(&lt;br /&gt;
  damage,&lt;br /&gt;
  damageWithPrimaryBonuses,&lt;br /&gt;
  bonusValues,&lt;br /&gt;
  criticalAttackRange,&lt;br /&gt;
  damageByType&lt;br /&gt;
) {&lt;br /&gt;
  damage = Math.floor(damage * bonusValues.magicResistanceCoeff);&lt;br /&gt;
  damage = Math.trunc((damage * bonusValues.weaponDefenseCoeff) / 100);&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.tigerStrengthCoeff) / 100);&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.berserkBonusCoeff) / 100);&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.fearBonusCoeff) / 100);&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.blessingBonusCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  calcFinalDamage(&lt;br /&gt;
    damage,&lt;br /&gt;
    damageWithPrimaryBonuses,&lt;br /&gt;
    bonusValues,&lt;br /&gt;
    criticalAttackRange,&lt;br /&gt;
    damageByType&lt;br /&gt;
  );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveFinalSkillDamage(&lt;br /&gt;
  damage,&lt;br /&gt;
  bonusValues,&lt;br /&gt;
  criticalAttackRange,&lt;br /&gt;
  damageByType&lt;br /&gt;
) {&lt;br /&gt;
  damage = Math.floor(damage * bonusValues.magicResistanceCoeff);&lt;br /&gt;
  damage = Math.trunc((damage * bonusValues.weaponDefenseCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  damage -= bonusValues.defense;&lt;br /&gt;
&lt;br /&gt;
  const damageValues =&lt;br /&gt;
    damage &amp;lt;= 2 &amp;amp;&amp;amp; bonusValues.isPhysicalSkill ? [1, 2, 3, 4, 5] : [damage];&lt;br /&gt;
&lt;br /&gt;
  for (const minDamage of damageValues) {&lt;br /&gt;
    damage = floorMultiplication(minDamage, bonusValues.skillWardCoeff);&lt;br /&gt;
    damage = floorMultiplication(damage, bonusValues.skillBonusCoeff);&lt;br /&gt;
&lt;br /&gt;
    const tempDamage = Math.floor(&lt;br /&gt;
      (damage * bonusValues.skillBonusByBonusCoeff) / 100&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    damage = Math.floor(&lt;br /&gt;
      (tempDamage * bonusValues.magicAttackValueCoeff) / 100 + 0.5&lt;br /&gt;
    );&lt;br /&gt;
    damage = Math.floor((damage * bonusValues.tigerStrengthCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
    calcFinalDamage(&lt;br /&gt;
      damage,&lt;br /&gt;
      tempDamage,&lt;br /&gt;
      bonusValues,&lt;br /&gt;
      criticalAttackRange,&lt;br /&gt;
      damageByType&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function computePolymorphPoint(attacker, victim, polymorphPowerTable) {&lt;br /&gt;
  attacker.polymorphDex = attacker.dex;&lt;br /&gt;
  victim.polymorphDex = victim.dex;&lt;br /&gt;
&lt;br /&gt;
  attacker.minAttackValuePolymorph = 0;&lt;br /&gt;
  attacker.maxAttackValuePolymorph = 0;&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker) &amp;amp;&amp;amp; isPolymorph(attacker)) {&lt;br /&gt;
    var polymorphPowerPct =&lt;br /&gt;
      getPolymorphPower(attacker.polymorphPoint, polymorphPowerTable) / 100;&lt;br /&gt;
    var polymorphMonster = createMonster(&lt;br /&gt;
      attacker.polymorphMonster,&lt;br /&gt;
      null,&lt;br /&gt;
      null,&lt;br /&gt;
      true&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    var polymorphStr = floorMultiplication(&lt;br /&gt;
      polymorphPowerPct,&lt;br /&gt;
      polymorphMonster.str&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    attacker.polymorphDex += floorMultiplication(&lt;br /&gt;
      polymorphPowerPct,&lt;br /&gt;
      polymorphMonster.dex&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    attacker.minAttackValuePolymorph = floorMultiplication(&lt;br /&gt;
      polymorphPowerPct,&lt;br /&gt;
      polymorphMonster.minAttackValue&lt;br /&gt;
    );&lt;br /&gt;
    attacker.maxAttackValuePolymorph = floorMultiplication(&lt;br /&gt;
      polymorphPowerPct,&lt;br /&gt;
      polymorphMonster.maxAttackValue&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    if (!attacker.weapon) {&lt;br /&gt;
      attacker.maxAttackValuePolymorph += 1;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    attacker.attackValue = 0;&lt;br /&gt;
&lt;br /&gt;
    if (isMagicClass(attacker)) {&lt;br /&gt;
      attacker.statAttackValue = 2 * (polymorphStr + attacker.int);&lt;br /&gt;
    } else {&lt;br /&gt;
      attacker.statAttackValue = 2 * (polymorphStr + attacker.str);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function computeHorse(attacker) {&lt;br /&gt;
  attacker.horseAttackValue = 0;&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker) &amp;amp;&amp;amp; isRiding(attacker) &amp;amp;&amp;amp; !isPolymorph(attacker)) {&lt;br /&gt;
    var horseConstant = 30;&lt;br /&gt;
&lt;br /&gt;
    if (attacker.class === &amp;quot;weaponary&amp;quot;) {&lt;br /&gt;
      horseConstant = 60;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    attacker.horseAttackValue = floorMultiplication(&lt;br /&gt;
      2 * attacker.level + attacker.statAttackValue,&lt;br /&gt;
      attacker.horsePoint / horseConstant&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getRankBonus(attacker) {&lt;br /&gt;
  if (!isChecked(attacker.lowRank)) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  switch (attacker.rank) {&lt;br /&gt;
    case &amp;quot;aggressive&amp;quot;:&lt;br /&gt;
      return 1;&lt;br /&gt;
    case &amp;quot;fraudulent&amp;quot;:&lt;br /&gt;
      return 2;&lt;br /&gt;
    case &amp;quot;malicious&amp;quot;:&lt;br /&gt;
      return 3;&lt;br /&gt;
    case &amp;quot;cruel&amp;quot;:&lt;br /&gt;
      return 5;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcElementCoeffPvP(elementBonus, mapping, attacker, victim) {&lt;br /&gt;
  var minElementMalus = 0;&lt;br /&gt;
  var maxDifference = 0;&lt;br /&gt;
  var savedElementDifferences = [];&lt;br /&gt;
  var elementBonusIndex = 0;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; elementBonus.length; index++) {&lt;br /&gt;
    if (!attacker[mapping.elementBonus[index]]) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var elementDifference =&lt;br /&gt;
      attacker[mapping.elementBonus[index]] -&lt;br /&gt;
      victim[mapping.elementResistance[index]];&lt;br /&gt;
&lt;br /&gt;
    if (elementDifference &amp;gt;= 0) {&lt;br /&gt;
      elementBonus[elementBonusIndex] = 10 * elementDifference;&lt;br /&gt;
      minElementMalus -= elementDifference;&lt;br /&gt;
      maxDifference = Math.max(maxDifference, elementDifference);&lt;br /&gt;
      elementBonusIndex++;&lt;br /&gt;
    } else {&lt;br /&gt;
      savedElementDifferences.push(elementDifference);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (!savedElementDifferences.length) {&lt;br /&gt;
    return;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  minElementMalus += maxDifference;&lt;br /&gt;
  savedElementDifferences.sort(compareNumbers);&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; savedElementDifferences.length; index++) {&lt;br /&gt;
    var elementDifference = savedElementDifferences[index];&lt;br /&gt;
&lt;br /&gt;
    elementBonus[elementBonusIndex + index] =&lt;br /&gt;
      10 * Math.max(minElementMalus, elementDifference);&lt;br /&gt;
&lt;br /&gt;
    minElementMalus = Math.min(&lt;br /&gt;
      0,&lt;br /&gt;
      Math.max(minElementMalus, minElementMalus - elementDifference)&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcCriticalHitChance(criticalHitPercentage) {&lt;br /&gt;
  if (criticalHitPercentage &amp;lt;= 9) {&lt;br /&gt;
    return Math.floor((criticalHitPercentage + 5) / 5);&lt;br /&gt;
  }&lt;br /&gt;
  return Math.floor((criticalHitPercentage + 5) / 6);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcCriticalSkillChance(criticalHitPercentage) {&lt;br /&gt;
  if (criticalHitPercentage === 0) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  } else if (criticalHitPercentage &amp;lt;= 9) {&lt;br /&gt;
    return Math.floor((criticalHitPercentage + 7) / 3);&lt;br /&gt;
  }&lt;br /&gt;
  return Math.floor((criticalHitPercentage + 5) / 3);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcPiercingSkillChance(piercingHitPercentage) {&lt;br /&gt;
  if (piercingHitPercentage &amp;lt;= 9) {&lt;br /&gt;
    return Math.floor(piercingHitPercentage / 2);&lt;br /&gt;
  }&lt;br /&gt;
  return 5 + Math.floor((piercingHitPercentage - 10) / 4);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function magicResistanceToCoeff(magicResistance) {&lt;br /&gt;
  if (magicResistance) {&lt;br /&gt;
    return 2000 / (6 * magicResistance + 1000) - 1;&lt;br /&gt;
  }&lt;br /&gt;
  return 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createBattleValues(attacker, victim, battle, skillType) {&lt;br /&gt;
  var {&lt;br /&gt;
    mapping,&lt;br /&gt;
    constants: { polymorphPowerTable, skillPowerTable, marriageTable },&lt;br /&gt;
  } = battle;&lt;br /&gt;
  var calcAttackValues;&lt;br /&gt;
&lt;br /&gt;
  var missPercentage = 0;&lt;br /&gt;
  var attackValueMeleeMagic = 0;&lt;br /&gt;
  var attackValueMarriage = 0;&lt;br /&gt;
  var monsterResistanceMarriage = 0;&lt;br /&gt;
  var monsterResistance = 0;&lt;br /&gt;
  var typeBonus = 0;&lt;br /&gt;
  var raceBonus = 0;&lt;br /&gt;
  var raceResistance = 0;&lt;br /&gt;
  var stoneBonus = 0;&lt;br /&gt;
  var monsterBonus = 0;&lt;br /&gt;
  var elementBonus = [0, 0, 0, 0, 0, 0]; // fire, ice, lightning, earth, darkness, wind, order doesn't matter&lt;br /&gt;
  var defenseMarriage = 0;&lt;br /&gt;
  var damageMultiplier = 1;&lt;br /&gt;
  var useDamage = 1;&lt;br /&gt;
  var defense = victim.defense;&lt;br /&gt;
  var defenseBoost = defense;&lt;br /&gt;
  var magicResistance = 0;&lt;br /&gt;
  var magicPenetration = 0;&lt;br /&gt;
  var weaponDefense = 0;&lt;br /&gt;
  var tigerStrength = 0;&lt;br /&gt;
  var berserkBonus = 0;&lt;br /&gt;
  var blessingBonus = 0;&lt;br /&gt;
  var fearBonus = 0;&lt;br /&gt;
  var magicAttackValueMeleeMagic = 0;&lt;br /&gt;
  var criticalHitPercentage = attacker.criticalHit;&lt;br /&gt;
  var isPlayerVsPlayer = false;&lt;br /&gt;
  var piercingHitPercentage = attacker.piercingHit;&lt;br /&gt;
  var extraPiercingHitPercentage = Math.max(0, piercingHitPercentage - 100);&lt;br /&gt;
  var averageDamage = 0;&lt;br /&gt;
  var averageDamageResistance = 0;&lt;br /&gt;
  var skillDamage = 0;&lt;br /&gt;
  var skillDamageResistance = 0;&lt;br /&gt;
  var rankBonus = 0;&lt;br /&gt;
  var useDarkProtection = false;&lt;br /&gt;
  var darkProtectionPoint = 0;&lt;br /&gt;
  var resistance90PercentHp = 0;&lt;br /&gt;
  var defensePercent = 0;&lt;br /&gt;
  var damageBonus = 0;&lt;br /&gt;
  var empireMalus = 0;&lt;br /&gt;
  var sungMaStrBonus = 0;&lt;br /&gt;
  var sungmaStrMalus = 0;&lt;br /&gt;
  var whiteDragonElixir = 0;&lt;br /&gt;
  var steelDragonElixir = 0;&lt;br /&gt;
&lt;br /&gt;
  attacker.statAttackValue = calcStatAttackValue(attacker);&lt;br /&gt;
&lt;br /&gt;
  computePolymorphPoint(attacker, victim, polymorphPowerTable);&lt;br /&gt;
  computeHorse(attacker);&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker)) {&lt;br /&gt;
    if (weaponData.hasOwnProperty(attacker.weapon)) {&lt;br /&gt;
      attacker.weapon = createWeapon(attacker.weapon);&lt;br /&gt;
    } else {&lt;br /&gt;
      attacker.weapon = createWeapon(0);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    attacker.weapon.getValues(attacker.weaponUpgrade);&lt;br /&gt;
&lt;br /&gt;
    attackValueMeleeMagic =&lt;br /&gt;
      attacker.attackValuePercent + Math.min(100, attacker.attackMeleeMagic);&lt;br /&gt;
&lt;br /&gt;
    var weaponType = attacker.weapon.type;&lt;br /&gt;
&lt;br /&gt;
    if (skillType &amp;amp;&amp;amp; attacker.class === &amp;quot;archery&amp;quot;) {&lt;br /&gt;
      if (weaponType !== 2) {&lt;br /&gt;
        useDamage = 0;&lt;br /&gt;
        weaponType = 2;&lt;br /&gt;
      }&lt;br /&gt;
      defense = 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var weaponDefenseName = mapping.defenseWeapon[weaponType];&lt;br /&gt;
    var weaponDefenseBreakName = mapping.breakWeapon[weaponType];&lt;br /&gt;
&lt;br /&gt;
    if (victim.hasOwnProperty(weaponDefenseName)) {&lt;br /&gt;
      weaponDefense = victim[weaponDefenseName];&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isChecked(attacker.whiteDragonElixir)) {&lt;br /&gt;
      whiteDragonElixir = 10;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    magicPenetration = attacker.magicPenetration;&lt;br /&gt;
&lt;br /&gt;
    if (isPC(victim)) {&lt;br /&gt;
      isPlayerVsPlayer = true;&lt;br /&gt;
&lt;br /&gt;
      if (!skillType) {&lt;br /&gt;
        if (weaponType === 2 &amp;amp;&amp;amp; !isPolymorph(attacker)) {&lt;br /&gt;
          missPercentage = victim.arrowBlock;&lt;br /&gt;
        } else {&lt;br /&gt;
          missPercentage = victim.meleeBlock;&lt;br /&gt;
        }&lt;br /&gt;
        missPercentage +=&lt;br /&gt;
          victim.meleeArrowBlock -&lt;br /&gt;
          (missPercentage * victim.meleeArrowBlock) / 100;&lt;br /&gt;
&lt;br /&gt;
        criticalHitPercentage = calcCriticalHitChance(criticalHitPercentage);&lt;br /&gt;
        berserkBonus = calcBerserkBonus(skillPowerTable, victim);&lt;br /&gt;
        blessingBonus = calcBlessingBonus(skillPowerTable, victim);&lt;br /&gt;
        fearBonus = calcFearBonus(skillPowerTable, victim);&lt;br /&gt;
        averageDamageResistance = victim.averageDamageResistance;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      typeBonus = Math.max(1, attacker.humanBonus - victim.humanResistance);&lt;br /&gt;
      raceBonus = attacker[mapping.raceBonus[victim.race]];&lt;br /&gt;
      raceResistance = victim[mapping.raceResistance[attacker.race]];&lt;br /&gt;
&lt;br /&gt;
      calcElementCoeffPvP(elementBonus, mapping, attacker, victim);&lt;br /&gt;
&lt;br /&gt;
      if (weaponType !== 2 &amp;amp;&amp;amp; attacker.hasOwnProperty(weaponDefenseBreakName)) {&lt;br /&gt;
        weaponDefense -= attacker[weaponDefenseBreakName];&lt;br /&gt;
      }&lt;br /&gt;
    } else {&lt;br /&gt;
      if (isChecked(attacker.isMarried)) {&lt;br /&gt;
        if (isChecked(attacker.loveNecklace)) {&lt;br /&gt;
          attackValueMarriage = getMarriageBonusValue(&lt;br /&gt;
            attacker,&lt;br /&gt;
            marriageTable,&lt;br /&gt;
            &amp;quot;loveNecklace&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isChecked(attacker.loveEarrings)) {&lt;br /&gt;
          criticalHitPercentage += getMarriageBonusValue(&lt;br /&gt;
            attacker,&lt;br /&gt;
            marriageTable,&lt;br /&gt;
            &amp;quot;loveEarrings&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isChecked(attacker.harmonyEarrings)) {&lt;br /&gt;
          piercingHitPercentage += getMarriageBonusValue(&lt;br /&gt;
            attacker,&lt;br /&gt;
            marriageTable,&lt;br /&gt;
            &amp;quot;harmonyEarrings&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (isChecked(attacker.tigerStrength)) {&lt;br /&gt;
        tigerStrength = 40;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      for (var index = 0; index &amp;lt; elementBonus.length; index++) {&lt;br /&gt;
        var elementBonusName = mapping.elementBonus[index];&lt;br /&gt;
        var elementResistanceName = mapping.elementResistance[index];&lt;br /&gt;
&lt;br /&gt;
        if (attacker[elementBonusName] &amp;amp;&amp;amp; victim[elementBonusName]) {&lt;br /&gt;
          elementBonus[index] =&lt;br /&gt;
            50 * (attacker[elementBonusName] - victim[elementResistanceName]);&lt;br /&gt;
        } else {&lt;br /&gt;
          elementBonus[index] = 5 * attacker[elementBonusName];&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      var victimType = victim.type;&lt;br /&gt;
&lt;br /&gt;
      if (victimType !== -1) {&lt;br /&gt;
        typeBonus = attacker[mapping.typeFlag[victimType]];&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      monsterBonus = attacker.monsterBonus;&lt;br /&gt;
&lt;br /&gt;
      if (isStone(victim)) {&lt;br /&gt;
        stoneBonus = attacker.stoneBonus;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (isBoss(victim)) {&lt;br /&gt;
        if (skillType) {&lt;br /&gt;
          skillDamage += attacker.skillBossDamage;&lt;br /&gt;
        } else {&lt;br /&gt;
          averageDamage += attacker.bossDamage;&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (isChecked(attacker.onYohara)) {&lt;br /&gt;
        var sungmaStrDifference = attacker.sungmaStr - attacker.sungmaStrMalus;&lt;br /&gt;
&lt;br /&gt;
        if (sungmaStrDifference &amp;gt;= 0) {&lt;br /&gt;
          sungMaStrBonus = sungmaStrDifference;&lt;br /&gt;
        } else {&lt;br /&gt;
          sungmaStrMalus = 0.5;&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (skillType) {&lt;br /&gt;
      skillDamage += attacker.skillDamage;&lt;br /&gt;
    } else {&lt;br /&gt;
      averageDamage += attacker.averageDamage;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    rankBonus = getRankBonus(attacker);&lt;br /&gt;
    damageBonus = attacker.damageBonus;&lt;br /&gt;
&lt;br /&gt;
    if (isChecked(attacker.empireMalus)) {&lt;br /&gt;
      empireMalus = 1;&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    if (isPC(victim)) {&lt;br /&gt;
      if (isChecked(victim.isMarried)) {&lt;br /&gt;
        if (isChecked(victim.harmonyBracelet)) {&lt;br /&gt;
          monsterResistanceMarriage = getMarriageBonusValue(&lt;br /&gt;
            victim,&lt;br /&gt;
            marriageTable,&lt;br /&gt;
            &amp;quot;harmonyBracelet&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isChecked(victim.harmonyNecklace) &amp;amp;&amp;amp; !skillType) {&lt;br /&gt;
          defenseMarriage = getMarriageBonusValue(&lt;br /&gt;
            victim,&lt;br /&gt;
            marriageTable,&lt;br /&gt;
            &amp;quot;harmonyNecklace&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      monsterResistance = victim.monsterResistance;&lt;br /&gt;
&lt;br /&gt;
      for (var index = 0; index &amp;lt; elementBonus.length; index++) {&lt;br /&gt;
        var elementBonusName = mapping.elementBonus[index];&lt;br /&gt;
        var elementResistanceName = mapping.elementResistance[index];&lt;br /&gt;
&lt;br /&gt;
        if (attacker[elementBonusName]) {&lt;br /&gt;
          elementBonus[index] =&lt;br /&gt;
            80 * (attacker[elementBonusName] - victim[elementResistanceName]);&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (!skillType) {&lt;br /&gt;
        if (isMeleeAttacker(attacker)) {&lt;br /&gt;
          missPercentage = victim.meleeBlock;&lt;br /&gt;
          averageDamageResistance = victim.averageDamageResistance;&lt;br /&gt;
          berserkBonus = calcBerserkBonus(skillPowerTable, victim);&lt;br /&gt;
          blessingBonus = calcBlessingBonus(skillPowerTable, victim);&lt;br /&gt;
          fearBonus = calcFearBonus(skillPowerTable, victim);&lt;br /&gt;
        } else if (isRangeAttacker(attacker)) {&lt;br /&gt;
          missPercentage = victim.arrowBlock;&lt;br /&gt;
          weaponDefense = victim.arrowDefense;&lt;br /&gt;
          averageDamageResistance = victim.averageDamageResistance;&lt;br /&gt;
          berserkBonus = calcBerserkBonus(skillPowerTable, victim);&lt;br /&gt;
          blessingBonus = calcBlessingBonus(skillPowerTable, victim);&lt;br /&gt;
          fearBonus = calcFearBonus(skillPowerTable, victim);&lt;br /&gt;
        } else if (isMagicAttacker(attacker)) {&lt;br /&gt;
          missPercentage = victim.arrowBlock;&lt;br /&gt;
          skillDamageResistance = victim.skillDamageResistance;&lt;br /&gt;
          magicResistance = victim.magicResistance;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        missPercentage +=&lt;br /&gt;
          victim.meleeArrowBlock -&lt;br /&gt;
          (missPercentage * victim.meleeArrowBlock) / 100;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    typeBonus = 1;&lt;br /&gt;
    damageMultiplier = attacker.damageMultiplier;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillType) {&lt;br /&gt;
    criticalHitPercentage = calcCriticalSkillChance(criticalHitPercentage);&lt;br /&gt;
    piercingHitPercentage = calcPiercingSkillChance(piercingHitPercentage);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (isPC(victim)) {&lt;br /&gt;
    if (!skillType &amp;amp;&amp;amp; isChecked(victim.biologist70)) {&lt;br /&gt;
      defenseBoost = Math.floor((defenseBoost * 110) / 100);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    criticalHitPercentage = Math.max(&lt;br /&gt;
      0,&lt;br /&gt;
      criticalHitPercentage - victim.criticalHitResistance&lt;br /&gt;
    );&lt;br /&gt;
    piercingHitPercentage = Math.max(&lt;br /&gt;
      0,&lt;br /&gt;
      piercingHitPercentage - victim.piercingHitResistance&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    if (skillType) {&lt;br /&gt;
      skillDamageResistance = victim.skillDamageResistance;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      victim.useDarkProtection &amp;amp;&amp;amp;&lt;br /&gt;
      victim.class === &amp;quot;black_magic&amp;quot; &amp;amp;&amp;amp;&lt;br /&gt;
      victim.skillDarkProtection&lt;br /&gt;
    ) {&lt;br /&gt;
      useDarkProtection = true;&lt;br /&gt;
      darkProtectionPoint = calcDarkProtectionPoint(skillPowerTable, victim);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    resistance90PercentHp = victim.resistance90PercentHp || 0;&lt;br /&gt;
&lt;br /&gt;
    if (isMagicClass(victim)) {&lt;br /&gt;
      defensePercent = (-2 * victim.magicDefense * victim.defensePercent) / 100;&lt;br /&gt;
    } else {&lt;br /&gt;
      defensePercent = (-2 * defenseBoost * victim.defensePercent) / 100;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isChecked(victim.steelDragonElixir)) {&lt;br /&gt;
      steelDragonElixir = 10;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillType === &amp;quot;magic&amp;quot;) {&lt;br /&gt;
    attackValueMeleeMagic = 0;&lt;br /&gt;
    magicAttackValueMeleeMagic =&lt;br /&gt;
      attacker.attackMagic + Math.min(100, attacker.attackMeleeMagic);&lt;br /&gt;
    attackValueMarriage = 0;&lt;br /&gt;
    defense = 0;&lt;br /&gt;
    magicResistance = victim.magicResistance;&lt;br /&gt;
&lt;br /&gt;
    if (magicResistance &amp;gt; 0 &amp;amp;&amp;amp; magicPenetration) {&lt;br /&gt;
      magicResistance = Math.floor(&lt;br /&gt;
        magicResistance * (1 - magicPenetration / 120) + 0.5&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    weaponDefense = 0;&lt;br /&gt;
    calcAttackValues = calcMagicAttackValue;&lt;br /&gt;
&lt;br /&gt;
    if (isDispell(attacker, 6)) {&lt;br /&gt;
      typeBonus = 0;&lt;br /&gt;
      raceBonus = 0;&lt;br /&gt;
      raceResistance = 0;&lt;br /&gt;
      stoneBonus = 0;&lt;br /&gt;
      monsterBonus = 0;&lt;br /&gt;
      for (var index = 0; index &amp;lt; elementBonus.length; index++) {&lt;br /&gt;
        elementBonus[index] = 0;&lt;br /&gt;
      }&lt;br /&gt;
      magicResistance = 0;&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    calcAttackValues = calcSecondaryAttackValue;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  missPercentage = Math.min(100, missPercentage);&lt;br /&gt;
  criticalHitPercentage = Math.min(criticalHitPercentage, 100);&lt;br /&gt;
  piercingHitPercentage = Math.min(piercingHitPercentage, 100);&lt;br /&gt;
&lt;br /&gt;
  const bonusValues = {&lt;br /&gt;
    missPercentage: missPercentage,&lt;br /&gt;
    skipCriticalStep: [&lt;br /&gt;
      !Boolean(100 - criticalHitPercentage),&lt;br /&gt;
      !Boolean(criticalHitPercentage),&lt;br /&gt;
    ],&lt;br /&gt;
    skipPiercingStep: [&lt;br /&gt;
      !Boolean(100 - piercingHitPercentage),&lt;br /&gt;
      !Boolean(piercingHitPercentage),&lt;br /&gt;
    ],&lt;br /&gt;
    isPhysicalSkill: skillType === &amp;quot;physical&amp;quot; &amp;amp;&amp;amp; attacker.class !== &amp;quot;archery&amp;quot;,&lt;br /&gt;
    weaponBonusCoeff: 1,&lt;br /&gt;
    attackValueCoeff: 100 + attackValueMeleeMagic,&lt;br /&gt;
    attackValueMarriage: attackValueMarriage,&lt;br /&gt;
    monsterResistanceMarriageCoeff: 100 - monsterResistanceMarriage,&lt;br /&gt;
    monsterResistanceCoeff: 100 - monsterResistance,&lt;br /&gt;
    typeBonusCoeff: typeBonus,&lt;br /&gt;
    raceBonusCoeff: raceBonus,&lt;br /&gt;
    raceResistanceCoeff: raceResistance,&lt;br /&gt;
    stoneBonusCoeff: stoneBonus,&lt;br /&gt;
    monsterBonusCoeff: monsterBonus,&lt;br /&gt;
    elementBonusCoeff: elementBonus,&lt;br /&gt;
    damageMultiplier: damageMultiplier,&lt;br /&gt;
    useDamage: useDamage,&lt;br /&gt;
    defense: defense,&lt;br /&gt;
    defenseBoost: defenseBoost,&lt;br /&gt;
    defenseMarriage: defenseMarriage,&lt;br /&gt;
    tigerStrengthCoeff: 100 + tigerStrength,&lt;br /&gt;
    magicResistanceCoeff: magicResistanceToCoeff(magicResistance),&lt;br /&gt;
    weaponDefenseCoeff: 100 - weaponDefense,&lt;br /&gt;
    berserkBonusCoeff: 100 + berserkBonus,&lt;br /&gt;
    blessingBonusCoeff: 100 - blessingBonus,&lt;br /&gt;
    fearBonusCoeff: 100 - fearBonus,&lt;br /&gt;
    magicAttackValueCoeff: 100 + magicAttackValueMeleeMagic,&lt;br /&gt;
    extraPiercingHitCoeff: 5 * extraPiercingHitPercentage,&lt;br /&gt;
    averageDamageCoeff: 100 + averageDamage,&lt;br /&gt;
    averageDamageResistanceCoeff: 100 - Math.min(99, averageDamageResistance),&lt;br /&gt;
    skillDamageCoeff: 100 + skillDamage,&lt;br /&gt;
    skillDamageResistanceCoeff: 100 - Math.min(99, skillDamageResistance),&lt;br /&gt;
    useDarkProtection: useDarkProtection,&lt;br /&gt;
    darkProtectionPoint: darkProtectionPoint,&lt;br /&gt;
    darkProtectionSp: victim.darkProtectionSp,&lt;br /&gt;
    rankBonusCoeff: 100 + rankBonus,&lt;br /&gt;
    resistance90PercentHp: resistance90PercentHp,&lt;br /&gt;
    defensePercent: Math.floor(defensePercent),&lt;br /&gt;
    damageBonusCoeff: Math.min(20, damageBonus),&lt;br /&gt;
    empireMalusCoeff: 10 - empireMalus,&lt;br /&gt;
    sungMaStrBonusCoeff: 10000 + sungMaStrBonus,&lt;br /&gt;
    sungmaStrMalusCoeff: sungmaStrMalus,&lt;br /&gt;
    whiteDragonElixirCoeff: 100 + whiteDragonElixir,&lt;br /&gt;
    steelDragonElixirCoeff: 100 - steelDragonElixir,&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  const damageTypeWeights = [&lt;br /&gt;
    (100 - criticalHitPercentage) *&lt;br /&gt;
      (100 - piercingHitPercentage) *&lt;br /&gt;
      (100 - missPercentage),&lt;br /&gt;
    criticalHitPercentage *&lt;br /&gt;
      (100 - piercingHitPercentage) *&lt;br /&gt;
      (100 - missPercentage),&lt;br /&gt;
    (100 - criticalHitPercentage) *&lt;br /&gt;
      piercingHitPercentage *&lt;br /&gt;
      (100 - missPercentage),&lt;br /&gt;
    criticalHitPercentage * piercingHitPercentage * (100 - missPercentage),&lt;br /&gt;
  ];&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    attacker: attacker,&lt;br /&gt;
    victim: victim,&lt;br /&gt;
    attackFactor: calcAttackFactor(attacker, victim),&lt;br /&gt;
    mainAttackValue: calcMainAttackValue(attacker),&lt;br /&gt;
    attackValues: calcAttackValues(attacker, isPlayerVsPlayer),&lt;br /&gt;
    bonusValues: bonusValues,&lt;br /&gt;
    damageTypeWeights: damageTypeWeights,&lt;br /&gt;
    attackTypeMapping: mapping.attackType,&lt;br /&gt;
    damageWeightedByType: {&lt;br /&gt;
      normalHit: {},&lt;br /&gt;
      criticalHit: {},&lt;br /&gt;
      piercingHit: {},&lt;br /&gt;
      criticalPiercingHit: {},&lt;br /&gt;
    },&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateBattleValues(battleValues, skillFormula, skillInfo) {&lt;br /&gt;
  var weaponBonus = skillInfo.adjust || 0;&lt;br /&gt;
  var skillWard = 0;&lt;br /&gt;
  var skillBonus = 0;&lt;br /&gt;
  var skillBonusByBonus = 0;&lt;br /&gt;
  var { attacker: attacker, bonusValues: bonusValues } = battleValues;&lt;br /&gt;
  var {&lt;br /&gt;
    range: [minVariation, maxVariation],&lt;br /&gt;
  } = skillInfo;&lt;br /&gt;
  var variationLength = maxVariation - minVariation + 1;&lt;br /&gt;
&lt;br /&gt;
  if (skillInfo.hasOwnProperty(&amp;quot;weaponBonus&amp;quot;)) {&lt;br /&gt;
    var [weaponType, weaponBonusValue] = skillInfo.weaponBonus;&lt;br /&gt;
&lt;br /&gt;
    if (weaponType === attacker.weapon.type) {&lt;br /&gt;
      weaponBonus += weaponBonusValue;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillInfo.skillBonus) {&lt;br /&gt;
    skillBonus = skillInfo.skillBonus;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillInfo.skillWard) {&lt;br /&gt;
    skillWard = skillInfo.skillWard;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillInfo.skillBonusByBonus) {&lt;br /&gt;
    skillBonusByBonus = skillInfo.skillBonusByBonus;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillInfo.removeWeaponReduction) {&lt;br /&gt;
    bonusValues.weaponDefenseCoeff = 100;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  bonusValues.weaponBonusCoeff = 100 + weaponBonus;&lt;br /&gt;
  bonusValues.skillWardCoeff = 1 - skillWard / 100;&lt;br /&gt;
  bonusValues.skillBonusCoeff = 1 + skillBonus / 100;&lt;br /&gt;
  bonusValues.skillBonusByBonusCoeff = 100 + skillBonusByBonus;&lt;br /&gt;
&lt;br /&gt;
  battleValues.skillFormula = skillFormula;&lt;br /&gt;
  battleValues.skillRange = skillInfo.range;&lt;br /&gt;
  battleValues.attackValues.totalCardinal *= variationLength;&lt;br /&gt;
  battleValues.attackValues.possibleDamageCount *= variationLength;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcWeights(minValue, maxValue, minInterval) {&lt;br /&gt;
  var firstWeightLimit = minValue + minInterval - 1;&lt;br /&gt;
  var lastWeightsLimit = maxValue - minInterval + 1;&lt;br /&gt;
  var weights = [];&lt;br /&gt;
&lt;br /&gt;
  for (var value = minValue; value &amp;lt; firstWeightLimit; value++) {&lt;br /&gt;
    weights.push(value - minValue + 1);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (var value = firstWeightLimit; value &amp;lt;= lastWeightsLimit; value++) {&lt;br /&gt;
    weights.push(minInterval);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (var value = lastWeightsLimit + 1; value &amp;lt;= maxValue; value++) {&lt;br /&gt;
    weights.push(maxValue - value + 1);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return weights;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcBerserkBonus(skillPowerTable, victim) {&lt;br /&gt;
  if (!isChecked(victim.useBerserk) || victim.class !== &amp;quot;body&amp;quot;) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  const skillPower = getSkillPower(victim.skillBerserk, skillPowerTable);&lt;br /&gt;
&lt;br /&gt;
  if (!skillPower) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  const berserkBonus = Math.floor(skillPower * 25);&lt;br /&gt;
&lt;br /&gt;
  return berserkBonus;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcBlessingBonus(skillPowerTable, victim) {&lt;br /&gt;
  if (!isChecked(victim.isBlessed)) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  const int = victim.intBlessing;&lt;br /&gt;
  const dex = victim.dexBlessing;&lt;br /&gt;
  const skillPower = getSkillPower(victim.skillBlessing, skillPowerTable);&lt;br /&gt;
&lt;br /&gt;
  if (!skillPower) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  let blessingBonus = floorMultiplication(&lt;br /&gt;
    ((int * 0.3 + 5) * (2 * skillPower + 0.5) + 0.3 * dex) / (skillPower + 2.3),&lt;br /&gt;
    1&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  if (victim.class === &amp;quot;dragon&amp;quot; &amp;amp;&amp;amp; isChecked(victim.blessingOnself)) {&lt;br /&gt;
    blessingBonus = floorMultiplication(blessingBonus, 1.1);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return blessingBonus;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcFearBonus(skillPowerTable, victim) {&lt;br /&gt;
  if (!isChecked(victim.useFear) || victim.class !== &amp;quot;weaponary&amp;quot;) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  const skillPower = getSkillPower(victim.skillFear, skillPowerTable);&lt;br /&gt;
&lt;br /&gt;
  if (!skillPower) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  const fearBonus = 5 + Math.floor(skillPower * 20);&lt;br /&gt;
&lt;br /&gt;
  return fearBonus;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcDarkProtectionPoint(skillPowerTable, victim) {&lt;br /&gt;
  const skillPower = getSkillPower(victim.skillDarkProtection, skillPowerTable);&lt;br /&gt;
&lt;br /&gt;
  return floorMultiplication(100 - victim.int * 0.84 * skillPower, 1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcStealthBonus(skillPowerTable, attacker) {&lt;br /&gt;
  if (!isChecked(attacker.useStealth)) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  const skillPower = getSkillPower(attacker.skillStealth, skillPowerTable);&lt;br /&gt;
&lt;br /&gt;
  if (!skillPower) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  const stealthBonus = skillPower * 50;&lt;br /&gt;
&lt;br /&gt;
  return stealthBonus;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSkillFormula(battle, skillId, battleValues, removeSkillVariation) {&lt;br /&gt;
  var { attacker, victim, attackFactor } = battleValues;&lt;br /&gt;
  var skillPowerTable = battle.constants.skillPowerTable;&lt;br /&gt;
&lt;br /&gt;
  var skillFormula;&lt;br /&gt;
  var skillInfo = { range: [0, 0] };&lt;br /&gt;
&lt;br /&gt;
  var { class: attackerClass, level: lv, vit, str, int, dex } = attacker;&lt;br /&gt;
&lt;br /&gt;
  if (skillId &amp;lt;= 9) {&lt;br /&gt;
    var skillPower = getSkillPower(&lt;br /&gt;
      attacker[&amp;quot;attackSkill&amp;quot; + skillId],&lt;br /&gt;
      skillPowerTable&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    var improvedBySkillBonus = false;&lt;br /&gt;
    var improvedByBonus = false;&lt;br /&gt;
&lt;br /&gt;
    if (attackerClass === &amp;quot;body&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Triple lacération&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.1 * atk + (0.5 * atk + 1.5 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Moulinet à l'épée&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              3 * atk + (0.8 * atk + 5 * str + 3 * dex + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Accélération&lt;br /&gt;
        case 5:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * atk + (atk + dex * 3 + str * 7 + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Volonté de vivre&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              (3 * atk + (atk + 1.5 * str) * skillPower) * 1.07,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          break;&lt;br /&gt;
        // Tremblement de terre&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              3 * atk +&lt;br /&gt;
                (0.9 * atk + variation + 5 * str + 3 * dex + lv) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;mental&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Attaque de l'esprit&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2.3 * atk + (4 * atk + 4 * str + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Attaque de la paume&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2.3 * atk + (3 * atk + 4 * str + 3 * vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Charge&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * atk + (2 * atk + 2 * dex + 2 * vit + 4 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          break;&lt;br /&gt;
        // Coup d'épée&lt;br /&gt;
        case 5:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * atk + (atk + 3 * dex + 5 * str + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Orbe de l'épée&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              (2 * atk + (2 * atk + 2 * dex + 2 * vit + 4 * str) * skillPower) *&lt;br /&gt;
                1.1,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          break;&lt;br /&gt;
        // Tremblement de terre&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              3 * atk +&lt;br /&gt;
                (0.9 * atk + variation + 5 * str + 3 * dex + lv) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;blade_fight&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Embuscade&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk + (1.2 * atk + variation + 4 * dex + 4 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [1, 50];&lt;br /&gt;
          skillInfo.range = [500, 700];&lt;br /&gt;
          skillInfo.adjust = calcStealthBonus(skillPowerTable, attacker);&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Attaque rapide&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk + (1.6 * atk + variation + 7 * dex + 7 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [1, 35];&lt;br /&gt;
          skillInfo.range = [200, 300];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Dague filante&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * atk + (0.5 * atk + 9 * dex + 7 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Brume empoisonnée&lt;br /&gt;
        case 5:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * lv + (atk + 3 * str + 18 * dex) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Poison insidieux&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              (2 * lv + (atk + 3 * str + 18 * dex) * skillPower) * 1.1,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          break;&lt;br /&gt;
        // Étoiles brillantes&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk + (1.7 * atk + variation + 6 * dex + 5 * lv) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;archery&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Tir à répétition&lt;br /&gt;
        // case 1:&lt;br /&gt;
        //   skillFormula = function (atk) {&lt;br /&gt;
        //     return floorMultiplication(&lt;br /&gt;
        //       atk + 0.2 * atk * Math.floor(2 + 6 * skillPower) + (0.8 * atk + 8 * dex * attackFactor + 2 * int) * skillPower,&lt;br /&gt;
        //       1&lt;br /&gt;
        //     );&lt;br /&gt;
        //   };&lt;br /&gt;
        //   improvedByBonus = true;&lt;br /&gt;
        //   break;&lt;br /&gt;
        // Pluie de flèches&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk + (1.7 * atk + 5 * dex + str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Flèche de feu&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.5 * atk + (2.6 * atk + 0.9 * int + variation) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [100, 300];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Foulée de plume&lt;br /&gt;
        case 4:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              (3 * dex + 200 + 2 * str + 2 * int) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.removeWeaponReduction = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Flèche empoisonnée&lt;br /&gt;
        case 5:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk +&lt;br /&gt;
                (1.4 * atk + variation + 7 * dex + 4 * str + 4 * int) *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [100, 200];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Coup étincelant&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              (atk +&lt;br /&gt;
                (1.2 * atk + variation + 6 * dex + 3 * str + 3 * int) *&lt;br /&gt;
                  skillPower) *&lt;br /&gt;
                1.2,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [100, 200];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Tir tempête&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.9 * atk + (2.6 * atk + variation) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;weaponary&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Toucher brûlant&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk +&lt;br /&gt;
                2 * lv +&lt;br /&gt;
                2 * int +&lt;br /&gt;
                (2 * atk + 4 * str + 14 * int) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Tourbillon du dragon&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.1 * atk +&lt;br /&gt;
                2 * lv +&lt;br /&gt;
                2 * int +&lt;br /&gt;
                (1.5 * atk + str + 12 * int) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Contre-sort&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              40 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                2 * int +&lt;br /&gt;
                (10 * int + 7 * mav + variation) * attackFactor * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [50, 100];&lt;br /&gt;
          break;&lt;br /&gt;
        // Coup démoniaque&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.9 * atk + (2.6 * atk + variation) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;black_magic&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Attaque des ténèbres&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              40 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                2 * int +&lt;br /&gt;
                (13 * int + 6 * mav + variation) * attackFactor * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [50, 100];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Attaque de flammes&lt;br /&gt;
        // case 2:&lt;br /&gt;
        //   skillFormula = function (mav, variation) {&lt;br /&gt;
        //     return floorMultiplication(&lt;br /&gt;
        //       5 * lv + 2 * int + (7 * int + 8 * mav + 4 * str + 2 * vit + variation) * skillPower,&lt;br /&gt;
        //       1&lt;br /&gt;
        //     );&lt;br /&gt;
        //   };&lt;br /&gt;
        //   skillInfo.range = [180, 100];&lt;br /&gt;
        //   improvedByBonus = true;&lt;br /&gt;
        //   break;&lt;br /&gt;
        // Esprit de flammes&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              30 +&lt;br /&gt;
                2 * lv +&lt;br /&gt;
                2 * int +&lt;br /&gt;
                (7 * int + 6 * mav + variation) * attackFactor * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [200, 500];&lt;br /&gt;
          break;&lt;br /&gt;
        // Frappe de l'esprit&lt;br /&gt;
        // case 5:&lt;br /&gt;
        //   skillFormula = function (mav, variation) {&lt;br /&gt;
        //     return floorMultiplication(&lt;br /&gt;
        //       40 + 2 * lv + 2 * int + (2 * vit + 2 * dex + 13 * int + 6 * mav + variation) * attackFactor * skillPower,&lt;br /&gt;
        //       1&lt;br /&gt;
        //     );&lt;br /&gt;
        //   };&lt;br /&gt;
        //   skillInfo.range = [180, 200];&lt;br /&gt;
        //   break;&lt;br /&gt;
        // Orbe des ténèbres&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (mav) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              120 +&lt;br /&gt;
                6 * lv +&lt;br /&gt;
                (5 * vit + 5 * dex + 29 * int + 9 * mav) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Vague mortelle&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              120 +&lt;br /&gt;
                6 * lv +&lt;br /&gt;
                (5 * vit + 5 * dex + 30 * int + variation + 9 * mav) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;dragon&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Talisman volant&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (mav) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              70 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                (18 * int + 7 * str + 5 * mav + 50) * attackFactor * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [4, 10];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Dragon chassant&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (mav) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              60 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                (16 * int + 6 * dex + 6 * mav + 120) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [4, 10];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Rugissement du dragon&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (mav) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              70 +&lt;br /&gt;
                3 * lv +&lt;br /&gt;
                (20 * int + 3 * str + 10 * mav + 100) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [4, 10];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Météore&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              120 +&lt;br /&gt;
                6 * lv +&lt;br /&gt;
                (5 * vit + 5 * dex + 30 * int + variation + 9 * mav) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;heal&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Jet de foudre&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              60 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                (8 * int + 2 * dex + 8 * mav + variation) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [6, 10];&lt;br /&gt;
          skillInfo.range = [5 * int, 15 * int];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Invocation de foudre&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              40 +&lt;br /&gt;
                4 * lv +&lt;br /&gt;
                (13 * int + 2 * str + 10 * mav + variation) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [6, 10];&lt;br /&gt;
          skillInfo.range = [5 * int, 16 * int];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Griffe de foudre&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              50 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                (8 * int + 2 * str + 8 * mav + variation) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 800];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;lycan&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Déchiqueter&lt;br /&gt;
        // case 1:&lt;br /&gt;
        //   skillFormula = function (atk) {&lt;br /&gt;
        //     return floorMultiplication(&lt;br /&gt;
        //       1.1 * atk + (0.3 * atk + 1.5 * str) * skillPower,&lt;br /&gt;
        //       1&lt;br /&gt;
        //     );&lt;br /&gt;
        //   };&lt;br /&gt;
        //   skillInfo.weaponBonus = [5, 54];&lt;br /&gt;
        //   improvedByBonus = true;&lt;br /&gt;
        //   break;&lt;br /&gt;
        // Souffle de loup&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * atk + (atk + 3 * dex + 5 * str + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [5, 35];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Bond de loup&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk + (1.6 * atk + 200 + 7 * dex + 7 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [5, 35];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Griffe de loup&lt;br /&gt;
        case 4:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              3 * atk + (0.8 * atk + 6 * str + 2 * dex + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Tempête cinglante&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.8 * atk +&lt;br /&gt;
                (atk + 6 * dex + variation + 3 * str + lv) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
    if (improvedBySkillBonus) {&lt;br /&gt;
      skillInfo.skillBonus =&lt;br /&gt;
        16 * getSkillPower(attacker.skillBonus, skillPowerTable);&lt;br /&gt;
&lt;br /&gt;
      var skillWardChoice = victim.skillWardChoice;&lt;br /&gt;
&lt;br /&gt;
      if (skillWardChoice &amp;amp;&amp;amp; skillWardChoice === attackerClass) {&lt;br /&gt;
        skillInfo.skillWard =&lt;br /&gt;
          24 * getSkillPower(victim.skillWard, skillPowerTable);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (improvedByBonus) {&lt;br /&gt;
      skillInfo.skillBonusByBonus = attacker[&amp;quot;skillBonus&amp;quot; + skillId];&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (removeSkillVariation) {&lt;br /&gt;
      var averageVariation = (skillInfo.range[0] + skillInfo.range[0]) / 2;&lt;br /&gt;
      skillInfo.range = [averageVariation, averageVariation];&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    var skillPower = getSkillPower(&lt;br /&gt;
      attacker[&amp;quot;horseSkill&amp;quot; + skillId],&lt;br /&gt;
      skillPowerTable&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    switch (skillId) {&lt;br /&gt;
      // Combat équestre&lt;br /&gt;
      case 137:&lt;br /&gt;
        skillFormula = function (atk) {&lt;br /&gt;
          return floorMultiplication(atk + 2 * atk * skillPower, 1);&lt;br /&gt;
        };&lt;br /&gt;
        break;&lt;br /&gt;
      // Charge à cheval&lt;br /&gt;
      case 138:&lt;br /&gt;
        skillFormula = function (atk) {&lt;br /&gt;
          return floorMultiplication(&lt;br /&gt;
            2.4 * (200 + 1.5 * lv) + 600 * skillPower,&lt;br /&gt;
            1&lt;br /&gt;
          );&lt;br /&gt;
        };&lt;br /&gt;
        break;&lt;br /&gt;
      // Vague de Pouvoir&lt;br /&gt;
      case 139:&lt;br /&gt;
        skillFormula = function (atk) {&lt;br /&gt;
          return floorMultiplication(&lt;br /&gt;
            2 * (200 + 1.5 * lv) + 600 * skillPower,&lt;br /&gt;
            1&lt;br /&gt;
          );&lt;br /&gt;
        };&lt;br /&gt;
        break;&lt;br /&gt;
      // Grêle de flèches&lt;br /&gt;
      case 140:&lt;br /&gt;
        skillFormula = function (atk) {&lt;br /&gt;
          return floorMultiplication(atk + 2 * atk * skillPower, 1);&lt;br /&gt;
        };&lt;br /&gt;
        break;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  updateBattleValues(battleValues, skillFormula, skillInfo);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcMagicAttackValueAugmentation(&lt;br /&gt;
  magicAttackValueWeapon,&lt;br /&gt;
  magicAttackValueBonus&lt;br /&gt;
) {&lt;br /&gt;
  if (magicAttackValueBonus) {&lt;br /&gt;
    return Math.max(&lt;br /&gt;
      1,&lt;br /&gt;
      0.0025056 *&lt;br /&gt;
        magicAttackValueBonus ** 0.602338 *&lt;br /&gt;
        magicAttackValueWeapon ** 1.20476&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
  return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getMagicAttackValueAugmentation(&lt;br /&gt;
  minMagicAttackValue,&lt;br /&gt;
  maxMagicAttackValue,&lt;br /&gt;
  magicAttackValueBonus&lt;br /&gt;
) {&lt;br /&gt;
  var magicAttackValueAugmentation = [];&lt;br /&gt;
&lt;br /&gt;
  for (&lt;br /&gt;
    var magicAttackValue = minMagicAttackValue;&lt;br /&gt;
    magicAttackValue &amp;lt;= maxMagicAttackValue;&lt;br /&gt;
    magicAttackValue++&lt;br /&gt;
  ) {&lt;br /&gt;
    magicAttackValueAugmentation.push(&lt;br /&gt;
      calcMagicAttackValueAugmentation(magicAttackValue, magicAttackValueBonus)&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return magicAttackValueAugmentation;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcPhysicalDamage(battleValues) {&lt;br /&gt;
  const {&lt;br /&gt;
    attackFactor,&lt;br /&gt;
    mainAttackValue,&lt;br /&gt;
    attackValues: {&lt;br /&gt;
      minAttackValue,&lt;br /&gt;
      maxAttackValue,&lt;br /&gt;
      attackValueOther,&lt;br /&gt;
      weights,&lt;br /&gt;
      criticalAttackRange,&lt;br /&gt;
    },&lt;br /&gt;
    bonusValues,&lt;br /&gt;
    damageWeightedByType,&lt;br /&gt;
  } = battleValues;&lt;br /&gt;
&lt;br /&gt;
  const savedDamage = {};&lt;br /&gt;
&lt;br /&gt;
  if (bonusValues.missPercentage) {&lt;br /&gt;
    damageWeightedByType.miss = bonusValues.missPercentage / 100;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (&lt;br /&gt;
    let attackValue = minAttackValue;&lt;br /&gt;
    attackValue &amp;lt;= maxAttackValue;&lt;br /&gt;
    attackValue++&lt;br /&gt;
  ) {&lt;br /&gt;
    const weight = weights[attackValue - minAttackValue];&lt;br /&gt;
    const damageByType = [[], [], [], []];&lt;br /&gt;
    const currentDamageInfo = [weight, damageByType];&lt;br /&gt;
&lt;br /&gt;
    const secondaryAttackValue = 2 * attackValue + attackValueOther;&lt;br /&gt;
    const rawDamage =&lt;br /&gt;
      mainAttackValue + floorMultiplication(attackFactor, secondaryAttackValue);&lt;br /&gt;
&lt;br /&gt;
    const damageWithPrimaryBonuses = calcDamageWithPrimaryBonuses(&lt;br /&gt;
      rawDamage,&lt;br /&gt;
      bonusValues&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    const damageAfterDefense =&lt;br /&gt;
      damageWithPrimaryBonuses -&lt;br /&gt;
      bonusValues.defenseBoost -&lt;br /&gt;
      bonusValues.defenseMarriage;&lt;br /&gt;
&lt;br /&gt;
    const damageValues =&lt;br /&gt;
      damageAfterDefense &amp;lt;= 2 ? [1, 2, 3, 4, 5] : [damageAfterDefense];&lt;br /&gt;
&lt;br /&gt;
    for (const damage of damageValues) {&lt;br /&gt;
      saveFinalDamage(&lt;br /&gt;
        damage,&lt;br /&gt;
        damageWithPrimaryBonuses,&lt;br /&gt;
        bonusValues,&lt;br /&gt;
        criticalAttackRange,&lt;br /&gt;
        damageByType&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    savedDamage[attackValue] = currentDamageInfo;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  processSavedDamage(savedDamage, damageWeightedByType, battleValues);&lt;br /&gt;
&lt;br /&gt;
  return damageWeightedByType;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcPhysicalSkillDamage(battleValues) {&lt;br /&gt;
  const {&lt;br /&gt;
    attackFactor,&lt;br /&gt;
    mainAttackValue,&lt;br /&gt;
    attackValues: {&lt;br /&gt;
      minAttackValue,&lt;br /&gt;
      maxAttackValue,&lt;br /&gt;
      attackValueOther,&lt;br /&gt;
      weights,&lt;br /&gt;
      criticalAttackRange,&lt;br /&gt;
    },&lt;br /&gt;
    bonusValues,&lt;br /&gt;
    damageWeightedByType,&lt;br /&gt;
    skillFormula,&lt;br /&gt;
    skillRange: [minVariation, maxVariation],&lt;br /&gt;
  } = battleValues;&lt;br /&gt;
&lt;br /&gt;
  const savedDamage = {};&lt;br /&gt;
&lt;br /&gt;
  for (&lt;br /&gt;
    let attackValue = minAttackValue;&lt;br /&gt;
    attackValue &amp;lt;= maxAttackValue;&lt;br /&gt;
    attackValue++&lt;br /&gt;
  ) {&lt;br /&gt;
    const weight = weights[attackValue - minAttackValue];&lt;br /&gt;
&lt;br /&gt;
    const secondaryAttackValue = 2 * attackValue + attackValueOther;&lt;br /&gt;
    const rawDamage =&lt;br /&gt;
      mainAttackValue + floorMultiplication(attackFactor, secondaryAttackValue);&lt;br /&gt;
&lt;br /&gt;
    const damageWithPrimaryBonuses = calcDamageWithPrimaryBonuses(&lt;br /&gt;
      rawDamage,&lt;br /&gt;
      bonusValues&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    const damageValues =&lt;br /&gt;
      damageWithPrimaryBonuses &amp;lt;= 2&lt;br /&gt;
        ? [1, 2, 3, 4, 5]&lt;br /&gt;
        : [damageWithPrimaryBonuses];&lt;br /&gt;
    const weightByDamage = weight / damageValues.length;&lt;br /&gt;
&lt;br /&gt;
    for (let variation = minVariation; variation &amp;lt;= maxVariation; variation++) {&lt;br /&gt;
      for (const damage of damageValues) {&lt;br /&gt;
        const damageWithFormula = skillFormula(&lt;br /&gt;
          damage * bonusValues.useDamage,&lt;br /&gt;
          variation&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        let damageKey = damageWithFormula;&lt;br /&gt;
&lt;br /&gt;
        if (damageWithPrimaryBonuses &amp;lt; bonusValues.defenseBoost) {&lt;br /&gt;
          damageKey = `${damageWithFormula}_${damageWithPrimaryBonuses}`;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        const entry = savedDamage[damageKey];&lt;br /&gt;
&lt;br /&gt;
        if (entry) {&lt;br /&gt;
          entry[0] += weightByDamage;&lt;br /&gt;
          continue;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        const damageByType = [[], [], [], []];&lt;br /&gt;
        const currentDamageInfo = [weightByDamage, damageByType];&lt;br /&gt;
&lt;br /&gt;
        const finalDamage = Math.floor(&lt;br /&gt;
          (damageWithFormula * bonusValues.weaponBonusCoeff) / 100&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        saveFinalSkillDamage(&lt;br /&gt;
          finalDamage,&lt;br /&gt;
          bonusValues,&lt;br /&gt;
          criticalAttackRange,&lt;br /&gt;
          damageByType&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        savedDamage[damageKey] = currentDamageInfo;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  processSavedDamage(savedDamage, damageWeightedByType, battleValues);&lt;br /&gt;
&lt;br /&gt;
  return damageWeightedByType;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcMagicSkillDamage(battleValues) {&lt;br /&gt;
  const {&lt;br /&gt;
    attackValues: {&lt;br /&gt;
      minMagicAttackValue,&lt;br /&gt;
      maxMagicAttackValue,&lt;br /&gt;
      magicAttackValueAugmentation,&lt;br /&gt;
      weights,&lt;br /&gt;
      criticalAttackRange,&lt;br /&gt;
    },&lt;br /&gt;
    bonusValues,&lt;br /&gt;
    damageWeightedByType,&lt;br /&gt;
    skillFormula,&lt;br /&gt;
    skillRange: [minVariation, maxVariation],&lt;br /&gt;
  } = battleValues;&lt;br /&gt;
&lt;br /&gt;
  const savedDamage = {};&lt;br /&gt;
&lt;br /&gt;
  for (&lt;br /&gt;
    let magicAttackValue = minMagicAttackValue;&lt;br /&gt;
    magicAttackValue &amp;lt;= maxMagicAttackValue;&lt;br /&gt;
    magicAttackValue++&lt;br /&gt;
  ) {&lt;br /&gt;
    const index = magicAttackValue - minMagicAttackValue;&lt;br /&gt;
    const weight = weights[index];&lt;br /&gt;
&lt;br /&gt;
    for (let variation = minVariation; variation &amp;lt;= maxVariation; variation++) {&lt;br /&gt;
      const rawDamage = skillFormula(&lt;br /&gt;
        magicAttackValue + magicAttackValueAugmentation[index],&lt;br /&gt;
        variation&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      const entry = savedDamage[rawDamage];&lt;br /&gt;
&lt;br /&gt;
      if (entry) {&lt;br /&gt;
        entry[0] += weight;&lt;br /&gt;
        continue;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      const damageByType = [[], [], [], []];&lt;br /&gt;
      const currentDamageInfo = [weight, damageByType];&lt;br /&gt;
&lt;br /&gt;
      let damageWithPrimaryBonuses = Math.floor(&lt;br /&gt;
        (rawDamage * bonusValues.weaponBonusCoeff) / 100&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      damageWithPrimaryBonuses = calcDamageWithPrimaryBonuses(&lt;br /&gt;
        damageWithPrimaryBonuses,&lt;br /&gt;
        bonusValues&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      const damageValues =&lt;br /&gt;
        damageWithPrimaryBonuses &amp;lt;= 2&lt;br /&gt;
          ? [1, 2, 3, 4, 5]&lt;br /&gt;
          : [damageWithPrimaryBonuses];&lt;br /&gt;
&lt;br /&gt;
      for (const damage of damageValues) {&lt;br /&gt;
        saveFinalSkillDamage(&lt;br /&gt;
          damage,&lt;br /&gt;
          bonusValues,&lt;br /&gt;
          criticalAttackRange,&lt;br /&gt;
          damageByType&lt;br /&gt;
        );&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      savedDamage[rawDamage] = currentDamageInfo;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  processSavedDamage(savedDamage, damageWeightedByType, battleValues);&lt;br /&gt;
&lt;br /&gt;
  return damageWeightedByType;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcDamage(&lt;br /&gt;
  attacker,&lt;br /&gt;
  victim,&lt;br /&gt;
  attackType,&lt;br /&gt;
  battle,&lt;br /&gt;
  removeSkillVariation&lt;br /&gt;
) {&lt;br /&gt;
  var damageCalculator, skillId, skillType;&lt;br /&gt;
&lt;br /&gt;
  if (attackType === &amp;quot;physical&amp;quot;) {&lt;br /&gt;
    damageCalculator = calcPhysicalDamage;&lt;br /&gt;
  } else if (attackType.startsWith(&amp;quot;attackSkill&amp;quot;)) {&lt;br /&gt;
    skillId = Number(attackType.split(&amp;quot;attackSkill&amp;quot;)[1]);&lt;br /&gt;
&lt;br /&gt;
    if (isMagicClass(attacker) || isDispell(attacker, skillId)) {&lt;br /&gt;
      skillType = &amp;quot;magic&amp;quot;;&lt;br /&gt;
      damageCalculator = calcMagicSkillDamage;&lt;br /&gt;
    } else {&lt;br /&gt;
      skillType = &amp;quot;physical&amp;quot;;&lt;br /&gt;
      damageCalculator = calcPhysicalSkillDamage;&lt;br /&gt;
    }&lt;br /&gt;
  } else if (attackType.startsWith(&amp;quot;horseSkill&amp;quot;)) {&lt;br /&gt;
    skillType = &amp;quot;physical&amp;quot;;&lt;br /&gt;
    skillId = Number(attackType.split(&amp;quot;horseSkill&amp;quot;)[1]);&lt;br /&gt;
    damageCalculator = calcPhysicalSkillDamage;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var battleValues = createBattleValues(attacker, victim, battle, skillType);&lt;br /&gt;
&lt;br /&gt;
  if (skillId) {&lt;br /&gt;
    getSkillFormula(battle, skillId, battleValues, removeSkillVariation);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    damageWeightedByType: damageCalculator(battleValues),&lt;br /&gt;
    attackValues: battleValues.attackValues,&lt;br /&gt;
    skillType: skillType,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function damageWithoutVariation(&lt;br /&gt;
  attacker,&lt;br /&gt;
  victim,&lt;br /&gt;
  attackType,&lt;br /&gt;
  battle,&lt;br /&gt;
  characters&lt;br /&gt;
) {&lt;br /&gt;
  var startDamageTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
  var { damageWeightedByType, attackValues, skillType } = calcDamage(&lt;br /&gt;
    attacker,&lt;br /&gt;
    victim,&lt;br /&gt;
    attackType,&lt;br /&gt;
    battle&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  var endDamageTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
  displayResults(&lt;br /&gt;
    attackValues,&lt;br /&gt;
    damageWeightedByType,&lt;br /&gt;
    battle,&lt;br /&gt;
    attacker.name,&lt;br /&gt;
    victim.name&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  var endDisplayTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
  displayFightInfo(&lt;br /&gt;
    attackValues.possibleDamageCount,&lt;br /&gt;
    endDamageTime - startDamageTime,&lt;br /&gt;
    endDisplayTime - endDamageTime,&lt;br /&gt;
    battle&lt;br /&gt;
  );&lt;br /&gt;
  addPotentialErrorInformation(&lt;br /&gt;
    battle.errorInformation,&lt;br /&gt;
    attacker,&lt;br /&gt;
    victim,&lt;br /&gt;
    skillType,&lt;br /&gt;
    characters&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  hideElement(battle.bonusVariationResultContainer);&lt;br /&gt;
  showElement(battle.fightResultTitle);&lt;br /&gt;
  showElement(battle.fightResultContainer);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function damageWithVariation(&lt;br /&gt;
  attacker,&lt;br /&gt;
  victim,&lt;br /&gt;
  attackType,&lt;br /&gt;
  battle,&lt;br /&gt;
  entity,&lt;br /&gt;
  entityVariation&lt;br /&gt;
) {&lt;br /&gt;
  var startTime = performance.now();&lt;br /&gt;
  var damageByBonus = [];&lt;br /&gt;
  var augmentationByBonus = [];&lt;br /&gt;
  var {&lt;br /&gt;
    bonusVariationMinValue: minVariation,&lt;br /&gt;
    bonusVariationMaxValue: maxVariation,&lt;br /&gt;
  } = entity;&lt;br /&gt;
  var step = Math.ceil((maxVariation - minVariation + 1) / 500);&lt;br /&gt;
  var simulationCount = 0;&lt;br /&gt;
  var simulationTime;&lt;br /&gt;
  var firstDamage = 1;&lt;br /&gt;
&lt;br /&gt;
  for (&lt;br /&gt;
    var bonusValue = minVariation;&lt;br /&gt;
    bonusValue &amp;lt;= maxVariation;&lt;br /&gt;
    bonusValue += step&lt;br /&gt;
  ) {&lt;br /&gt;
    entity[entityVariation] = bonusValue;&lt;br /&gt;
&lt;br /&gt;
    var {&lt;br /&gt;
      damageWeightedByType,&lt;br /&gt;
      attackValues: { totalCardinal },&lt;br /&gt;
    } = calcDamage(&lt;br /&gt;
      copyObject(attacker),&lt;br /&gt;
      copyObject(victim),&lt;br /&gt;
      attackType,&lt;br /&gt;
      battle,&lt;br /&gt;
      true&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    var meanDamage = calcMeanDamage(damageWeightedByType, totalCardinal);&lt;br /&gt;
&lt;br /&gt;
    if (bonusValue === minVariation) {&lt;br /&gt;
      firstDamage = Math.max(meanDamage, 1e-3);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    damageByBonus.push({ x: bonusValue, y: meanDamage });&lt;br /&gt;
    augmentationByBonus.push({&lt;br /&gt;
      x: bonusValue,&lt;br /&gt;
      y: meanDamage / firstDamage - 1,&lt;br /&gt;
    });&lt;br /&gt;
    simulationCount++;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var endTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
  battle.damageByBonus = damageByBonus.concat(entityVariation);&lt;br /&gt;
&lt;br /&gt;
  addToBonusVariationChart(&lt;br /&gt;
    damageByBonus,&lt;br /&gt;
    augmentationByBonus,&lt;br /&gt;
    entity.bonusVariationName,&lt;br /&gt;
    battle.bonusVariationChart&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  simulationCount = battle.numberFormats.default.format(simulationCount);&lt;br /&gt;
  simulationTime = battle.numberFormats.second.format(&lt;br /&gt;
    (endTime - startTime) / 1000&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  battle.simulationCounter.textContent = simulationCount;&lt;br /&gt;
  battle.simulationTime.textContent = simulationTime;&lt;br /&gt;
&lt;br /&gt;
  hideElement(battle.fightResultContainer);&lt;br /&gt;
  showElement(battle.fightResultTitle);&lt;br /&gt;
  showElement(battle.bonusVariationResultContainer);&lt;br /&gt;
&lt;br /&gt;
  if (&lt;br /&gt;
    isChecked(attacker.useBonusVariation) &amp;amp;&amp;amp;&lt;br /&gt;
    isChecked(victim.useBonusVariation)&lt;br /&gt;
  ) {&lt;br /&gt;
    showElement(battle.errorInformation[&amp;quot;attacker-victim-variation&amp;quot;]);&lt;br /&gt;
  } else {&lt;br /&gt;
    hideElement(battle.errorInformation[&amp;quot;attacker-victim-variation&amp;quot;]);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function changeMonsterValues(monster, instance, attacker) {&lt;br /&gt;
  switch (instance) {&lt;br /&gt;
    case &amp;quot;SungMahiTower&amp;quot;:&lt;br /&gt;
      var sungMahiFloor = 1;&lt;br /&gt;
      var sungMahiStep = 1;&lt;br /&gt;
      var rawDefense = 120;&lt;br /&gt;
&lt;br /&gt;
      if (isPC(attacker)) {&lt;br /&gt;
        sungMahiFloor = attacker.sungMahiFloor;&lt;br /&gt;
        sungMahiStep = attacker.sungMahiStep;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (monster.rank === 5) {&lt;br /&gt;
        monster.level = 121;&lt;br /&gt;
        monster.dex = 75;&lt;br /&gt;
        rawDefense += 1;&lt;br /&gt;
      } else if (monster.rank === 6) {&lt;br /&gt;
        monster.level = 123;&lt;br /&gt;
        monster.dex = 75;&lt;br /&gt;
        rawDefense += 1;&lt;br /&gt;
      } else {&lt;br /&gt;
        monster.level = 120;&lt;br /&gt;
        monster.dex = 68;&lt;br /&gt;
      }&lt;br /&gt;
      monster.vit = 100;&lt;br /&gt;
      monster.rawDefense = rawDefense + (sungMahiStep - 1) * 6;&lt;br /&gt;
      monster.fistDefense = 0;&lt;br /&gt;
      monster.swordDefense = 0;&lt;br /&gt;
      monster.twoHandedSwordDefense = 0;&lt;br /&gt;
      monster.daggerDefense = 0;&lt;br /&gt;
      monster.bellDefense = 0;&lt;br /&gt;
      monster.fanDefense = 0;&lt;br /&gt;
      monster.arrowDefense = 0;&lt;br /&gt;
      monster.clawDefense = 0;&lt;br /&gt;
      monster.magicResistance = 0;&lt;br /&gt;
      monster.fireResistance = -20;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  switch (monster.vnum) {&lt;br /&gt;
    // Alastor&lt;br /&gt;
    case 6790:&lt;br /&gt;
      monster.iceResistance = 0;&lt;br /&gt;
      monster.iceBonus = 0;&lt;br /&gt;
      monster.lightningResistance = -10;&lt;br /&gt;
      monster.lightningBonus = 65;&lt;br /&gt;
      break;&lt;br /&gt;
&lt;br /&gt;
    // Zodiac boss&lt;br /&gt;
    case 2752:&lt;br /&gt;
    case 2762:&lt;br /&gt;
    case 2772:&lt;br /&gt;
    case 2782:&lt;br /&gt;
    case 2792:&lt;br /&gt;
    case 2802:&lt;br /&gt;
    case 2812:&lt;br /&gt;
    case 2822:&lt;br /&gt;
    case 2832:&lt;br /&gt;
    case 2842:&lt;br /&gt;
    case 2852:&lt;br /&gt;
    case 2862:&lt;br /&gt;
      monster.level = 136;&lt;br /&gt;
      monster.vit = 200;&lt;br /&gt;
      monster.rawDefense = 5000;&lt;br /&gt;
      break;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createWeapon(vnum) {&lt;br /&gt;
  var weapon = copyObject(weaponData[vnum]);&lt;br /&gt;
  var serpentVnums = [360, 380, 1210, 2230, 3250, 5200, 6150, 7330];&lt;br /&gt;
  var weaponValues = weapon[1];&lt;br /&gt;
  var isSerpent = isValueInArray(Number(vnum), serpentVnums);&lt;br /&gt;
  var isSpecial = Array.isArray(weaponValues[0]);&lt;br /&gt;
  var isMagic;&lt;br /&gt;
&lt;br /&gt;
  if (isSpecial) {&lt;br /&gt;
    isMagic = weaponValues[0][1] &amp;gt; 0;&lt;br /&gt;
  } else {&lt;br /&gt;
    isMagic = weaponValues[1] &amp;gt; 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    type: weapon[0],&lt;br /&gt;
    maxUpgrade: weapon[2].length - 1,&lt;br /&gt;
    isSerpent: isSerpent,&lt;br /&gt;
    isMagic: isMagic,&lt;br /&gt;
    getValues: function (upgrade) {&lt;br /&gt;
      var currentWeaponValues = weaponValues;&lt;br /&gt;
&lt;br /&gt;
      if (upgrade === undefined) {&lt;br /&gt;
        // rare bug when weaponUpgrade is deleted&lt;br /&gt;
        console.warn(&amp;quot;WeaponUpgrade is missing.&amp;quot;);&lt;br /&gt;
        upgrade = this.maxUpgrade;&lt;br /&gt;
      }&lt;br /&gt;
      upgrade = Math.min(upgrade, this.maxUpgrade);&lt;br /&gt;
&lt;br /&gt;
      if (isSpecial) {&lt;br /&gt;
        currentWeaponValues = weaponValues[upgrade];&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      this.minAttackValue = currentWeaponValues[2];&lt;br /&gt;
      this.maxAttackValue = currentWeaponValues[3];&lt;br /&gt;
      this.minMagicAttackValue = currentWeaponValues[0];&lt;br /&gt;
      this.maxMagicAttackValue = currentWeaponValues[1];&lt;br /&gt;
      this.growth = weapon[2][upgrade];&lt;br /&gt;
    },&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createMonster(&lt;br /&gt;
  monsterVnum,&lt;br /&gt;
  translateMonster,&lt;br /&gt;
  attacker,&lt;br /&gt;
  polymorphMonster&lt;br /&gt;
) {&lt;br /&gt;
  var monsterAttributes = monsterData[monsterVnum];&lt;br /&gt;
&lt;br /&gt;
  var monster = {&lt;br /&gt;
    vnum: Number(monsterVnum),&lt;br /&gt;
    name: translateMonster&lt;br /&gt;
      ? getTranslatedMonsterName(monsterVnum)&lt;br /&gt;
      : monsterAttributes[36],&lt;br /&gt;
    rank: monsterAttributes[0],&lt;br /&gt;
    race: monsterAttributes[1],&lt;br /&gt;
    attack: monsterAttributes[2],&lt;br /&gt;
    level: monsterAttributes[3],&lt;br /&gt;
    type: monsterAttributes[4],&lt;br /&gt;
    str: monsterAttributes[5],&lt;br /&gt;
    dex: monsterAttributes[6],&lt;br /&gt;
    vit: monsterAttributes[7],&lt;br /&gt;
    int: monsterAttributes[8],&lt;br /&gt;
    minAttackValue: monsterAttributes[9],&lt;br /&gt;
    maxAttackValue: monsterAttributes[10],&lt;br /&gt;
    rawDefense: monsterAttributes[11],&lt;br /&gt;
    criticalHit: monsterAttributes[12],&lt;br /&gt;
    piercingHit: monsterAttributes[13],&lt;br /&gt;
    fistDefense: monsterAttributes[14],&lt;br /&gt;
    swordDefense: monsterAttributes[15],&lt;br /&gt;
    twoHandedSwordDefense: monsterAttributes[16],&lt;br /&gt;
    daggerDefense: monsterAttributes[17],&lt;br /&gt;
    bellDefense: monsterAttributes[18],&lt;br /&gt;
    fanDefense: monsterAttributes[19],&lt;br /&gt;
    arrowDefense: monsterAttributes[20],&lt;br /&gt;
    clawDefense: monsterAttributes[21],&lt;br /&gt;
    fireResistance: monsterAttributes[22],&lt;br /&gt;
    lightningResistance: monsterAttributes[23],&lt;br /&gt;
    magicResistance: monsterAttributes[24],&lt;br /&gt;
    windResistance: monsterAttributes[25],&lt;br /&gt;
    lightningBonus: monsterAttributes[26],&lt;br /&gt;
    fireBonus: monsterAttributes[27],&lt;br /&gt;
    iceBonus: monsterAttributes[28],&lt;br /&gt;
    windBonus: monsterAttributes[29],&lt;br /&gt;
    earthBonus: monsterAttributes[30],&lt;br /&gt;
    darknessBonus: monsterAttributes[31],&lt;br /&gt;
    darknessResistance: monsterAttributes[32],&lt;br /&gt;
    iceResistance: monsterAttributes[33],&lt;br /&gt;
    earthResistance: monsterAttributes[34],&lt;br /&gt;
    damageMultiplier: monsterAttributes[35],&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  // monster.instance = 0;&lt;br /&gt;
&lt;br /&gt;
  // if (attacker &amp;amp;&amp;amp; monster.instance === 0) {&lt;br /&gt;
  //   changeMonsterValues(monster, &amp;quot;SungMahiTower&amp;quot;, attacker);&lt;br /&gt;
  // }&lt;br /&gt;
  if (!polymorphMonster) {&lt;br /&gt;
    changeMonsterValues(monster);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  monster.defense = monster.rawDefense + monster.level + monster.vit;&lt;br /&gt;
&lt;br /&gt;
  return monster;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addPotentialErrorInformation(&lt;br /&gt;
  errorInformation,&lt;br /&gt;
  attacker,&lt;br /&gt;
  victim,&lt;br /&gt;
  skillType,&lt;br /&gt;
  characters&lt;br /&gt;
) {&lt;br /&gt;
  for (var error of Object.values(errorInformation)) {&lt;br /&gt;
    hideElement(error);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker)) {&lt;br /&gt;
    if (isRiding(attacker)) {&lt;br /&gt;
      if (attacker.horsePoint === 0) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;horse-level&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
      showElement(errorInformation[&amp;quot;horse-stat&amp;quot;]);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isPolymorph(attacker)) {&lt;br /&gt;
      if (attacker.polymorphPoint === 0) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;polymorph-level&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (&lt;br /&gt;
        (attacker.polymorphPoint &amp;lt;= 39 &amp;amp;&amp;amp; attacker.attackValuePercent &amp;lt;= 199) ||&lt;br /&gt;
        (attacker.polymorphPoint === 40 &amp;amp;&amp;amp; attacker.attackValuePercent &amp;lt;= 299)&lt;br /&gt;
      ) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;polymorph-bonus&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
    if (skillType === &amp;quot;magic&amp;quot; &amp;amp;&amp;amp; !isDispell(attacker, 6)) {&lt;br /&gt;
      if (attacker.magicAttackValue) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;magic-attack-value-bonus&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
      if (victim.magicResistance) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;magic-resistance&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
      if (victim.magicResistance &amp;gt; 0 &amp;amp;&amp;amp; attacker.magicPenetration) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;magic-penetration&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    showElement(errorInformation[&amp;quot;monster-attacker&amp;quot;]);&lt;br /&gt;
    if (isMagicAttacker(attacker) &amp;amp;&amp;amp; victim.magicResistance) {&lt;br /&gt;
      showElement(errorInformation[&amp;quot;magic-resistance&amp;quot;]);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (isPC(victim)) {&lt;br /&gt;
    if (isRiding(victim)) {&lt;br /&gt;
      showElement(errorInformation[&amp;quot;horse-stat&amp;quot;]);&lt;br /&gt;
    }&lt;br /&gt;
    if (isPolymorph(victim)) {&lt;br /&gt;
      if (attacker.polymorphPoint === 0) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;polymorph-level&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
      showElement(errorInformation[&amp;quot;polymorph-defense&amp;quot;]);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (characters.unsavedChanges) {&lt;br /&gt;
    showElement(errorInformation[&amp;quot;save&amp;quot;]);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function reduceChartPointsListener(battle) {&lt;br /&gt;
  var {&lt;br /&gt;
    reduceChartPointsContainer,&lt;br /&gt;
    reduceChartPoints,&lt;br /&gt;
    numberFormats: { second: numberFormat },&lt;br /&gt;
    displayTime,&lt;br /&gt;
  } = battle;&lt;br /&gt;
&lt;br /&gt;
  reduceChartPoints.addEventListener(&amp;quot;change&amp;quot;, function () {&lt;br /&gt;
    reduceChartPoints.disabled = true;&lt;br /&gt;
&lt;br /&gt;
    var startDisplayTime = performance.now();&lt;br /&gt;
    var scatterDataByType = battle.scatterDataByType;&lt;br /&gt;
    var {&lt;br /&gt;
      chart,&lt;br /&gt;
      maxPoints,&lt;br /&gt;
      chart: {&lt;br /&gt;
        data: { datasets },&lt;br /&gt;
      },&lt;br /&gt;
    } = battle.damageChart;&lt;br /&gt;
    var addAnimations = false;&lt;br /&gt;
&lt;br /&gt;
    for (var index = 0; index &amp;lt; datasets.length; index++) {&lt;br /&gt;
      var dataset = datasets[index];&lt;br /&gt;
      var scatterData = scatterDataByType[dataset.name];&lt;br /&gt;
&lt;br /&gt;
      if (dataset.canBeReduced &amp;amp;&amp;amp; reduceChartPoints.checked) {&lt;br /&gt;
        dataset.data = aggregateDamage(scatterData, maxPoints);&lt;br /&gt;
        addAnimations = true;&lt;br /&gt;
      } else {&lt;br /&gt;
        dataset.data = scatterData;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    handleChartAnimations(chart, addAnimations);&lt;br /&gt;
    chart.update();&lt;br /&gt;
&lt;br /&gt;
    displayTime.textContent = numberFormat.format(&lt;br /&gt;
      (performance.now() - startDisplayTime) / 1000&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    setTimeout(function () {&lt;br /&gt;
      reduceChartPoints.disabled = false;&lt;br /&gt;
    }, 1000);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  reduceChartPointsContainer.addEventListener(&amp;quot;pointerup&amp;quot;, function (event) {&lt;br /&gt;
    if (event.pointerType === &amp;quot;mouse&amp;quot;) {&lt;br /&gt;
      if (event.target.closest(&amp;quot;label&amp;quot;)) {&lt;br /&gt;
        return;&lt;br /&gt;
      }&lt;br /&gt;
      reduceChartPoints.click();&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function downloadRawDataListener(battle) {&lt;br /&gt;
  var { downLoadRawData, downLoadRawDataVariation } = battle;&lt;br /&gt;
  var fileType = &amp;quot;text/csv;charset=utf-8;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  downLoadRawData.addEventListener(&amp;quot;click&amp;quot;, function () {&lt;br /&gt;
    var damageWeightedByType = battle.damageWeightedByType;&lt;br /&gt;
    var filename = &amp;quot;raw_damage.csv&amp;quot;;&lt;br /&gt;
    var csvContent = &amp;quot;damage,probabilities,damageType\n&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    for (var damageType in damageWeightedByType) {&lt;br /&gt;
      var damageWeighted = damageWeightedByType[damageType];&lt;br /&gt;
&lt;br /&gt;
      for (var damage in damageWeighted) {&lt;br /&gt;
        csvContent +=&lt;br /&gt;
          damage + &amp;quot;,&amp;quot; + damageWeighted[damage] + &amp;quot;,&amp;quot; + damageType + &amp;quot;\n&amp;quot;;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    downloadData(csvContent, fileType, filename);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  downLoadRawDataVariation.addEventListener(&amp;quot;click&amp;quot;, function () {&lt;br /&gt;
    var damageByBonus = battle.damageByBonus;&lt;br /&gt;
    var damageByBonusLength = damageByBonus.length;&lt;br /&gt;
    var filename = &amp;quot;damage_variation.csv&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    if (!damageByBonusLength) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var csvContent =&lt;br /&gt;
      damageByBonus[damageByBonusLength - 1] + &amp;quot;,averageDamage\n&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    for (var index = 0; index &amp;lt; damageByBonusLength - 1; index++) {&lt;br /&gt;
      var row = damageByBonus[index];&lt;br /&gt;
&lt;br /&gt;
      csvContent += row.x + &amp;quot;,&amp;quot; + row.y + &amp;quot;\n&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    downloadData(csvContent, fileType, filename);&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function displayResults(&lt;br /&gt;
  attackValues,&lt;br /&gt;
  damageWeightedByType,&lt;br /&gt;
  battle,&lt;br /&gt;
  attackerName,&lt;br /&gt;
  victimName&lt;br /&gt;
) {&lt;br /&gt;
  var [meanDamage, minDamage, maxDamage, scatterDataByType, uniqueDamageCount] =&lt;br /&gt;
    prepareDamageData(damageWeightedByType, attackValues);&lt;br /&gt;
&lt;br /&gt;
  addToDamageChart(battle, scatterDataByType);&lt;br /&gt;
  updateDamageChartDescription(battle, uniqueDamageCount);&lt;br /&gt;
  displayFightResults(&lt;br /&gt;
    battle,&lt;br /&gt;
    attackerName,&lt;br /&gt;
    victimName,&lt;br /&gt;
    meanDamage,&lt;br /&gt;
    minDamage,&lt;br /&gt;
    maxDamage&lt;br /&gt;
  );&lt;br /&gt;
  battle.damageWeightedByType = damageWeightedByType;&lt;br /&gt;
  battle.scatterDataByType = scatterDataByType;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function displayFightResults(&lt;br /&gt;
  battle,&lt;br /&gt;
  attackerName,&lt;br /&gt;
  victimName,&lt;br /&gt;
  meanDamage,&lt;br /&gt;
  minDamage,&lt;br /&gt;
  maxDamage&lt;br /&gt;
) {&lt;br /&gt;
  var {&lt;br /&gt;
    tableResultFight,&lt;br /&gt;
    tableResultHistory,&lt;br /&gt;
    savedFights,&lt;br /&gt;
    numberFormats: { default: numberFormat },&lt;br /&gt;
    deleteFightTemplate,&lt;br /&gt;
  } = battle;&lt;br /&gt;
&lt;br /&gt;
  hideElement(tableResultHistory.rows[1]);&lt;br /&gt;
&lt;br /&gt;
  var valuesToDisplay = [&lt;br /&gt;
    attackerName,&lt;br /&gt;
    victimName,&lt;br /&gt;
    battle.battleChoice.attackType.selectedText,&lt;br /&gt;
    meanDamage,&lt;br /&gt;
    minDamage,&lt;br /&gt;
    maxDamage,&lt;br /&gt;
  ];&lt;br /&gt;
&lt;br /&gt;
  savedFights.push(valuesToDisplay);&lt;br /&gt;
  updateSavedFights(savedFights);&lt;br /&gt;
&lt;br /&gt;
  editTableResultRow(tableResultFight.rows[1], valuesToDisplay, numberFormat);&lt;br /&gt;
  addRowToTableResultHistory(&lt;br /&gt;
    tableResultHistory,&lt;br /&gt;
    valuesToDisplay,&lt;br /&gt;
    deleteFightTemplate,&lt;br /&gt;
    numberFormat&lt;br /&gt;
  );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function displayFightInfo(&lt;br /&gt;
  possibleDamageCount,&lt;br /&gt;
  damageTimeDuration,&lt;br /&gt;
  displayTimeDuration,&lt;br /&gt;
  battle&lt;br /&gt;
) {&lt;br /&gt;
  const {&lt;br /&gt;
    damageInfoContainer,&lt;br /&gt;
    numberFormats: { default: defaultFormat, second: secondFormat },&lt;br /&gt;
    possibleDamageCounter,&lt;br /&gt;
    damageTime,&lt;br /&gt;
    displayTime,&lt;br /&gt;
  } = battle;&lt;br /&gt;
&lt;br /&gt;
  if (possibleDamageCount &amp;lt;= 1) {&lt;br /&gt;
    hideElement(damageInfoContainer);&lt;br /&gt;
    return;&lt;br /&gt;
  } else {&lt;br /&gt;
    showElement(damageInfoContainer);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  possibleDamageCount = defaultFormat.format(possibleDamageCount);&lt;br /&gt;
  damageTimeDuration = secondFormat.format(damageTimeDuration / 1000);&lt;br /&gt;
  displayTimeDuration = secondFormat.format(displayTimeDuration / 1000);&lt;br /&gt;
&lt;br /&gt;
  possibleDamageCounter.textContent = possibleDamageCount;&lt;br /&gt;
  damageTime.textContent = damageTimeDuration;&lt;br /&gt;
  displayTime.textContent = displayTimeDuration;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function parseTypeAndName(data) {&lt;br /&gt;
  var [type, nameOrVnum] = splitFirst(data, &amp;quot;-&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    type: type,&lt;br /&gt;
    nameOrVnum: nameOrVnum,&lt;br /&gt;
    isCharacter: type === &amp;quot;character&amp;quot;,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isCharacterSelected(characterName, selected) {&lt;br /&gt;
  if (!selected) {&lt;br /&gt;
    return false;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var { nameOrVnum, isCharacter } = parseTypeAndName(selected);&lt;br /&gt;
&lt;br /&gt;
  return nameOrVnum === characterName &amp;amp;&amp;amp; isCharacter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function useBonusVariationMode(character, variation) {&lt;br /&gt;
  return (&lt;br /&gt;
    isChecked(character.useBonusVariation) &amp;amp;&amp;amp;&lt;br /&gt;
    character.hasOwnProperty(variation) &amp;amp;&amp;amp;&lt;br /&gt;
    character.bonusVariationMinValue &amp;lt; character.bonusVariationMaxValue&lt;br /&gt;
  );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createBattle(characters, battle) {&lt;br /&gt;
  var battleChoice = battle.battleChoice;&lt;br /&gt;
  var battleForm = battleChoice.form;&lt;br /&gt;
  var lastInvalidTime = 0;&lt;br /&gt;
&lt;br /&gt;
  battleForm.addEventListener(&amp;quot;change&amp;quot;, handleBattleFormChange);&lt;br /&gt;
  battleForm.addEventListener(&amp;quot;invalid&amp;quot;, handleBattleFormInvalid, true);&lt;br /&gt;
  battleForm.addEventListener(&amp;quot;submit&amp;quot;, handleBattleFormSubmit);&lt;br /&gt;
&lt;br /&gt;
  function handleBattleFormChange(event) {&lt;br /&gt;
    var target = event.target;&lt;br /&gt;
    var { name: targetName, value: targetValue, type: targetType } = target;&lt;br /&gt;
&lt;br /&gt;
    if (targetType !== &amp;quot;radio&amp;quot;) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (targetName === &amp;quot;attackType&amp;quot;) {&lt;br /&gt;
      battleChoice.attackType.selectedText =&lt;br /&gt;
        target.previousElementSibling.textContent;&lt;br /&gt;
    } else {&lt;br /&gt;
      updateBattleChoiceButton(battleChoice, targetName, targetValue);&lt;br /&gt;
&lt;br /&gt;
      if (targetName === &amp;quot;attacker&amp;quot;) {&lt;br /&gt;
        filterAttackTypeSelection(characters, battleChoice, targetValue);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function handleBattleFormInvalid(event) {&lt;br /&gt;
    var currentTime = Date.now();&lt;br /&gt;
&lt;br /&gt;
    if (currentTime - lastInvalidTime &amp;lt; 100) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    lastInvalidTime = currentTime;&lt;br /&gt;
&lt;br /&gt;
    var target = event.target;&lt;br /&gt;
    var modal = target.closest(&amp;quot;.modal&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (!modal) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var dataModal = modal.dataset.modal;&lt;br /&gt;
&lt;br /&gt;
    if (!dataModal) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var category = dataModal.split(&amp;quot;-&amp;quot;)[0];&lt;br /&gt;
&lt;br /&gt;
    if (isValueInArray(category, battleChoice.categories)) {&lt;br /&gt;
      battleChoice[category].button.click();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function handleBattleFormSubmit(event) {&lt;br /&gt;
    event.preventDefault();&lt;br /&gt;
&lt;br /&gt;
    // auto save&lt;br /&gt;
    if (characters.unsavedChanges) {&lt;br /&gt;
      characters.saveButton.click();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var battleInfo = new FormData(event.target);&lt;br /&gt;
    var attackerData = battleInfo.get(&amp;quot;attacker&amp;quot;);&lt;br /&gt;
    var attackType = battleInfo.get(&amp;quot;attackType&amp;quot;);&lt;br /&gt;
    var victimData = battleInfo.get(&amp;quot;victim&amp;quot;);&lt;br /&gt;
    var attackerVariation;&lt;br /&gt;
    var victimVariation;&lt;br /&gt;
&lt;br /&gt;
    if (!attackerData &amp;amp;&amp;amp; !attackType &amp;amp;&amp;amp; !victimData) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var { nameOrVnum: attackerNameOrVnum, isCharacter: attackerIsPlayer } =&lt;br /&gt;
      parseTypeAndName(attackerData);&lt;br /&gt;
    var { nameOrVnum: victimNameOrVnum, isCharacter: victimIsPlayer } =&lt;br /&gt;
      parseTypeAndName(victimData);&lt;br /&gt;
&lt;br /&gt;
    if (attackerIsPlayer) {&lt;br /&gt;
      var attacker = copyObject(characters.savedCharacters[attackerNameOrVnum]);&lt;br /&gt;
      attackerVariation = attacker.bonusVariation;&lt;br /&gt;
    } else {&lt;br /&gt;
      var attacker = createMonster(&lt;br /&gt;
        attackerNameOrVnum,&lt;br /&gt;
        characters.translateMonsters&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (victimIsPlayer) {&lt;br /&gt;
      var victim = copyObject(characters.savedCharacters[victimNameOrVnum]);&lt;br /&gt;
      victimVariation = victim.bonusVariation;&lt;br /&gt;
    } else {&lt;br /&gt;
      var victim = createMonster(&lt;br /&gt;
        victimNameOrVnum,&lt;br /&gt;
        characters.translateMonsters,&lt;br /&gt;
        attacker&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (useBonusVariationMode(attacker, attackerVariation)) {&lt;br /&gt;
      damageWithVariation(&lt;br /&gt;
        attacker,&lt;br /&gt;
        victim,&lt;br /&gt;
        attackType,&lt;br /&gt;
        battle,&lt;br /&gt;
        attacker,&lt;br /&gt;
        attackerVariation&lt;br /&gt;
      );&lt;br /&gt;
    } else if (useBonusVariationMode(victim, victimVariation)) {&lt;br /&gt;
      damageWithVariation(&lt;br /&gt;
        attacker,&lt;br /&gt;
        victim,&lt;br /&gt;
        attackType,&lt;br /&gt;
        battle,&lt;br /&gt;
        victim,&lt;br /&gt;
        victimVariation&lt;br /&gt;
      );&lt;br /&gt;
    } else {&lt;br /&gt;
      damageWithoutVariation(attacker, victim, attackType, battle, characters);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createMapping() {&lt;br /&gt;
  return {&lt;br /&gt;
    typeFlag: [&lt;br /&gt;
      &amp;quot;animalBonus&amp;quot;, // 0&lt;br /&gt;
      &amp;quot;humanBonus&amp;quot;, // 1&lt;br /&gt;
      &amp;quot;orcBonus&amp;quot;, // 2&lt;br /&gt;
      &amp;quot;mysticBonus&amp;quot;, // 3&lt;br /&gt;
      &amp;quot;undeadBonus&amp;quot;, // 4&lt;br /&gt;
      &amp;quot;insectBonus&amp;quot;, // 5&lt;br /&gt;
      &amp;quot;desertBonus&amp;quot;, // 6&lt;br /&gt;
      &amp;quot;devilBonus&amp;quot;, // 7&lt;br /&gt;
      &amp;quot;zodiacBonus&amp;quot;, // 8&lt;br /&gt;
    ],&lt;br /&gt;
    raceBonus: {&lt;br /&gt;
      warrior: &amp;quot;warriorBonus&amp;quot;,&lt;br /&gt;
      sura: &amp;quot;suraBonus&amp;quot;,&lt;br /&gt;
      ninja: &amp;quot;ninjaBonus&amp;quot;,&lt;br /&gt;
      shaman: &amp;quot;shamanBonus&amp;quot;,&lt;br /&gt;
      lycan: &amp;quot;lycanBonus&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    raceResistance: {&lt;br /&gt;
      warrior: &amp;quot;warriorResistance&amp;quot;,&lt;br /&gt;
      sura: &amp;quot;suraResistance&amp;quot;,&lt;br /&gt;
      ninja: &amp;quot;ninjaResistance&amp;quot;,&lt;br /&gt;
      shaman: &amp;quot;shamanResistance&amp;quot;,&lt;br /&gt;
      lycan: &amp;quot;lycanResistance&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    defenseWeapon: [&lt;br /&gt;
      &amp;quot;swordDefense&amp;quot;, // 0&lt;br /&gt;
      &amp;quot;daggerDefense&amp;quot;, // 1&lt;br /&gt;
      &amp;quot;arrowDefense&amp;quot;, // 2&lt;br /&gt;
      &amp;quot;twoHandedSwordDefense&amp;quot;, // 3&lt;br /&gt;
      &amp;quot;bellDefense&amp;quot;, // 4&lt;br /&gt;
      &amp;quot;clawDefense&amp;quot;, // 5&lt;br /&gt;
      &amp;quot;fanDefense&amp;quot;, // 6&lt;br /&gt;
      &amp;quot;swordDefense&amp;quot;, // 7&lt;br /&gt;
      &amp;quot;fistDefense&amp;quot;, // 8&lt;br /&gt;
    ],&lt;br /&gt;
    breakWeapon: [&lt;br /&gt;
      &amp;quot;breakSwordDefense&amp;quot;, // 0&lt;br /&gt;
      &amp;quot;breakDaggerDefense&amp;quot;, // 1&lt;br /&gt;
      &amp;quot;breakArrowDefense&amp;quot;, // 2&lt;br /&gt;
      &amp;quot;breakTwoHandedSwordDefense&amp;quot;, // 3&lt;br /&gt;
      &amp;quot;breakBellDefense&amp;quot;, // 4&lt;br /&gt;
      &amp;quot;breakClawDefense&amp;quot;, // 5&lt;br /&gt;
      &amp;quot;breakFanDefense&amp;quot;, // 6&lt;br /&gt;
      &amp;quot;breakSwordDefense&amp;quot;, // 7&lt;br /&gt;
    ],&lt;br /&gt;
    elementBonus: [&lt;br /&gt;
      &amp;quot;fireBonus&amp;quot;, // 0&lt;br /&gt;
      &amp;quot;iceBonus&amp;quot;, // 1&lt;br /&gt;
      &amp;quot;windBonus&amp;quot;, // 2&lt;br /&gt;
      &amp;quot;lightningBonus&amp;quot;, // 3&lt;br /&gt;
      &amp;quot;earthBonus&amp;quot;, // 4&lt;br /&gt;
      &amp;quot;darknessBonus&amp;quot;, // 5&lt;br /&gt;
    ],&lt;br /&gt;
    elementResistance: [&lt;br /&gt;
      &amp;quot;fireResistance&amp;quot;, // 0&lt;br /&gt;
      &amp;quot;iceResistance&amp;quot;, // 1&lt;br /&gt;
      &amp;quot;windResistance&amp;quot;, // 2&lt;br /&gt;
      &amp;quot;lightningResistance&amp;quot;, // 3&lt;br /&gt;
      &amp;quot;earthResistance&amp;quot;, // 4&lt;br /&gt;
      &amp;quot;darknessResistance&amp;quot;, // 5&lt;br /&gt;
    ],&lt;br /&gt;
    attackType: [&lt;br /&gt;
      &amp;quot;normalHit&amp;quot;,&lt;br /&gt;
      &amp;quot;criticalHit&amp;quot;,&lt;br /&gt;
      &amp;quot;piercingHit&amp;quot;,&lt;br /&gt;
      &amp;quot;criticalPiercingHit&amp;quot;,&lt;br /&gt;
    ],&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createConstants() {&lt;br /&gt;
  var constants = {&lt;br /&gt;
    polymorphPowerTable: [&lt;br /&gt;
      10, 11, 11, 12, 13, 13, 14, 15, 16, 17, 18, 19, 20, 22, 23, 24, 26, 27,&lt;br /&gt;
      29, 31, 33, 35, 37, 39, 41, 44, 46, 49, 52, 55, 59, 62, 66, 70, 74, 79,&lt;br /&gt;
      84, 89, 94, 100, 0,&lt;br /&gt;
    ],&lt;br /&gt;
    skillPowerTable: [&lt;br /&gt;
      0, 0.05, 0.06, 0.08, 0.1, 0.12, 0.14, 0.16, 0.18, 0.2, 0.22, 0.24, 0.26,&lt;br /&gt;
      0.28, 0.3, 0.32, 0.34, 0.36, 0.38, 0.4, 0.5, 0.52, 0.54, 0.56, 0.58, 0.6,&lt;br /&gt;
      0.63, 0.66, 0.69, 0.72, 0.82, 0.85, 0.88, 0.91, 0.94, 0.98, 1.02, 1.06,&lt;br /&gt;
      1.1, 1.15, 1.25,&lt;br /&gt;
    ],&lt;br /&gt;
    marriageTable: {&lt;br /&gt;
      harmonyEarrings: [4, 5, 6, 8],&lt;br /&gt;
      loveEarrings: [4, 5, 6, 8],&lt;br /&gt;
      harmonyBracelet: [4, 5, 6, 8],&lt;br /&gt;
      loveNecklace: [20, 25, 30, 40],&lt;br /&gt;
      harmonyNecklace: [12, 16, 20, 30],&lt;br /&gt;
    },&lt;br /&gt;
    allowedWeaponsPerRace: {&lt;br /&gt;
      warrior: [0, 3, 8],&lt;br /&gt;
      ninja: [0, 1, 2, 8],&lt;br /&gt;
      sura: [0, 7, 8],&lt;br /&gt;
      shaman: [4, 6, 8],&lt;br /&gt;
      lycan: [5, 8],&lt;br /&gt;
    },&lt;br /&gt;
  };&lt;br /&gt;
  return constants;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initResultTableHistory(battle) {&lt;br /&gt;
  var {&lt;br /&gt;
    tableResultHistory,&lt;br /&gt;
    savedFights,&lt;br /&gt;
    deleteFightTemplate,&lt;br /&gt;
    numberFormats: { default: numberFormat },&lt;br /&gt;
  } = battle;&lt;br /&gt;
  var startIndex = 3;&lt;br /&gt;
&lt;br /&gt;
  if (savedFights.length) {&lt;br /&gt;
    hideElement(tableResultHistory.rows[1]);&lt;br /&gt;
&lt;br /&gt;
    for (var savedFight of savedFights) {&lt;br /&gt;
      addRowToTableResultHistory(&lt;br /&gt;
        tableResultHistory,&lt;br /&gt;
        savedFight,&lt;br /&gt;
        deleteFightTemplate,&lt;br /&gt;
        numberFormat&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  tableResultHistory.addEventListener(&amp;quot;click&amp;quot;, function (event) {&lt;br /&gt;
    var deleteButton = event.target.closest(&amp;quot;.svg-icon-delete&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (deleteButton) {&lt;br /&gt;
      var row = deleteButton.closest(&amp;quot;tr&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
      if (row) {&lt;br /&gt;
        savedFights.splice(row.rowIndex - startIndex, 1);&lt;br /&gt;
        updateSavedFights(savedFights);&lt;br /&gt;
&lt;br /&gt;
        row.remove();&lt;br /&gt;
&lt;br /&gt;
        if (tableResultHistory.rows.length === startIndex) {&lt;br /&gt;
          showElement(tableResultHistory.rows[1]);&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initDamageChart(battle, currentLanguage, defaultText) {&lt;br /&gt;
  const { reduceChartPointsContainer, reduceChartPoints } = battle;&lt;br /&gt;
  const { default: defaultFormat, percent: percentFormat } =&lt;br /&gt;
    battle.numberFormats;&lt;br /&gt;
  const customPlugins = {&lt;br /&gt;
    id: &amp;quot;customPlugins&amp;quot;,&lt;br /&gt;
    afterDraw(chart) {&lt;br /&gt;
      const missPercentage = chart.data.missPercentage;&lt;br /&gt;
&lt;br /&gt;
      if (!missPercentage) {&lt;br /&gt;
        return;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      const {&lt;br /&gt;
        ctx,&lt;br /&gt;
        chartArea: { top, right },&lt;br /&gt;
      } = chart;&lt;br /&gt;
      ctx.save();&lt;br /&gt;
      const text =&lt;br /&gt;
        defaultText.miss + &amp;quot; : &amp;quot; + percentFormat.format(missPercentage);&lt;br /&gt;
      const padding = 4;&lt;br /&gt;
      const fontSize = 14;&lt;br /&gt;
&lt;br /&gt;
      ctx.font = fontSize + &amp;quot;px Helvetica Neue&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
      const textWidth = ctx.measureText(text).width;&lt;br /&gt;
      const xPosition = right - textWidth - 5;&lt;br /&gt;
      const yPosition = top + 5;&lt;br /&gt;
&lt;br /&gt;
      ctx.fillStyle = &amp;quot;rgba(255, 0, 0, 0.2)&amp;quot;;&lt;br /&gt;
      ctx.fillRect(&lt;br /&gt;
        xPosition - padding,&lt;br /&gt;
        yPosition - padding,&lt;br /&gt;
        textWidth + 2 * padding,&lt;br /&gt;
        fontSize + 2 * padding&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      ctx.strokeStyle = &amp;quot;red&amp;quot;;&lt;br /&gt;
      ctx.strokeRect(&lt;br /&gt;
        xPosition - padding,&lt;br /&gt;
        yPosition - padding,&lt;br /&gt;
        textWidth + 2 * padding,&lt;br /&gt;
        fontSize + 2 * padding&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      ctx.fillStyle = &amp;quot;#666&amp;quot;;&lt;br /&gt;
      ctx.textBaseline = &amp;quot;top&amp;quot;;&lt;br /&gt;
      ctx.fillText(text, xPosition, yPosition + 1);&lt;br /&gt;
&lt;br /&gt;
      ctx.restore();&lt;br /&gt;
    },&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  Chart.register(customPlugins);&lt;br /&gt;
&lt;br /&gt;
  const ctx = battle.plotDamage.getContext(&amp;quot;2d&amp;quot;);&lt;br /&gt;
  const maxLabelsInTooltip = 10;&lt;br /&gt;
  const nullLabelText = &amp;quot; ...&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  const chart = new Chart(ctx, {&lt;br /&gt;
    type: &amp;quot;scatter&amp;quot;,&lt;br /&gt;
    data: {&lt;br /&gt;
      missPercentage: 0,&lt;br /&gt;
      datasets: [],&lt;br /&gt;
    },&lt;br /&gt;
    options: {&lt;br /&gt;
      locale: currentLanguage,&lt;br /&gt;
      responsive: true,&lt;br /&gt;
      maintainAspectRatio: false,&lt;br /&gt;
      plugins: {&lt;br /&gt;
        legend: {&lt;br /&gt;
          display: true,&lt;br /&gt;
          onHover: function (e) {&lt;br /&gt;
            e.native.target.style.cursor = &amp;quot;pointer&amp;quot;;&lt;br /&gt;
          },&lt;br /&gt;
          onLeave: function (e) {&lt;br /&gt;
            e.native.target.style.cursor = &amp;quot;default&amp;quot;;&lt;br /&gt;
          },&lt;br /&gt;
          onClick: function (e, legendItem, legend) {&lt;br /&gt;
            const currentIndex = legendItem.datasetIndex;&lt;br /&gt;
            const ci = legend.chart;&lt;br /&gt;
            const isCurrentDatasetVisible = ci.isDatasetVisible(currentIndex);&lt;br /&gt;
            const datasets = ci.data.datasets;&lt;br /&gt;
            const isReducePointsChecked = reduceChartPoints.checked;&lt;br /&gt;
            let hideReducePoints = true;&lt;br /&gt;
&lt;br /&gt;
            datasets[currentIndex].hidden = isCurrentDatasetVisible;&lt;br /&gt;
            legendItem.hidden = isCurrentDatasetVisible;&lt;br /&gt;
&lt;br /&gt;
            for (const index in datasets) {&lt;br /&gt;
              if (ci.isDatasetVisible(index) &amp;amp;&amp;amp; datasets[index].canBeReduced) {&lt;br /&gt;
                showElement(reduceChartPointsContainer);&lt;br /&gt;
                hideReducePoints = false;&lt;br /&gt;
                break;&lt;br /&gt;
              }&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            if (hideReducePoints) {&lt;br /&gt;
              hideElement(reduceChartPointsContainer);&lt;br /&gt;
              handleChartAnimations(ci, true);&lt;br /&gt;
            } else {&lt;br /&gt;
              handleChartAnimations(ci, isReducePointsChecked);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            ci.update();&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        title: {&lt;br /&gt;
          display: true,&lt;br /&gt;
          text: defaultText.damageRepartition,&lt;br /&gt;
          font: {&lt;br /&gt;
            size: 20,&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        tooltip: {&lt;br /&gt;
          callbacks: {&lt;br /&gt;
            label: function (context) {&lt;br /&gt;
              if (context.label === null) {&lt;br /&gt;
                return nullLabelText;&lt;br /&gt;
              }&lt;br /&gt;
&lt;br /&gt;
              const xValue = defaultFormat.format(context.parsed.x);&lt;br /&gt;
              const yValue = percentFormat.format(context.parsed.y);&lt;br /&gt;
              const label =&lt;br /&gt;
                &amp;quot; &amp;quot; +&lt;br /&gt;
                context.dataset.label +&lt;br /&gt;
                &amp;quot; : (&amp;quot; +&lt;br /&gt;
                xValue +&lt;br /&gt;
                &amp;quot;, &amp;quot; +&lt;br /&gt;
                yValue +&lt;br /&gt;
                &amp;quot;)&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
              return label;&lt;br /&gt;
            },&lt;br /&gt;
            beforeBody: function (tooltipItems) {&lt;br /&gt;
              if (tooltipItems.length &amp;gt; maxLabelsInTooltip + 1) {&lt;br /&gt;
                tooltipItems.splice(maxLabelsInTooltip + 1);&lt;br /&gt;
                tooltipItems[maxLabelsInTooltip].label = null;&lt;br /&gt;
              }&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          caretPadding: 10,&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
      scales: {&lt;br /&gt;
        x: {&lt;br /&gt;
          type: &amp;quot;linear&amp;quot;,&lt;br /&gt;
          position: &amp;quot;bottom&amp;quot;,&lt;br /&gt;
          title: {&lt;br /&gt;
            display: true,&lt;br /&gt;
            text: defaultText.damage,&lt;br /&gt;
            font: {&lt;br /&gt;
              size: 16,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          ticks: {&lt;br /&gt;
            callback: function (value) {&lt;br /&gt;
              return Number.isInteger(value) ? value : &amp;quot;&amp;quot;;&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        y: {&lt;br /&gt;
          title: {&lt;br /&gt;
            display: true,&lt;br /&gt;
            text: defaultText.percentage,&lt;br /&gt;
            font: {&lt;br /&gt;
              size: 16,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          ticks: {&lt;br /&gt;
            format: {&lt;br /&gt;
              style: &amp;quot;percent&amp;quot;,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
      elements: {&lt;br /&gt;
        point: {&lt;br /&gt;
          borderWidth: 1,&lt;br /&gt;
          radius: 3,&lt;br /&gt;
          hitRadius: 3,&lt;br /&gt;
          hoverRadius: 6,&lt;br /&gt;
          hoverBorderWidth: 2,&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
    },&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  const datasetsStyle = [&lt;br /&gt;
    {&lt;br /&gt;
      name: &amp;quot;normalHit&amp;quot;,&lt;br /&gt;
      canBeReduced: false,&lt;br /&gt;
      label: defaultText.normalHit,&lt;br /&gt;
      backgroundColor: &amp;quot;rgba(75, 192, 192, 0.2)&amp;quot;,&lt;br /&gt;
      borderColor: &amp;quot;rgba(75, 192, 192, 1)&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      name: &amp;quot;piercingHit&amp;quot;,&lt;br /&gt;
      canBeReduced: false,&lt;br /&gt;
      label: defaultText.piercingHit,&lt;br /&gt;
      backgroundColor: &amp;quot;rgba(192, 192, 75, 0.2)&amp;quot;,&lt;br /&gt;
      borderColor: &amp;quot;rgba(192, 192, 75, 1)&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      name: &amp;quot;criticalHit&amp;quot;,&lt;br /&gt;
      canBeReduced: false,&lt;br /&gt;
      label: defaultText.criticalHit,&lt;br /&gt;
      backgroundColor: &amp;quot;rgba(192, 75, 192, 0.2)&amp;quot;,&lt;br /&gt;
      borderColor: &amp;quot;rgba(192, 75, 192, 1)&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      name: &amp;quot;criticalPiercingHit&amp;quot;,&lt;br /&gt;
      canBeReduced: false,&lt;br /&gt;
      label: defaultText.criticalPiercingHit,&lt;br /&gt;
      backgroundColor: &amp;quot;rgba(75, 75, 192, 0.2)&amp;quot;,&lt;br /&gt;
      borderColor: &amp;quot;rgba(75, 75, 192, 1)&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
  ];&lt;br /&gt;
  battle.damageChart = {&lt;br /&gt;
    chart: chart,&lt;br /&gt;
    datasetsStyle: datasetsStyle,&lt;br /&gt;
    maxPoints: 500,&lt;br /&gt;
    reduceChartPointsContainer: reduceChartPointsContainer,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initBonusVariationChart(battle, currentLanguage, defaultText) {&lt;br /&gt;
  const { plotBonusVariation } = battle;&lt;br /&gt;
&lt;br /&gt;
  const ctx = plotBonusVariation.getContext(&amp;quot;2d&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  const chart = new Chart(ctx, {&lt;br /&gt;
    type: &amp;quot;line&amp;quot;,&lt;br /&gt;
    data: {&lt;br /&gt;
      datasets: [&lt;br /&gt;
        {&lt;br /&gt;
          label: defaultText.averageDamage,&lt;br /&gt;
          backgroundColor: &amp;quot;rgba(75, 192, 192, 0.2)&amp;quot;,&lt;br /&gt;
          borderColor: &amp;quot;rgba(75, 192, 192, 1)&amp;quot;,&lt;br /&gt;
          fill: true,&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          label: defaultText.damageAugmentation,&lt;br /&gt;
          backgroundColor: &amp;quot;rgba(192, 192, 75, 0.2)&amp;quot;,&lt;br /&gt;
          borderColor: &amp;quot;rgba(192, 192, 75, 1)&amp;quot;,&lt;br /&gt;
          hidden: true,&lt;br /&gt;
          yTicksFormat: { style: &amp;quot;percent&amp;quot; },&lt;br /&gt;
          fill: true,&lt;br /&gt;
        },&lt;br /&gt;
      ],&lt;br /&gt;
    },&lt;br /&gt;
    options: {&lt;br /&gt;
      locale: currentLanguage,&lt;br /&gt;
      responsive: true,&lt;br /&gt;
      maintainAspectRatio: false,&lt;br /&gt;
      plugins: {&lt;br /&gt;
        legend: {&lt;br /&gt;
          display: true,&lt;br /&gt;
          onHover: function (e) {&lt;br /&gt;
            e.native.target.style.cursor = &amp;quot;pointer&amp;quot;;&lt;br /&gt;
          },&lt;br /&gt;
          onLeave: function (e) {&lt;br /&gt;
            e.native.target.style.cursor = &amp;quot;default&amp;quot;;&lt;br /&gt;
          },&lt;br /&gt;
          onClick: function (e, legendItem, legend) {&lt;br /&gt;
            var currentIndex = legendItem.datasetIndex;&lt;br /&gt;
            var ci = legend.chart;&lt;br /&gt;
            var datasets = ci.data.datasets;&lt;br /&gt;
            var isCurrentDatasetVisible = ci.isDatasetVisible(currentIndex);&lt;br /&gt;
            var yAxis = ci.options.scales.y;&lt;br /&gt;
&lt;br /&gt;
            var otherIndex = currentIndex === 0 ? 1 : 0;&lt;br /&gt;
            var visibleDataset = isCurrentDatasetVisible&lt;br /&gt;
              ? datasets[otherIndex]&lt;br /&gt;
              : datasets[currentIndex];&lt;br /&gt;
&lt;br /&gt;
            datasets[currentIndex].hidden = isCurrentDatasetVisible;&lt;br /&gt;
            datasets[otherIndex].hidden = !isCurrentDatasetVisible;&lt;br /&gt;
&lt;br /&gt;
            yAxis.title.text = visibleDataset.label;&lt;br /&gt;
            yAxis.ticks.format = visibleDataset.yTicksFormat;&lt;br /&gt;
&lt;br /&gt;
            ci.update();&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        title: {&lt;br /&gt;
          display: true,&lt;br /&gt;
          text: defaultText.bonusVariationTitle.split(&amp;quot;[[]]&amp;quot;),&lt;br /&gt;
          font: {&lt;br /&gt;
            size: 18,&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        tooltip: {&lt;br /&gt;
          caretPadding: 10,&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
      scales: {&lt;br /&gt;
        x: {&lt;br /&gt;
          type: &amp;quot;linear&amp;quot;,&lt;br /&gt;
          position: &amp;quot;bottom&amp;quot;,&lt;br /&gt;
          title: {&lt;br /&gt;
            display: true,&lt;br /&gt;
            text: &amp;quot;Bonus&amp;quot;,&lt;br /&gt;
            font: {&lt;br /&gt;
              size: 16,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          ticks: {&lt;br /&gt;
            callback: function (value) {&lt;br /&gt;
              if (Number.isInteger(value)) {&lt;br /&gt;
                return Number(value);&lt;br /&gt;
              }&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        y: {&lt;br /&gt;
          title: {&lt;br /&gt;
            display: true,&lt;br /&gt;
            text: defaultText.averageDamage,&lt;br /&gt;
            font: {&lt;br /&gt;
              size: 16,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
      elements: {&lt;br /&gt;
        point: {&lt;br /&gt;
          borderWidth: 1,&lt;br /&gt;
          radius: 3,&lt;br /&gt;
          hitRadius: 3,&lt;br /&gt;
          hoverRadius: 6,&lt;br /&gt;
          hoverBorderWidth: 2,&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
    },&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  battle.bonusVariationChart = chart;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterAttackTypeSelection(characters, battleChoice, targetValue) {&lt;br /&gt;
  var { nameOrVnum: attackerNameOrVnum, isCharacter: isAttackerPlayer } =&lt;br /&gt;
    parseTypeAndName(targetValue);&lt;br /&gt;
&lt;br /&gt;
  if (isAttackerPlayer) {&lt;br /&gt;
    var attacker = characters.savedCharacters[attackerNameOrVnum];&lt;br /&gt;
    filterAttackTypeSelectionCharacter(attacker, battleChoice.attackType);&lt;br /&gt;
  } else {&lt;br /&gt;
    filterAttackTypeSelectionMonster(battleChoice.attackType);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addBattleData(battle) {&lt;br /&gt;
  var errorElements = document.querySelectorAll(&amp;quot;[data-error]&amp;quot;);&lt;br /&gt;
  var { elements: attackTypeElements, container: attackTypeContainer } =&lt;br /&gt;
    battle.battleChoice.attackType;&lt;br /&gt;
  var attackTypeChilds = attackTypeContainer.children;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; errorElements.length; index++) {&lt;br /&gt;
    var errorElement = errorElements[index];&lt;br /&gt;
    battle.errorInformation[errorElement.dataset.error] = errorElement;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (var index = 1; index &amp;lt; attackTypeChilds.length - 1; index++) {&lt;br /&gt;
    var attackTypeChild = attackTypeChilds[index];&lt;br /&gt;
    var input = attackTypeChild.querySelector(&amp;quot;input&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    attackTypeElements.push({&lt;br /&gt;
      container: attackTypeChild,&lt;br /&gt;
      input: input,&lt;br /&gt;
      inputClass: input.dataset.class,&lt;br /&gt;
      inputValue: input.value,&lt;br /&gt;
    });&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createDamageCalculatorInformation(&lt;br /&gt;
  defaultLang,&lt;br /&gt;
  currentLanguage,&lt;br /&gt;
  defaultText&lt;br /&gt;
) {&lt;br /&gt;
  const characters = {&lt;br /&gt;
    unsavedChanges: false,&lt;br /&gt;
    savedCharacters: {},&lt;br /&gt;
    currentCharacter: null,&lt;br /&gt;
    savedMonsters: getSavedMonsters(),&lt;br /&gt;
    monsterElements: {},&lt;br /&gt;
    characterCreation: document.getElementById(&amp;quot;character-creation&amp;quot;),&lt;br /&gt;
    addNewCharacterButton: document.getElementById(&amp;quot;add-new-character&amp;quot;),&lt;br /&gt;
    dropZone: document.getElementById(&amp;quot;character-drop-zone&amp;quot;),&lt;br /&gt;
    characterInput: document.getElementById(&amp;quot;character-input&amp;quot;),&lt;br /&gt;
    newCharacterTemplate: document.getElementById(&amp;quot;new-character-template&amp;quot;)&lt;br /&gt;
      .children[0],&lt;br /&gt;
    charactersContainer: document.getElementById(&amp;quot;characters-container&amp;quot;),&lt;br /&gt;
    monsterButtonTemplates: document.getElementById(&amp;quot;monster-button-templates&amp;quot;),&lt;br /&gt;
    monsterTemplate: document.getElementById(&amp;quot;new-monster-template&amp;quot;)&lt;br /&gt;
      .children[0],&lt;br /&gt;
    monstersContainer: document.getElementById(&amp;quot;monsters-container&amp;quot;),&lt;br /&gt;
    monsteriFrame: document.getElementById(&amp;quot;monster-iframe&amp;quot;),&lt;br /&gt;
    stoneiFrame: document.getElementById(&amp;quot;stone-iframe&amp;quot;),&lt;br /&gt;
    saveButton: document.getElementById(&amp;quot;save-character&amp;quot;),&lt;br /&gt;
    weaponCategory: document.getElementById(&amp;quot;weapon-category&amp;quot;),&lt;br /&gt;
    weaponDisplay: document.getElementById(&amp;quot;weapon-display&amp;quot;),&lt;br /&gt;
    randomAttackValue: document.getElementById(&amp;quot;random-attack-value&amp;quot;),&lt;br /&gt;
    randomMagicAttackValue: document.getElementById(&lt;br /&gt;
      &amp;quot;random-magic-attack-value&amp;quot;&lt;br /&gt;
    ),&lt;br /&gt;
    toggleSiblings: {},&lt;br /&gt;
    polymorphDisplay: document.getElementById(&amp;quot;polymorph-display&amp;quot;),&lt;br /&gt;
    bonusVariation: {&lt;br /&gt;
      tabButton: document.getElementById(&amp;quot;Variation&amp;quot;),&lt;br /&gt;
      checkbox: document.getElementById(&amp;quot;use-bonus-variation&amp;quot;),&lt;br /&gt;
      input: document.getElementById(&amp;quot;bonus-variation&amp;quot;),&lt;br /&gt;
      inputName: document.getElementById(&amp;quot;bonus-variation-name&amp;quot;),&lt;br /&gt;
      container: document.getElementById(&amp;quot;bonus-variation-creation&amp;quot;),&lt;br /&gt;
      minValue: document.getElementById(&amp;quot;bonus-variation-min-value&amp;quot;),&lt;br /&gt;
      maxValue: document.getElementById(&amp;quot;bonus-variation-max-value&amp;quot;),&lt;br /&gt;
      disabledText: document.getElementById(&amp;quot;bonus-variation-disabled&amp;quot;),&lt;br /&gt;
      selectedText: document.getElementById(&amp;quot;bonus-variation-selected&amp;quot;),&lt;br /&gt;
      displaySpan: document.getElementById(&amp;quot;bonus-variation-display&amp;quot;),&lt;br /&gt;
    },&lt;br /&gt;
    skillElementsToFilter: document.querySelectorAll(&lt;br /&gt;
      &amp;quot;#skill-container [data-class]&amp;quot;&lt;br /&gt;
    ),&lt;br /&gt;
    currentLanguage: currentLanguage,&lt;br /&gt;
    translateMonsters: defaultLang !== currentLanguage,&lt;br /&gt;
    defaultText: defaultText,&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  for (const [pseudo, character] of Object.entries(getSavedCharacters())) {&lt;br /&gt;
    characters.savedCharacters[pseudo] = character;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  document.querySelectorAll(&amp;quot;.toggle-sibling&amp;quot;).forEach(function (element) {&lt;br /&gt;
    const target = element.dataset.target;&lt;br /&gt;
    const sibling = document.getElementById(target);&lt;br /&gt;
    characters.toggleSiblings[element.name] = sibling;&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  const constants = createConstants();&lt;br /&gt;
&lt;br /&gt;
  const battle = {&lt;br /&gt;
    savedFights: getSavedFights(),&lt;br /&gt;
    battleChoice: {&lt;br /&gt;
      resetAttackType: false,&lt;br /&gt;
      form: document.getElementById(&amp;quot;create-battle&amp;quot;),&lt;br /&gt;
      template: document.getElementById(&amp;quot;battle-selection-template&amp;quot;)&lt;br /&gt;
        .children[0],&lt;br /&gt;
      raceToImage: {&lt;br /&gt;
        warrior: &amp;quot;/images/0/0f/Bandeaurougehomme.png&amp;quot;,&lt;br /&gt;
        ninja: &amp;quot;/images/0/0e/Queuedechevalclair.png&amp;quot;,&lt;br /&gt;
        sura: &amp;quot;/images/3/37/Couperespectablerouge.png&amp;quot;,&lt;br /&gt;
        shaman: &amp;quot;/images/6/6a/Coupeeleganteclairfemme.png&amp;quot;,&lt;br /&gt;
        lycan: &amp;quot;/images/4/4e/Protectionfrontalerouge.png&amp;quot;,&lt;br /&gt;
      },&lt;br /&gt;
      categories: [&amp;quot;attacker&amp;quot;, &amp;quot;victim&amp;quot;],&lt;br /&gt;
      translateMonsters: defaultLang !== currentLanguage,&lt;br /&gt;
      attacker: {&lt;br /&gt;
        character: {&lt;br /&gt;
          count: 0,&lt;br /&gt;
          container: document.getElementById(&amp;quot;attacker-selection-characters&amp;quot;),&lt;br /&gt;
          elements: {},&lt;br /&gt;
        },&lt;br /&gt;
        monster: {&lt;br /&gt;
          count: 0,&lt;br /&gt;
          container: document.getElementById(&amp;quot;attacker-selection-monsters&amp;quot;),&lt;br /&gt;
          elements: {},&lt;br /&gt;
        },&lt;br /&gt;
        button: document.getElementById(&amp;quot;attacker-trigger&amp;quot;),&lt;br /&gt;
        defaultButtonContent: document.getElementById(&lt;br /&gt;
          &amp;quot;attacker-default-button-content&amp;quot;&lt;br /&gt;
        ),&lt;br /&gt;
        buttonContent: document.getElementById(&amp;quot;attacker-button-content&amp;quot;),&lt;br /&gt;
        container: document.getElementById(&amp;quot;attacker-selection&amp;quot;),&lt;br /&gt;
        selected: null,&lt;br /&gt;
      },&lt;br /&gt;
      victim: {&lt;br /&gt;
        character: {&lt;br /&gt;
          count: 0,&lt;br /&gt;
          container: document.getElementById(&amp;quot;victim-selection-characters&amp;quot;),&lt;br /&gt;
          elements: {},&lt;br /&gt;
        },&lt;br /&gt;
        monster: {&lt;br /&gt;
          count: 0,&lt;br /&gt;
          container: document.getElementById(&amp;quot;victim-selection-monsters&amp;quot;),&lt;br /&gt;
          elements: {},&lt;br /&gt;
        },&lt;br /&gt;
        stone: {&lt;br /&gt;
          count: 0,&lt;br /&gt;
          container: document.getElementById(&amp;quot;victim-selection-stones&amp;quot;),&lt;br /&gt;
          elements: {},&lt;br /&gt;
        },&lt;br /&gt;
        button: document.getElementById(&amp;quot;victim-trigger&amp;quot;),&lt;br /&gt;
        defaultButtonContent: document.getElementById(&lt;br /&gt;
          &amp;quot;victim-default-button-content&amp;quot;&lt;br /&gt;
        ),&lt;br /&gt;
        buttonContent: document.getElementById(&amp;quot;victim-button-content&amp;quot;),&lt;br /&gt;
        selected: null,&lt;br /&gt;
      },&lt;br /&gt;
      attackType: {&lt;br /&gt;
        container: document.getElementById(&amp;quot;attack-type-selection&amp;quot;),&lt;br /&gt;
        elements: [],&lt;br /&gt;
        defaultInput: document.getElementById(&amp;quot;physical-attack&amp;quot;),&lt;br /&gt;
        selectedText: &amp;quot;&amp;quot;,&lt;br /&gt;
      },&lt;br /&gt;
    },&lt;br /&gt;
    damageWeightedByType: {},&lt;br /&gt;
    scatterDataByType: {},&lt;br /&gt;
    damageByBonus: [],&lt;br /&gt;
    tableResultFight: document.getElementById(&amp;quot;result-table-fight&amp;quot;),&lt;br /&gt;
    tableResultHistory: document.getElementById(&amp;quot;result-table-history&amp;quot;),&lt;br /&gt;
    deleteFightTemplate: document.getElementById(&amp;quot;delete-fight-template&amp;quot;)&lt;br /&gt;
      .children[0],&lt;br /&gt;
    errorInformation: {},&lt;br /&gt;
    fightResultTitle: document.getElementById(&amp;quot;fight-result-title&amp;quot;),&lt;br /&gt;
    fightResultContainer: document.getElementById(&amp;quot;fight-result-container&amp;quot;),&lt;br /&gt;
    downLoadRawData: document.getElementById(&amp;quot;download-raw-data&amp;quot;),&lt;br /&gt;
    downLoadRawDataVariation: document.getElementById(&lt;br /&gt;
      &amp;quot;download-raw-data-variation&amp;quot;&lt;br /&gt;
    ),&lt;br /&gt;
    bonusVariationResultContainer: document.getElementById(&lt;br /&gt;
      &amp;quot;bonus-variation-result-container&amp;quot;&lt;br /&gt;
    ),&lt;br /&gt;
    reduceChartPointsContainer: document.getElementById(&lt;br /&gt;
      &amp;quot;reduce-chart-points-container&amp;quot;&lt;br /&gt;
    ),&lt;br /&gt;
    reduceChartPoints: document.getElementById(&amp;quot;reduce-chart-points&amp;quot;),&lt;br /&gt;
    plotDamage: document.getElementById(&amp;quot;plot-damage&amp;quot;),&lt;br /&gt;
    plotBonusVariation: document.getElementById(&amp;quot;plot-bonus-variation&amp;quot;),&lt;br /&gt;
    chartDescriptionContainer: document.getElementById(&lt;br /&gt;
      &amp;quot;chart-description-container&amp;quot;&lt;br /&gt;
    ),&lt;br /&gt;
    damageInfoContainer: document.getElementById(&amp;quot;damage-info-container&amp;quot;),&lt;br /&gt;
    uniqueDamageCounters: document.querySelectorAll(&amp;quot;.unique-damage-counter&amp;quot;),&lt;br /&gt;
    possibleDamageCounter: document.getElementById(&amp;quot;possible-damage-counter&amp;quot;),&lt;br /&gt;
    damageTime: document.getElementById(&amp;quot;damage-time&amp;quot;),&lt;br /&gt;
    displayTime: document.getElementById(&amp;quot;display-time&amp;quot;),&lt;br /&gt;
    simulationCounter: document.getElementById(&amp;quot;simulation-counter&amp;quot;),&lt;br /&gt;
    simulationTime: document.getElementById(&amp;quot;simulation-time&amp;quot;),&lt;br /&gt;
    numberFormats: {&lt;br /&gt;
      default: new Intl.NumberFormat(currentLanguage, {&lt;br /&gt;
        minimumFractionDigits: 0,&lt;br /&gt;
        maximumFractionDigits: 1,&lt;br /&gt;
      }),&lt;br /&gt;
      percent: new Intl.NumberFormat(currentLanguage, {&lt;br /&gt;
        style: &amp;quot;percent&amp;quot;,&lt;br /&gt;
        maximumFractionDigits: 3,&lt;br /&gt;
      }),&lt;br /&gt;
      second: new Intl.NumberFormat(currentLanguage, {&lt;br /&gt;
        style: &amp;quot;unit&amp;quot;,&lt;br /&gt;
        unit: &amp;quot;second&amp;quot;,&lt;br /&gt;
        unitDisplay: &amp;quot;long&amp;quot;,&lt;br /&gt;
        maximumFractionDigits: 3,&lt;br /&gt;
      }),&lt;br /&gt;
    },&lt;br /&gt;
    mapping: createMapping(),&lt;br /&gt;
    constants: constants,&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  addBattleData(battle);&lt;br /&gt;
  initResultTableHistory(battle);&lt;br /&gt;
  initDamageChart(battle, currentLanguage, defaultText);&lt;br /&gt;
  initBonusVariationChart(battle, currentLanguage, defaultText);&lt;br /&gt;
  reduceChartPointsListener(battle);&lt;br /&gt;
  downloadRawDataListener(battle);&lt;br /&gt;
&lt;br /&gt;
  return [characters, battle];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function parseText(input) {&lt;br /&gt;
  const regex = /\[\[(.*?)\]\]|([^\[]+)/g;&lt;br /&gt;
  const result = [];&lt;br /&gt;
&lt;br /&gt;
  input.replace(regex, (_, matchA, matchText) =&amp;gt; {&lt;br /&gt;
    if (matchA !== undefined) {&lt;br /&gt;
      result.push({&lt;br /&gt;
        text: matchA,&lt;br /&gt;
        category: matchA === &amp;quot;&amp;quot; ? &amp;quot;NOTRANSLATE&amp;quot; : &amp;quot;A&amp;quot;,&lt;br /&gt;
      });&lt;br /&gt;
    } else if (matchText) {&lt;br /&gt;
      result.push({ text: matchText, category: &amp;quot;#text&amp;quot; });&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  return result;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function translateText(general) {&lt;br /&gt;
  const nodesToTranslate = [&amp;quot;A&amp;quot;, &amp;quot;I&amp;quot;, &amp;quot;B&amp;quot;];&lt;br /&gt;
&lt;br /&gt;
  for (const element of document.querySelectorAll(&amp;quot;[data-t]&amp;quot;)) {&lt;br /&gt;
    const translateText = general[element.dataset.t];&lt;br /&gt;
&lt;br /&gt;
    if (!translateText) continue;&lt;br /&gt;
&lt;br /&gt;
    const childNodes = element.childNodes;&lt;br /&gt;
    const numChildren = childNodes.length;&lt;br /&gt;
&lt;br /&gt;
    if (numChildren === 1) {&lt;br /&gt;
      childNodes[0].textContent = translateText;&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    const parsedText = parseText(translateText);&lt;br /&gt;
    const numParsed = parsedText.length;&lt;br /&gt;
&lt;br /&gt;
    let childIndex = 0;&lt;br /&gt;
    let textIndex = 0;&lt;br /&gt;
&lt;br /&gt;
    while (childIndex &amp;lt; numChildren) {&lt;br /&gt;
      const child = childNodes[childIndex];&lt;br /&gt;
&lt;br /&gt;
      if (textIndex === numParsed) {&lt;br /&gt;
        console.warn(&amp;quot;Bad translation for element&amp;quot;, element);&lt;br /&gt;
        break;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      const parsed = parsedText[textIndex];&lt;br /&gt;
&lt;br /&gt;
      let childName = child.nodeName;&lt;br /&gt;
      const isNodeToTranslate = nodesToTranslate.includes(childName);&lt;br /&gt;
&lt;br /&gt;
      if (&lt;br /&gt;
        (childName === &amp;quot;A&amp;quot; &amp;amp;&amp;amp; child.firstChild?.nodeName === &amp;quot;IMG&amp;quot;) ||&lt;br /&gt;
        !(isNodeToTranslate || childName === &amp;quot;#text&amp;quot;) ||&lt;br /&gt;
        child.dataset?.notranslate&lt;br /&gt;
      ) {&lt;br /&gt;
        childName = &amp;quot;NOTRANSLATE&amp;quot;;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (&lt;br /&gt;
        childName === parsed.category ||&lt;br /&gt;
        (parsed.category === &amp;quot;A&amp;quot; &amp;amp;&amp;amp; isNodeToTranslate)&lt;br /&gt;
      ) {&lt;br /&gt;
        if (childName !== &amp;quot;NOTRANSLATE&amp;quot;) {&lt;br /&gt;
          child.textContent = parsed.text;&lt;br /&gt;
        }&lt;br /&gt;
        childIndex++;&lt;br /&gt;
        textIndex++;&lt;br /&gt;
      } else if (childName === &amp;quot;NOTRANSLATE&amp;quot;) {&lt;br /&gt;
        childIndex++;&lt;br /&gt;
      } else if (isNodeToTranslate) {&lt;br /&gt;
        element.insertBefore(document.createTextNode(parsed.text), child);&lt;br /&gt;
        textIndex++;&lt;br /&gt;
      } else {&lt;br /&gt;
        child.textContent = &amp;quot;&amp;quot;;&lt;br /&gt;
        childIndex++;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (textIndex &amp;lt; parsedText.length) {&lt;br /&gt;
      const textNode = document.createTextNode(parsedText[textIndex].text);&lt;br /&gt;
      element.appendChild(textNode);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function translateWeapons(weapons) {&lt;br /&gt;
  const characterCreation = document.getElementById(&amp;quot;character-creation&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  for (const weaponInput of characterCreation.elements[&amp;quot;weapon&amp;quot;]) {&lt;br /&gt;
    const weaponTranslation = weapons[weaponInput.value];&lt;br /&gt;
&lt;br /&gt;
    if (weaponTranslation) {&lt;br /&gt;
      weaponInput.parentElement.lastElementChild.textContent =&lt;br /&gt;
        weaponTranslation;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleSpecialIndexes(generalTranslations, specialIndexes) {&lt;br /&gt;
  const specialTranslations = {};&lt;br /&gt;
&lt;br /&gt;
  translation.special = specialTranslations;&lt;br /&gt;
&lt;br /&gt;
  for (const [generalIndex, specialKey] of Object.entries(specialIndexes)) {&lt;br /&gt;
    const translatedValue = generalTranslations[generalIndex];&lt;br /&gt;
&lt;br /&gt;
    if (translatedValue) {&lt;br /&gt;
      specialTranslations[specialKey] = translatedValue;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  translation.mapping = {&lt;br /&gt;
    &amp;quot;Demi-humain&amp;quot;: specialTranslations.halfHuman,&lt;br /&gt;
    Mal: specialTranslations.devil,&lt;br /&gt;
    Désert: specialTranslations.desert,&lt;br /&gt;
    Animal: specialTranslations.animal,&lt;br /&gt;
    Orc: specialTranslations.orc,&lt;br /&gt;
    Mystique: specialTranslations.mystic,&lt;br /&gt;
    &amp;quot;Mort-vivant&amp;quot;: specialTranslations.undead,&lt;br /&gt;
    Insecte: specialTranslations.insect,&lt;br /&gt;
    Zodiaque: specialTranslations.zodiac,&lt;br /&gt;
    &amp;quot;Aucun type&amp;quot;: specialTranslations.noType,&lt;br /&gt;
    Mêlée: specialTranslations.melee,&lt;br /&gt;
    Flèche: specialTranslations.arrow,&lt;br /&gt;
    Magique: specialTranslations.magic,&lt;br /&gt;
    DC: specialTranslations.skill,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function translateTitle() {&lt;br /&gt;
  const translatedTitle = translation.special.pageTitle;&lt;br /&gt;
&lt;br /&gt;
  if (translatedTitle) {&lt;br /&gt;
    document.querySelector(&amp;quot;h1&amp;quot;).textContent = translatedTitle;&lt;br /&gt;
    document.querySelector(&amp;quot;ul.subpage&amp;quot;).lastElementChild.textContent =&lt;br /&gt;
      translatedTitle;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function translateSummary(attempts = 5) {&lt;br /&gt;
  const tocContainer = document.getElementById(&amp;quot;toc&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (!tocContainer) {&lt;br /&gt;
    if (attempts &amp;gt; 0) {&lt;br /&gt;
      console.log(`Translating summary... Attempts left: ${attempts}`);&lt;br /&gt;
      setTimeout(() =&amp;gt; translateSummary(attempts - 1), 1000);&lt;br /&gt;
    }&lt;br /&gt;
    return;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  const { toc, hide } = translation.special;&lt;br /&gt;
&lt;br /&gt;
  const heading = tocContainer.querySelector(&amp;quot;h2&amp;quot;);&lt;br /&gt;
  const toggleLink = tocContainer.querySelector(&amp;quot;a.togglelink&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (heading) heading.textContent = toc;&lt;br /&gt;
  if (toggleLink) toggleLink.textContent = hide;&lt;br /&gt;
&lt;br /&gt;
  for (const link of tocContainer.querySelectorAll(&amp;quot;ul a&amp;quot;)) {&lt;br /&gt;
    const hash = link.hash.substring(1);&lt;br /&gt;
    const title = document.getElementById(hash);&lt;br /&gt;
&lt;br /&gt;
    if (title) {&lt;br /&gt;
      const toctext = link.querySelector(&amp;quot;span.toctext&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
      if (toctext?.firstElementChild) {&lt;br /&gt;
        toctext.firstElementChild.textContent = title.textContent;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function translateDefaultText(defaultText) {&lt;br /&gt;
  const specialTranslations = translation.special;&lt;br /&gt;
&lt;br /&gt;
  for (const key of Object.keys(defaultText)) {&lt;br /&gt;
    if (specialTranslations.hasOwnProperty(key)) {&lt;br /&gt;
      defaultText[key] = specialTranslations[key];&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function translatePage(defaultText, currentLanguage) {&lt;br /&gt;
  const mwContent = document.querySelector(&amp;quot;.mw-content-ltr&amp;quot;);&lt;br /&gt;
  const { general, weapons } = translation;&lt;br /&gt;
  const specialIndexes = {&lt;br /&gt;
    471: &amp;quot;placeholder&amp;quot;,&lt;br /&gt;
    473: &amp;quot;boss&amp;quot;,&lt;br /&gt;
    474: &amp;quot;pageTitle&amp;quot;,&lt;br /&gt;
    475: &amp;quot;toc&amp;quot;,&lt;br /&gt;
    476: &amp;quot;hide&amp;quot;,&lt;br /&gt;
    502: &amp;quot;unsavedWarning&amp;quot;,&lt;br /&gt;
    503: &amp;quot;deleteWarning&amp;quot;,&lt;br /&gt;
    504: &amp;quot;pseudo&amp;quot;,&lt;br /&gt;
    481: &amp;quot;damage&amp;quot;,&lt;br /&gt;
    505: &amp;quot;percentage&amp;quot;,&lt;br /&gt;
    506: &amp;quot;miss&amp;quot;,&lt;br /&gt;
    507: &amp;quot;normalHit&amp;quot;,&lt;br /&gt;
    508: &amp;quot;criticalHit&amp;quot;,&lt;br /&gt;
    509: &amp;quot;piercingHit&amp;quot;,&lt;br /&gt;
    510: &amp;quot;criticalPiercingHit&amp;quot;,&lt;br /&gt;
    511: &amp;quot;damageRepartition&amp;quot;,&lt;br /&gt;
    512: &amp;quot;averageDamage&amp;quot;,&lt;br /&gt;
    513: &amp;quot;damageAugmentation&amp;quot;,&lt;br /&gt;
    514: &amp;quot;bonusVariationTitle&amp;quot;,&lt;br /&gt;
    489: &amp;quot;halfHuman&amp;quot;,&lt;br /&gt;
    490: &amp;quot;devil&amp;quot;,&lt;br /&gt;
    491: &amp;quot;desert&amp;quot;,&lt;br /&gt;
    492: &amp;quot;animal&amp;quot;,&lt;br /&gt;
    493: &amp;quot;orc&amp;quot;,&lt;br /&gt;
    494: &amp;quot;mystic&amp;quot;,&lt;br /&gt;
    495: &amp;quot;undead&amp;quot;,&lt;br /&gt;
    496: &amp;quot;insect&amp;quot;,&lt;br /&gt;
    497: &amp;quot;zodiac&amp;quot;,&lt;br /&gt;
    515: &amp;quot;noType&amp;quot;,&lt;br /&gt;
    498: &amp;quot;melee&amp;quot;,&lt;br /&gt;
    499: &amp;quot;arrow&amp;quot;,&lt;br /&gt;
    500: &amp;quot;magic&amp;quot;,&lt;br /&gt;
    516: &amp;quot;skill&amp;quot;,&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  translateText(general);&lt;br /&gt;
  translateWeapons(weapons);&lt;br /&gt;
  handleSpecialIndexes(general, specialIndexes);&lt;br /&gt;
  translateTitle();&lt;br /&gt;
  translateSummary();&lt;br /&gt;
  translateDefaultText(defaultText);&lt;br /&gt;
&lt;br /&gt;
  if (mwContent) {&lt;br /&gt;
    mwContent.setAttribute(&amp;quot;lang&amp;quot;, currentLanguage);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getDefaultText() {&lt;br /&gt;
  return {&lt;br /&gt;
    unsavedWarning:&lt;br /&gt;
      &amp;quot;Voulez-vous continuer ? Les dernières modifications ne seront pas sauvegardées.&amp;quot;,&lt;br /&gt;
    deleteWarning:&lt;br /&gt;
      &amp;quot;Voulez-vous vraiment supprimer définitivement le personnage [[]] ?&amp;quot;,&lt;br /&gt;
    pseudo: &amp;quot;Pseudo&amp;quot;,&lt;br /&gt;
    damage: &amp;quot;Dégâts&amp;quot;,&lt;br /&gt;
    percentage: &amp;quot;Pourcentage&amp;quot;,&lt;br /&gt;
    miss: &amp;quot;Miss&amp;quot;,&lt;br /&gt;
    normalHit: &amp;quot;Coup classique&amp;quot;,&lt;br /&gt;
    criticalHit: &amp;quot;Coup critique&amp;quot;,&lt;br /&gt;
    piercingHit: &amp;quot;Coup perçant&amp;quot;,&lt;br /&gt;
    criticalPiercingHit: &amp;quot;Coup critique perçant&amp;quot;,&lt;br /&gt;
    damageRepartition: &amp;quot;Distribution des dégâts&amp;quot;,&lt;br /&gt;
    averageDamage: &amp;quot;Dégâts moyens&amp;quot;,&lt;br /&gt;
    damageAugmentation: &amp;quot;Augmentation des dégâts&amp;quot;,&lt;br /&gt;
    bonusVariationTitle:&lt;br /&gt;
      &amp;quot;Évolution des dégâts moyens[[]]par rapport à la valeur d'un bonus&amp;quot;,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setLanguage(radios, lang, url, reload = false) {&lt;br /&gt;
  url.searchParams.set(&amp;quot;lang&amp;quot;, lang);&lt;br /&gt;
  updateLastLang(lang);&lt;br /&gt;
&lt;br /&gt;
  if (reload) {&lt;br /&gt;
    window.location.href = url.toString();&lt;br /&gt;
  } else {&lt;br /&gt;
    radios.value = lang;&lt;br /&gt;
    history.replaceState(null, &amp;quot;&amp;quot;, url);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getCurrentLanguage(defaultLang) {&lt;br /&gt;
  const url = new URL(window.location.href);&lt;br /&gt;
  const URLlang = url.searchParams.get(&amp;quot;lang&amp;quot;);&lt;br /&gt;
  const lastLang = getLastLang();&lt;br /&gt;
  const browserLang = navigator.language.split(&amp;quot;-&amp;quot;)[0];&lt;br /&gt;
  const languageSelection = document.getElementById(&amp;quot;language-selection&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (!languageSelection) {&lt;br /&gt;
    return defaultLang;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  const radios = languageSelection.elements[&amp;quot;country&amp;quot;];&lt;br /&gt;
&lt;br /&gt;
  if (!radios) {&lt;br /&gt;
    return defaultLang;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  languageSelection.addEventListener(&amp;quot;change&amp;quot;, changeLanguage);&lt;br /&gt;
&lt;br /&gt;
  function changeLanguage(event) {&lt;br /&gt;
    const newLang = event.target.value;&lt;br /&gt;
    const newUrl = new URL(window.location.href);&lt;br /&gt;
    setLanguage(radios, newLang, newUrl, true);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  const allowedLanguages = Array.from(radios).map((input) =&amp;gt; input.value);&lt;br /&gt;
&lt;br /&gt;
  for (const lang of [URLlang, lastLang, browserLang]) {&lt;br /&gt;
    if (allowedLanguages.includes(lang)) {&lt;br /&gt;
      setLanguage(radios, lang, url);&lt;br /&gt;
      return lang;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return defaultLang;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadStyle(src) {&lt;br /&gt;
  var link = document.createElement(&amp;quot;link&amp;quot;);&lt;br /&gt;
  link.href = src;&lt;br /&gt;
  link.rel = &amp;quot;stylesheet&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  document.head.appendChild(link);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
async function addScript(src) {&lt;br /&gt;
  return new Promise((resolve, reject) =&amp;gt; {&lt;br /&gt;
    const script = document.createElement(&amp;quot;script&amp;quot;);&lt;br /&gt;
    script.src = src;&lt;br /&gt;
    script.async = true;&lt;br /&gt;
&lt;br /&gt;
    script.onload = () =&amp;gt; resolve();&lt;br /&gt;
    script.onerror = () =&amp;gt; reject(new Error(`Failed to load script: ${src}`));&lt;br /&gt;
&lt;br /&gt;
    document.head.appendChild(script);&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
(async function () {&lt;br /&gt;
  const basePath = &amp;quot;/index.php?title=Utilisateur:Ankhseram/&amp;quot;;&lt;br /&gt;
  const dataScript = `${basePath}WeaponsAndMonsters.js&amp;amp;action=raw&amp;amp;ctype=text/javascript`;&lt;br /&gt;
  const simulatorStyle = `${basePath}SimulatorStyle.css&amp;amp;action=raw&amp;amp;ctype=text/css`;&lt;br /&gt;
  const chartLibrary = &amp;quot;https://cdn.jsdelivr.net/npm/chart.js&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  const defaultLang = &amp;quot;fr&amp;quot;;&lt;br /&gt;
  const defaultText = getDefaultText();&lt;br /&gt;
  const currentLanguage = getCurrentLanguage(defaultLang);&lt;br /&gt;
&lt;br /&gt;
  loadStyle(simulatorStyle);&lt;br /&gt;
&lt;br /&gt;
  let translationScript;&lt;br /&gt;
&lt;br /&gt;
  if (currentLanguage !== defaultLang) {&lt;br /&gt;
    translationScript = `${basePath}Calculator/${currentLanguage}.js&amp;amp;action=raw&amp;amp;ctype=text/javascript`;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  const scriptsToLoad = [addScript(chartLibrary), addScript(dataScript)];&lt;br /&gt;
&lt;br /&gt;
  if (translationScript) {&lt;br /&gt;
    scriptsToLoad.push(addScript(translationScript));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  await Promise.all(scriptsToLoad);&lt;br /&gt;
&lt;br /&gt;
  if (translationScript) {&lt;br /&gt;
    translatePage(defaultText, currentLanguage);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  const [characters, battle] = createDamageCalculatorInformation(&lt;br /&gt;
    defaultLang,&lt;br /&gt;
    currentLanguage,&lt;br /&gt;
    defaultText&lt;br /&gt;
  );&lt;br /&gt;
  characterManagement(characters, battle);&lt;br /&gt;
  monsterManagement(characters, battle);&lt;br /&gt;
  updateBattleChoice(characters, battle.battleChoice);&lt;br /&gt;
  createBattle(characters, battle);&lt;br /&gt;
})();&lt;/div&gt;</summary>
		<author><name>Dexter</name></author>
		
	</entry>
	<entry>
		<id>https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Common.css&amp;diff=107428</id>
		<title>MediaWiki:Common.css</title>
		<link rel="alternate" type="text/html" href="https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Common.css&amp;diff=107428"/>
		<updated>2025-05-29T20:57:36Z</updated>

		<summary type="html">&lt;p&gt;Dexter : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;/* Le CSS placé ici sera chargé sur toutes les pages */&lt;br /&gt;
&lt;br /&gt;
html {&lt;br /&gt;
  scroll-behavior: smooth;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
  body {&lt;br /&gt;
    background-image: url('https://fr-wiki.metin2.gameforge.com/images/b/bf/Fondhalloween.png');&lt;br /&gt;
  }&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
body {&lt;br /&gt;
  background-image: url(&amp;quot;https://fr-wiki.metin2.gameforge.com/images/1/15/Fond2015.jpg&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#mw-content ul {&lt;br /&gt;
  margin-bottom: 0.3em;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#mw-content ol {&lt;br /&gt;
  list-style: none;&lt;br /&gt;
  counter-reset: custom-counter;&lt;br /&gt;
  margin: 0.3em 0 0.3em 1.6em;&lt;br /&gt;
  padding: 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
ol li {&lt;br /&gt;
  padding: 0;&lt;br /&gt;
  padding-left: 5px;&lt;br /&gt;
  counter-increment: custom-counter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
ol li::marker {&lt;br /&gt;
  content: counter(custom-counter) &amp;quot;.  &amp;quot;;&lt;br /&gt;
  font-weight: bold;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
td,&lt;br /&gt;
th {&lt;br /&gt;
  padding: 2px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.map span.mw-collapsible-toggle {&lt;br /&gt;
  padding-right: 10px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
table.map a.mw-collapsible-text,&lt;br /&gt;
.prettytable &amp;gt; span.mw-collapsible-toggle,&lt;br /&gt;
.prettytable &amp;gt; span.mw-collapsible-toggle &amp;gt; a {&lt;br /&gt;
  color: #ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.boxesheaderbackground,&lt;br /&gt;
.cadre &amp;gt; div:first-child {&lt;br /&gt;
  background: repeat&lt;br /&gt;
    url(&amp;quot;https://fr-wiki.metin2.gameforge.com/images/a/a7/Boxheaderbrown.png&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#mw-content .heading-wrapper &amp;gt; h2 {&lt;br /&gt;
  border-image-slice: 5 0 4 0 fill;&lt;br /&gt;
  border-image-width: auto;&lt;br /&gt;
  border-image-repeat: repeat;&lt;br /&gt;
  border-image-source: url(&amp;quot;https://fr-wiki.metin2.gameforge.com/images/a/a7/Boxheaderbrown.png&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.cadre {&lt;br /&gt;
  border: 1px solid #2f1d1f;&lt;br /&gt;
  border-radius: 15px 0;&lt;br /&gt;
  width: 100%;&lt;br /&gt;
  box-shadow: 3px 3px 9px 0px #544e41;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.cadre &amp;gt; div:first-child {&lt;br /&gt;
  text-align: center;&lt;br /&gt;
  color: white;&lt;br /&gt;
  line-height: 25px;&lt;br /&gt;
  overflow: hidden;&lt;br /&gt;
  border-top-left-radius: 15px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#mw-content .fondfenetre,&lt;br /&gt;
.sous-titre,&lt;br /&gt;
table.pretty-table th {&lt;br /&gt;
  background: url(&amp;quot;https://fr-wiki.metin2.gameforge.com/images/8/89/Fondfenetre.png&amp;quot;)&lt;br /&gt;
    repeat;&lt;br /&gt;
  color: white;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
table.pretty-table td {&lt;br /&gt;
  padding: 5px 10px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
table.pretty-table th {&lt;br /&gt;
  padding: 2px 10px;&lt;br /&gt;
  font-weight: normal;&lt;br /&gt;
  font-size: 1.1em;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
table.pretty-table tbody &amp;gt; *:nth-child(2n + 1) &amp;gt; td {&lt;br /&gt;
  background: rgba(0, 0, 0, 0.1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
table.pretty-table tr:hover {&lt;br /&gt;
  background: rgba(0, 0, 0, 0.05);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
table.pretty-table tr:first-child &amp;gt; th:first-child {&lt;br /&gt;
  border-radius: 8px 0 0 0;&lt;br /&gt;
  overflow: hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
table.pretty-table caption {&lt;br /&gt;
  margin-top: 10px;&lt;br /&gt;
  font-weight: bold;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.fondfenetre a,&lt;br /&gt;
.fondfenetre span,&lt;br /&gt;
table.pretty-table th a,&lt;br /&gt;
table.pretty-table th span {&lt;br /&gt;
  color: white;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
table.pretty-table.sortable th.headerSort {&lt;br /&gt;
  background-image: url(&amp;quot;data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 width=%2221%22 height=%229%22 viewBox=%220 0 21 9%22%3E %3Cpath fill=%22%23fff%22 d=%22M14.5 5l-4 4-4-4zM14.5 4l-4-4-4 4z%22/%3E %3C/svg%3E&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
table.pretty-table.sortable th.headerSortUp {&lt;br /&gt;
  background-image: url(&amp;quot;data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 width=%2221%22 height=%224%22 viewBox=%220 0 21 4%22%3E %3Cpath fill=%22%23fff%22 d=%22M6.5 4l4-4 4 4z%22/%3E %3C/svg%3E&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
table.pretty-table.sortable th.headerSortDown {&lt;br /&gt;
  background-image: url(&amp;quot;data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 width=%2221%22 height=%224%22 viewBox=%220 0 21 4%22%3E %3Cpath fill=%22%23fff%22 d=%22M14.5 0l-4 4-4-4z%22/%3E %3C/svg%3E&amp;quot;)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
table.sticky-header-row thead tr {&lt;br /&gt;
  position: sticky;&lt;br /&gt;
  top: 0;&lt;br /&gt;
  z-index: 10;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
table.sticky-header-column th:first-child {&lt;br /&gt;
  position: sticky;&lt;br /&gt;
  left: 0;&lt;br /&gt;
  z-index: 20;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sous-titre {&lt;br /&gt;
  max-width: 180px;&lt;br /&gt;
  border: 1px solid black;&lt;br /&gt;
  border-radius: 8px;&lt;br /&gt;
  color: white;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.modeleAnnonce {&lt;br /&gt;
  border-image: url(&amp;quot;https://fr-wiki.metin2.gameforge.com/images/f/fb/Modeleannonce.png&amp;quot;)&lt;br /&gt;
    17 35 3 fill / auto / 0 repeat;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.container {&lt;br /&gt;
  display: flex;&lt;br /&gt;
  flex-direction: row;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.monster-card {&lt;br /&gt;
  border: 1px black solid;&lt;br /&gt;
  padding: 5px;&lt;br /&gt;
  max-width: 400px;&lt;br /&gt;
  box-sizing: border-box;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.monster-card &amp;gt; :first-child {&lt;br /&gt;
  display: flex;&lt;br /&gt;
  justify-content: space-between;&lt;br /&gt;
  margin-bottom: 5px;&lt;br /&gt;
  line-height: 25px;&lt;br /&gt;
  padding: 0 5px;&lt;br /&gt;
  background: none;&lt;br /&gt;
  background-color: black;&lt;br /&gt;
  color: white;&lt;br /&gt;
  white-space: nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.monster-card &amp;gt; :first-child a {&lt;br /&gt;
  color: white;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.monster-card &amp;gt; :nth-child(2) {&lt;br /&gt;
  display: flex;&lt;br /&gt;
  justify-content: space-between;&lt;br /&gt;
  margin-bottom: 5px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.monster-card &amp;gt; :nth-child(3) {&lt;br /&gt;
  background: rgba(0, 0, 0, 0.1);&lt;br /&gt;
  display: grid;&lt;br /&gt;
  justify-content: center;&lt;br /&gt;
  align-items: start;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
button.brown {&lt;br /&gt;
  background: #651e10;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
button.brown-transparent {&lt;br /&gt;
  background: #651e10cc;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
button.brown:hover,&lt;br /&gt;
button.brown:focus {&lt;br /&gt;
  background: #551a0e;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
button.red {&lt;br /&gt;
  background: #ef4444;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
button.red:hover,&lt;br /&gt;
button.red:focus {&lt;br /&gt;
  background: #b91c1c;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
button:active {&lt;br /&gt;
  opacity: 0.8;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.button {&lt;br /&gt;
  border: 2px solid grey;&lt;br /&gt;
  padding: 0 12px;&lt;br /&gt;
  line-height: 25px;&lt;br /&gt;
  border-radius: 16px;&lt;br /&gt;
  background: rgba(234, 234, 234);&lt;br /&gt;
  cursor: pointer;&lt;br /&gt;
  display: inline-block;&lt;br /&gt;
  position: relative;&lt;br /&gt;
  user-select: none;&lt;br /&gt;
  white-space: nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.button:hover {&lt;br /&gt;
  background: transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.modal {&lt;br /&gt;
  opacity: 0;&lt;br /&gt;
  visibility: hidden;&lt;br /&gt;
  transform: scale(1.1);&lt;br /&gt;
  transition: visibility 0s linear 0.25s, opacity 0.25s 0s, transform 0.25s;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.close-button {&lt;br /&gt;
  transition: color 0.2s linear, background-color 0.2s linear;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.close-button:hover {&lt;br /&gt;
  background-color: red;&lt;br /&gt;
  color: #ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.show-modal {&lt;br /&gt;
  opacity: 1;&lt;br /&gt;
  visibility: visible;&lt;br /&gt;
  transform: scale(1);&lt;br /&gt;
  transition: visibility 0s linear 0s, opacity 0.25s 0s, transform 0.25s;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.cacheOrdi,&lt;br /&gt;
.gen-active {&lt;br /&gt;
  display: block;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.texte-long,&lt;br /&gt;
.texte-long-2 {&lt;br /&gt;
  text-overflow: ellipsis;&lt;br /&gt;
  white-space: nowrap;&lt;br /&gt;
  overflow: hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.texte-long:hover,&lt;br /&gt;
.texte-long-2:hover {&lt;br /&gt;
  white-space: normal;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.shop-img img {&lt;br /&gt;
  height: auto;&lt;br /&gt;
  width: auto;&lt;br /&gt;
  max-height: 130px;&lt;br /&gt;
  max-width: 130px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#mw-content .soulignement &amp;gt; a:link {&lt;br /&gt;
  text-decoration: none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* Remplacer popInfo et popContenu par pop-parent et pop-content */&lt;br /&gt;
.popContenu {&lt;br /&gt;
  display: inline-block;&lt;br /&gt;
  transition: all 0.4s ease;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.popInfo:hover .popContenu {&lt;br /&gt;
  opacity: 1 !important;&lt;br /&gt;
  transition: all 0.4s ease;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.pop-parent:hover .pop-content {&lt;br /&gt;
  opacity: 1;&lt;br /&gt;
  transition: opacity 0.4s ease;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.pop-content {&lt;br /&gt;
  opacity: 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.cadreFenetre,&lt;br /&gt;
.game-window {&lt;br /&gt;
  border: solid;&lt;br /&gt;
  border-image: url(&amp;quot;https://fr-wiki.metin2.gameforge.com/images/1/11/Cadrefenetre.png&amp;quot;)&lt;br /&gt;
    11 fill / auto / 0 repeat;&lt;br /&gt;
  padding: 10px;&lt;br /&gt;
  backdrop-filter: blur(4px);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tabber-active.button {&lt;br /&gt;
  background: rgba(75, 85, 95);&lt;br /&gt;
  color: white;&lt;br /&gt;
  border: 2px solid rgba(75, 85, 95);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
ul.subpage {&lt;br /&gt;
  display: flex;&lt;br /&gt;
  list-style: none;&lt;br /&gt;
  margin: 0 0 10px;&lt;br /&gt;
  padding: 0;&lt;br /&gt;
  background: rgba(81, 36, 16, 0.3);&lt;br /&gt;
  overflow: hidden;&lt;br /&gt;
  line-height: 30px;&lt;br /&gt;
  white-space: nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.subpage a {&lt;br /&gt;
  padding-left: 20px;&lt;br /&gt;
  background: #512410;&lt;br /&gt;
  display: inline-block;&lt;br /&gt;
  line-height: 30px;&lt;br /&gt;
  position: relative;&lt;br /&gt;
  color: #f1de8e;&lt;br /&gt;
  cursor: pointer;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.subpage a:before,&lt;br /&gt;
.subpage a:after {&lt;br /&gt;
  content: &amp;quot;&amp;quot;;&lt;br /&gt;
  position: absolute;&lt;br /&gt;
  width: 0;&lt;br /&gt;
  height: 0;&lt;br /&gt;
  right: 0;&lt;br /&gt;
  padding: 1px 0;&lt;br /&gt;
  border-top: 14px solid transparent;&lt;br /&gt;
  border-bottom: 14px solid transparent;&lt;br /&gt;
  border-left: 14px solid white;&lt;br /&gt;
  transform: translate(14px);&lt;br /&gt;
  z-index: 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.subpage a:after {&lt;br /&gt;
  border-left: 14px solid #512410;&lt;br /&gt;
  transform: translate(13px);&lt;br /&gt;
  z-index: 2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.subpage &amp;gt; li:last-child {&lt;br /&gt;
  padding-left: 20px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
ul.subpage &amp;gt; li:first-child {&lt;br /&gt;
  flex-shrink: 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
ul.subpage &amp;gt; li:first-child &amp;gt; a {&lt;br /&gt;
  height: 100%;&lt;br /&gt;
  display: flex;&lt;br /&gt;
  align-items: center;&lt;br /&gt;
  padding-left: 10px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
ul.subpage &amp;gt; li &amp;gt; a:hover {&lt;br /&gt;
  background: #9d5b37;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
ul.subpage &amp;gt; li &amp;gt; a:hover:after {&lt;br /&gt;
  border-left-color: #9d5b37;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.image-sizing img,&lt;br /&gt;
.image-sizing-200 img,&lt;br /&gt;
.image-sizing-none img {&lt;br /&gt;
  height: auto;&lt;br /&gt;
  width: auto;&lt;br /&gt;
  max-height: 300px;&lt;br /&gt;
  max-width: 100%;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.image-sizing-200 img {&lt;br /&gt;
  max-height: 200px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.image-sizing-none img {&lt;br /&gt;
  max-height: none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
div.ul-res ul {&lt;br /&gt;
  margin: 0;&lt;br /&gt;
  list-style: none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tab-glob {&lt;br /&gt;
  display: flex;&lt;br /&gt;
  flex-direction: row;&lt;br /&gt;
  margin: 10px 0;&lt;br /&gt;
  column-gap: 2px;&lt;br /&gt;
  align-items: flex-start;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tab-glob &amp;gt; :first-child {&lt;br /&gt;
  display: grid;&lt;br /&gt;
  grid-template-columns: max-content;&lt;br /&gt;
  row-gap: 2px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tab-glob &amp;gt; :first-child &amp;gt; * {&lt;br /&gt;
  border: 1px black solid;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tab-glob &amp;gt; :first-child &amp;gt; *:not(.fondfenetre) {&lt;br /&gt;
  font-weight: bold;&lt;br /&gt;
  display: flex;&lt;br /&gt;
  justify-content: center;&lt;br /&gt;
  align-items: center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tab-glob &amp;gt; :nth-child(2) {&lt;br /&gt;
  width: 100%;&lt;br /&gt;
  overflow-x: auto;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tab-glob &amp;gt; :nth-child(2) &amp;gt; :first-child {&lt;br /&gt;
  display: grid;&lt;br /&gt;
  grid-template-columns: repeat(10, minmax(75px, 1fr));&lt;br /&gt;
  gap: 2px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tab-glob &amp;gt; :nth-child(2) &amp;gt; :first-child &amp;gt; * {&lt;br /&gt;
  border: 1px black solid;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tab-glob &amp;gt; :nth-child(2) &amp;gt; :first-child &amp;gt; :not(.fondfenetre) {&lt;br /&gt;
  display: flex;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tab-glob &amp;gt; :nth-child(2) &amp;gt; :first-child &amp;gt; :not(.fondfenetre) &amp;gt; * {&lt;br /&gt;
  margin: auto;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.list-equip {&lt;br /&gt;
  padding: 5px;&lt;br /&gt;
  border: 1px solid #2f1d1f;&lt;br /&gt;
  display: flex;&lt;br /&gt;
  flex-direction: column;&lt;br /&gt;
  align-items: center;&lt;br /&gt;
  gap: 5px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.list-equip &amp;gt; :first-child {&lt;br /&gt;
  width: 100%;&lt;br /&gt;
  line-height: 25px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.list-equip &amp;gt; :first-child &amp;gt; * {&lt;br /&gt;
  padding: 0 5px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.fabrication {&lt;br /&gt;
  position: relative;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.fabrication &amp;gt; * {&lt;br /&gt;
  position: absolute;&lt;br /&gt;
  top: -188px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.fabrication &amp;gt; .bottom-fab,&lt;br /&gt;
.fabrication &amp;gt; .bottom-fab ~ * {&lt;br /&gt;
  top: -58px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.fabrication &amp;gt; * &amp;gt; *:nth-child(2) {&lt;br /&gt;
  position: relative;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.fabrication &amp;gt; * &amp;gt; *:nth-child(2) &amp;gt; * {&lt;br /&gt;
  position: absolute;&lt;br /&gt;
  top: -18px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.fabrication &amp;gt; * &amp;gt; *:nth-child(n + 3) {&lt;br /&gt;
  position: absolute;&lt;br /&gt;
  top: 100px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.info-boutique ul {&lt;br /&gt;
  list-style-image: none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.info-boutique p:last-child {&lt;br /&gt;
  margin-bottom: 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
kbd {&lt;br /&gt;
  background-color: #eee;&lt;br /&gt;
  border-radius: 3px;&lt;br /&gt;
  border: 1px solid #b4b4b4;&lt;br /&gt;
  box-shadow: 0 1px 1px rgb(0 0 0 / 20%), 0 2px 0 0 rgb(255 255 255 / 70%) inset;&lt;br /&gt;
  color: #333;&lt;br /&gt;
  display: inline-block;&lt;br /&gt;
  font-size: 0.85em;&lt;br /&gt;
  font-weight: 700;&lt;br /&gt;
  line-height: 1;&lt;br /&gt;
  padding: 2px 4px;&lt;br /&gt;
  white-space: nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.top-button {&lt;br /&gt;
  display: flex;&lt;br /&gt;
  justify-content: center;&lt;br /&gt;
  align-items: center;&lt;br /&gt;
  opacity: 0;&lt;br /&gt;
  cursor: pointer;&lt;br /&gt;
  position: fixed;&lt;br /&gt;
  bottom: 10px;&lt;br /&gt;
  right: 10px;&lt;br /&gt;
  width: 32px;&lt;br /&gt;
  height: 32px;&lt;br /&gt;
  background: linear-gradient(&lt;br /&gt;
    180deg,&lt;br /&gt;
    rgba(124, 200, 65, 1) 0%,&lt;br /&gt;
    rgba(113, 161, 85, 1) 50%,&lt;br /&gt;
    rgba(64, 117, 39, 1) 50%,&lt;br /&gt;
    rgba(46, 97, 31, 1) 100%&lt;br /&gt;
  );&lt;br /&gt;
  border: 1px solid #d0af52;&lt;br /&gt;
  box-shadow: 1px 1px 2px #000, inset 1px 1px #090200, inset -1px -1px #090200;&lt;br /&gt;
  transform: translateY(100px);&lt;br /&gt;
  transition: all 0.5s ease;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.top-button:after {&lt;br /&gt;
  content: &amp;quot;&amp;quot;;&lt;br /&gt;
  height: 32px;&lt;br /&gt;
  width: 32px;&lt;br /&gt;
  background-image: url(&amp;quot;data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fffacb' height='32' viewBox='0 -960 960 960' width='32'%3E%3Cpath d='m296-345-56-56 240-240 240 240-56 56-184-184-184 184Z'/%3E%3C/svg%3E&amp;quot;);&lt;br /&gt;
  background-repeat: no-repeat;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.show-button {&lt;br /&gt;
  opacity: 1;&lt;br /&gt;
  transform: translateY(0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.ul-row ul {&lt;br /&gt;
  display: flex;&lt;br /&gt;
  column-gap: 30px;&lt;br /&gt;
  flex-wrap: wrap;&lt;br /&gt;
  overflow: hidden;&lt;br /&gt;
  margin: 0;&lt;br /&gt;
  list-style-image: none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.flex {&lt;br /&gt;
  display: flex;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#catlinks {&lt;br /&gt;
  margin-top: 10px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.improved-collapsible &amp;gt; .mw-collapsible-toggle {&lt;br /&gt;
  grid-area: 1 / -1;&lt;br /&gt;
  display: flex;&lt;br /&gt;
  justify-content: flex-end;&lt;br /&gt;
  align-items: center;&lt;br /&gt;
  float: initial;&lt;br /&gt;
  z-index: 1;&lt;br /&gt;
  padding-right: 5px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.improved-collapsible .mw-collapsible-toggle:before {&lt;br /&gt;
  content: &amp;quot;&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.improved-collapsible .mw-collapsible-text {&lt;br /&gt;
  display: none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.improved-collapsible .mw-collapsible-toggle:after {&lt;br /&gt;
  width: 32px;&lt;br /&gt;
  height: 32px;&lt;br /&gt;
  content: &amp;quot;&amp;quot;;&lt;br /&gt;
  background-image: url(&amp;quot;data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23000000' height='32' viewBox='0 -960 960 960' width='32'%3E%3Cpath d='M480-345 240-585l56-56 184 184 184-184 56 56-240 240Z'/%3E%3C/svg%3E&amp;quot;);&lt;br /&gt;
  background-repeat: no-repeat;&lt;br /&gt;
  transition: transform 0.2s ease-in-out;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.improved-collapsible .mw-collapsible-toggle-expanded:after {&lt;br /&gt;
  transform: rotate(-180deg);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tooltip-icon {&lt;br /&gt;
  background-image: url(&amp;quot;data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' height='24' viewBox='0 -960 960 960' width='24'%3E%3Cpath d='M443-285h75v-234h-75v234Zm36.895-311Q496-596 507-606.895q11-10.894 11-27Q518-650 507.105-661q-10.894-11-27-11Q464-672 453-661.105q-11 10.894-11 27Q442-618 452.895-607q10.894 11 27 11ZM480-90q-80.907 0-152.065-30.763-71.159-30.763-123.797-83.5Q151.5-257 120.75-328.087 90-399.175 90-480q0-80.907 30.763-152.065 30.763-71.159 83.5-123.797Q257-808.5 328.087-839.25 399.175-870 480-870q80.907 0 152.065 30.763 71.159 30.763 123.797 83.5Q808.5-703 839.25-631.913 870-560.825 870-480q0 80.907-30.763 152.065-30.763 71.159-83.5 123.797Q703-151.5 631.913-120.75 560.825-90 480-90Zm0-75q131.5 0 223.25-91.75T795-480q0-131.5-91.75-223.25T480-795q-131.5 0-223.25 91.75T165-480q0 131.5 91.75 223.25T480-165Zm0-315Z'/%3E%3C/svg%3E&amp;quot;);&lt;br /&gt;
  background-repeat: no-repeat;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tooltip-info {&lt;br /&gt;
  position: absolute;&lt;br /&gt;
  bottom: calc(100% + 8px);&lt;br /&gt;
  left: 50%;&lt;br /&gt;
  transform: translateX(-50%);&lt;br /&gt;
  max-width: 290px;&lt;br /&gt;
  width: max-content;&lt;br /&gt;
  z-index: 50;&lt;br /&gt;
  opacity: 0;&lt;br /&gt;
  visibility: hidden;&lt;br /&gt;
  transition: opacity 0.2s ease, visibility 0.2s ease;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tooltip-info:after {&lt;br /&gt;
  content: &amp;quot;&amp;quot;;&lt;br /&gt;
  border: 8px solid transparent;&lt;br /&gt;
  border-top-color: inherit;&lt;br /&gt;
  position: absolute;&lt;br /&gt;
  left: calc(50% - 8px);&lt;br /&gt;
  top: 100%;&lt;br /&gt;
  z-index: 50;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tooltip-icon:hover &amp;gt; .tooltip-info {&lt;br /&gt;
  opacity: 1;&lt;br /&gt;
  visibility: visible;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
input,&lt;br /&gt;
input[type=&amp;quot;checkbox&amp;quot;],&lt;br /&gt;
select {&lt;br /&gt;
  border: 3px #d0e0e3 solid;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
input[type=&amp;quot;checkbox&amp;quot;] {&lt;br /&gt;
  background-color: white;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
input[type=&amp;quot;checkbox&amp;quot;]:checked {&lt;br /&gt;
  background-color: #19bd94;&lt;br /&gt;
  border: none;&lt;br /&gt;
  position: relative;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
input[type=&amp;quot;checkbox&amp;quot;]:checked:after {&lt;br /&gt;
  content: &amp;quot;&amp;quot;;&lt;br /&gt;
  position: absolute;&lt;br /&gt;
  background: transparent;&lt;br /&gt;
  left: 20%;&lt;br /&gt;
  top: 20%;&lt;br /&gt;
  width: 45%;&lt;br /&gt;
  height: 25%;&lt;br /&gt;
  transform: rotate(-45deg);&lt;br /&gt;
  border: 0.18em white solid;&lt;br /&gt;
  border-top: none;&lt;br /&gt;
  border-right: none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
input:focus,&lt;br /&gt;
select:focus {&lt;br /&gt;
  border: 3px rgb(102, 175, 233) solid;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
input:focus:not([type='checkbox']),&lt;br /&gt;
select:focus {&lt;br /&gt;
  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075),&lt;br /&gt;
    0 0 8px rgba(102, 175, 233, 0.6);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.label-hover label:hover {&lt;br /&gt;
  background-color: rgba(0, 0, 0, 0.1);&lt;br /&gt;
  border-radius: 8px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.cacheTel,&lt;br /&gt;
.tabber-container &amp;gt; :last-child &amp;gt; :not(.tabber-active),&lt;br /&gt;
.tabber-noactive {&lt;br /&gt;
  display: none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes pnj-square {&lt;br /&gt;
  from {&lt;br /&gt;
    background-color: #f80000;&lt;br /&gt;
  }&lt;br /&gt;
  to {&lt;br /&gt;
    background-color: white;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes pnj-circle {&lt;br /&gt;
  from {&lt;br /&gt;
    border-color: #984c48;&lt;br /&gt;
  }&lt;br /&gt;
  to {&lt;br /&gt;
    border-color: white;&lt;br /&gt;
  }&lt;br /&gt;
  from {&lt;br /&gt;
    scale: 1;&lt;br /&gt;
  }&lt;br /&gt;
  to {&lt;br /&gt;
    scale: 0.1;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes loading {&lt;br /&gt;
  0% {&lt;br /&gt;
    transform: scale(1.5);&lt;br /&gt;
  }&lt;br /&gt;
  100% {&lt;br /&gt;
    transform: scale(1);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@media screen and (max-width: 768px) {&lt;br /&gt;
  .texte-long {&lt;br /&gt;
    white-space: normal;&lt;br /&gt;
    overflow: visible;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  .grid2 {&lt;br /&gt;
    grid-template-columns: repeat(2, 1fr) !important;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  .grid3 {&lt;br /&gt;
    grid-template-columns: repeat(3, auto) !important;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  .container {&lt;br /&gt;
    flex-direction: column;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  .cacheTel,&lt;br /&gt;
  .subpage &amp;gt; li:nth-last-child(2) &amp;gt; a {&lt;br /&gt;
    display: block;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  .top-button {&lt;br /&gt;
    background: rgba(0, 0, 0, 0.7);&lt;br /&gt;
    color: #999;&lt;br /&gt;
    border: none;&lt;br /&gt;
    box-shadow: none;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  .top-button::after {&lt;br /&gt;
    background-image: url(&amp;quot;data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23ffffff' height='24' viewBox='0 -960 960 960' width='24'%3E%3Cpath d='M440-80v-647L256-544l-56-56 280-280 280 280-56 57-184-184v647h-80Z'/%3E%3C/svg%3E&amp;quot;);&lt;br /&gt;
    height: 24px;&lt;br /&gt;
    width: 24px;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  .tooltip-icon {&lt;br /&gt;
    position: static;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  .tooltip-info {&lt;br /&gt;
    position: fixed;&lt;br /&gt;
    left: 20px;&lt;br /&gt;
    right: 20px;&lt;br /&gt;
    bottom: 50px;&lt;br /&gt;
    max-width: none;&lt;br /&gt;
    width: auto;&lt;br /&gt;
    transform: none;&lt;br /&gt;
    height: max-content;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  .subpage &amp;gt; li &amp;gt; a,&lt;br /&gt;
  .cacheOrdi,&lt;br /&gt;
  .tooltip-info:after {&lt;br /&gt;
    display: none;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@media screen and (max-width: 340px) {&lt;br /&gt;
  #mw-content {&lt;br /&gt;
    padding-left: 10px;&lt;br /&gt;
    padding-right: 10px;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@media screen and (min-width: 851px) {&lt;br /&gt;
  html {&lt;br /&gt;
    scroll-padding-top: 3.325em;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;/div&gt;</summary>
		<author><name>Dexter</name></author>
		
	</entry>
	<entry>
		<id>https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Common.css&amp;diff=107411</id>
		<title>MediaWiki:Common.css</title>
		<link rel="alternate" type="text/html" href="https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Common.css&amp;diff=107411"/>
		<updated>2025-05-28T19:51:10Z</updated>

		<summary type="html">&lt;p&gt;Dexter : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;/* Le CSS placé ici sera chargé sur toutes les pages */&lt;br /&gt;
&lt;br /&gt;
html {&lt;br /&gt;
  scroll-behavior: smooth;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
  body {&lt;br /&gt;
    background-image: url('https://fr-wiki.metin2.gameforge.com/images/b/bf/Fondhalloween.png');&lt;br /&gt;
  }&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
body {&lt;br /&gt;
  background-image: url(&amp;quot;https://fr-wiki.metin2.gameforge.com/images/1/15/Fond2015.jpg&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#mw-content ul {&lt;br /&gt;
  margin-bottom: 0.3em;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#mw-content ol {&lt;br /&gt;
  list-style: none;&lt;br /&gt;
  counter-reset: custom-counter;&lt;br /&gt;
  margin: 0.3em 0 0.3em 1.6em;&lt;br /&gt;
  padding: 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
ol li {&lt;br /&gt;
  padding: 0;&lt;br /&gt;
  padding-left: 5px;&lt;br /&gt;
  counter-increment: custom-counter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
ol li::marker {&lt;br /&gt;
  content: counter(custom-counter) &amp;quot;.  &amp;quot;;&lt;br /&gt;
  font-weight: bold;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
td,&lt;br /&gt;
th {&lt;br /&gt;
  padding: 2px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.map span.mw-collapsible-toggle {&lt;br /&gt;
  padding-right: 10px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
table.map a.mw-collapsible-text,&lt;br /&gt;
.prettytable &amp;gt; span.mw-collapsible-toggle,&lt;br /&gt;
.prettytable &amp;gt; span.mw-collapsible-toggle &amp;gt; a {&lt;br /&gt;
  color: #ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.boxesheaderbackground,&lt;br /&gt;
.cadre &amp;gt; div:first-child {&lt;br /&gt;
  background: repeat&lt;br /&gt;
    url(&amp;quot;https://fr-wiki.metin2.gameforge.com/images/a/a7/Boxheaderbrown.png&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#mw-content .heading-wrapper &amp;gt; h2 {&lt;br /&gt;
  border-image-slice: 5 0 4 0 fill;&lt;br /&gt;
  border-image-width: auto;&lt;br /&gt;
  border-image-repeat: repeat;&lt;br /&gt;
  border-image-source: url(&amp;quot;https://fr-wiki.metin2.gameforge.com/images/a/a7/Boxheaderbrown.png&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.cadre {&lt;br /&gt;
  border: 1px solid #2f1d1f;&lt;br /&gt;
  border-radius: 15px 0;&lt;br /&gt;
  width: 100%;&lt;br /&gt;
  box-shadow: 3px 3px 9px 0px #544e41;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.cadre &amp;gt; div:first-child {&lt;br /&gt;
  text-align: center;&lt;br /&gt;
  color: white;&lt;br /&gt;
  line-height: 25px;&lt;br /&gt;
  overflow: hidden;&lt;br /&gt;
  border-top-left-radius: 15px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.fondfenetre,&lt;br /&gt;
.sous-titre,&lt;br /&gt;
table.pretty-table th,&lt;br /&gt;
table.pretty-table.sortable &amp;gt; thead &amp;gt; tr {&lt;br /&gt;
  background: url(&amp;quot;https://fr-wiki.metin2.gameforge.com/images/8/89/Fondfenetre.png&amp;quot;)&lt;br /&gt;
    repeat;&lt;br /&gt;
  color: white;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
table.pretty-table td {&lt;br /&gt;
  padding: 5px 10px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
table.pretty-table th {&lt;br /&gt;
  padding: 2px 10px;&lt;br /&gt;
  font-weight: normal;&lt;br /&gt;
  font-size: 1.1em;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
table.pretty-table tbody &amp;gt; *:nth-child(2n + 1) &amp;gt; td {&lt;br /&gt;
  background: rgba(0, 0, 0, 0.1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
table.pretty-table tr:hover {&lt;br /&gt;
  background: rgba(0, 0, 0, 0.05);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
table.pretty-table tr:first-child &amp;gt; th:first-child {&lt;br /&gt;
  border-radius: 8px 0 0 0;&lt;br /&gt;
  overflow: hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
table.pretty-table caption {&lt;br /&gt;
  margin-top: 10px;&lt;br /&gt;
  font-weight: bold;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.fondfenetre a,&lt;br /&gt;
.fondfenetre span,&lt;br /&gt;
table.pretty-table th a,&lt;br /&gt;
table.pretty-table th span {&lt;br /&gt;
  color: white;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
table.pretty-table.sortable th {&lt;br /&gt;
  filter: invert(1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
table.sticky-header-row thead tr {&lt;br /&gt;
  position: sticky;&lt;br /&gt;
  top: 0;&lt;br /&gt;
  z-index: 10;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
table.sticky-header-column th:first-child {&lt;br /&gt;
  position: sticky;&lt;br /&gt;
  left: 0;&lt;br /&gt;
  z-index: 20;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sous-titre {&lt;br /&gt;
  max-width: 180px;&lt;br /&gt;
  border: 1px solid black;&lt;br /&gt;
  border-radius: 8px;&lt;br /&gt;
  color: white;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.modeleAnnonce {&lt;br /&gt;
  border-image: url(&amp;quot;https://fr-wiki.metin2.gameforge.com/images/f/fb/Modeleannonce.png&amp;quot;)&lt;br /&gt;
    17 35 3 fill / auto / 0 repeat;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.container {&lt;br /&gt;
  display: flex;&lt;br /&gt;
  flex-direction: row;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.monster-card {&lt;br /&gt;
  border: 1px black solid;&lt;br /&gt;
  padding: 5px;&lt;br /&gt;
  max-width: 400px;&lt;br /&gt;
  box-sizing: border-box;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.monster-card &amp;gt; :first-child {&lt;br /&gt;
  display: flex;&lt;br /&gt;
  justify-content: space-between;&lt;br /&gt;
  margin-bottom: 5px;&lt;br /&gt;
  line-height: 25px;&lt;br /&gt;
  padding: 0 5px;&lt;br /&gt;
  background: none;&lt;br /&gt;
  background-color: black;&lt;br /&gt;
  color: white;&lt;br /&gt;
  white-space: nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.monster-card &amp;gt; :first-child a {&lt;br /&gt;
  color: white;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.monster-card &amp;gt; :nth-child(2) {&lt;br /&gt;
  display: flex;&lt;br /&gt;
  justify-content: space-between;&lt;br /&gt;
  margin-bottom: 5px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.monster-card &amp;gt; :nth-child(3) {&lt;br /&gt;
  background: rgba(0, 0, 0, 0.1);&lt;br /&gt;
  display: grid;&lt;br /&gt;
  justify-content: center;&lt;br /&gt;
  align-items: start;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
button.brown {&lt;br /&gt;
  background: #651e10;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
button.brown-transparent {&lt;br /&gt;
  background: #651e10cc;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
button.brown:hover,&lt;br /&gt;
button.brown:focus {&lt;br /&gt;
  background: #551a0e;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
button.red {&lt;br /&gt;
  background: #ef4444;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
button.red:hover,&lt;br /&gt;
button.red:focus {&lt;br /&gt;
  background: #b91c1c;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
button:active {&lt;br /&gt;
  opacity: 0.8;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.button {&lt;br /&gt;
  border: 2px solid grey;&lt;br /&gt;
  padding: 0 12px;&lt;br /&gt;
  line-height: 25px;&lt;br /&gt;
  border-radius: 16px;&lt;br /&gt;
  background: rgba(234, 234, 234);&lt;br /&gt;
  cursor: pointer;&lt;br /&gt;
  display: inline-block;&lt;br /&gt;
  position: relative;&lt;br /&gt;
  user-select: none;&lt;br /&gt;
  white-space: nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.button:hover {&lt;br /&gt;
  background: transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.modal {&lt;br /&gt;
  opacity: 0;&lt;br /&gt;
  visibility: hidden;&lt;br /&gt;
  transform: scale(1.1);&lt;br /&gt;
  transition: visibility 0s linear 0.25s, opacity 0.25s 0s, transform 0.25s;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.close-button {&lt;br /&gt;
  transition: color 0.2s linear, background-color 0.2s linear;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.close-button:hover {&lt;br /&gt;
  background-color: red;&lt;br /&gt;
  color: #ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.show-modal {&lt;br /&gt;
  opacity: 1;&lt;br /&gt;
  visibility: visible;&lt;br /&gt;
  transform: scale(1);&lt;br /&gt;
  transition: visibility 0s linear 0s, opacity 0.25s 0s, transform 0.25s;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.cacheOrdi,&lt;br /&gt;
.gen-active {&lt;br /&gt;
  display: block;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.texte-long,&lt;br /&gt;
.texte-long-2 {&lt;br /&gt;
  text-overflow: ellipsis;&lt;br /&gt;
  white-space: nowrap;&lt;br /&gt;
  overflow: hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.texte-long:hover,&lt;br /&gt;
.texte-long-2:hover {&lt;br /&gt;
  white-space: normal;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.shop-img img {&lt;br /&gt;
  height: auto;&lt;br /&gt;
  width: auto;&lt;br /&gt;
  max-height: 130px;&lt;br /&gt;
  max-width: 130px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#mw-content .soulignement &amp;gt; a:link {&lt;br /&gt;
  text-decoration: none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* Remplacer popInfo et popContenu par pop-parent et pop-content */&lt;br /&gt;
.popContenu {&lt;br /&gt;
  display: inline-block;&lt;br /&gt;
  transition: all 0.4s ease;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.popInfo:hover .popContenu {&lt;br /&gt;
  opacity: 1 !important;&lt;br /&gt;
  transition: all 0.4s ease;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.pop-parent:hover .pop-content {&lt;br /&gt;
  opacity: 1;&lt;br /&gt;
  transition: opacity 0.4s ease;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.pop-content {&lt;br /&gt;
  opacity: 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.cadreFenetre,&lt;br /&gt;
.game-window {&lt;br /&gt;
  border: solid;&lt;br /&gt;
  border-image: url(&amp;quot;https://fr-wiki.metin2.gameforge.com/images/1/11/Cadrefenetre.png&amp;quot;)&lt;br /&gt;
    11 fill / auto / 0 repeat;&lt;br /&gt;
  padding: 10px;&lt;br /&gt;
  backdrop-filter: blur(4px);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tabber-active.button {&lt;br /&gt;
  background: rgba(75, 85, 95);&lt;br /&gt;
  color: white;&lt;br /&gt;
  border: 2px solid rgba(75, 85, 95);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
ul.subpage {&lt;br /&gt;
  display: flex;&lt;br /&gt;
  list-style: none;&lt;br /&gt;
  margin: 0 0 10px;&lt;br /&gt;
  padding: 0;&lt;br /&gt;
  background: rgba(81, 36, 16, 0.3);&lt;br /&gt;
  overflow: hidden;&lt;br /&gt;
  line-height: 30px;&lt;br /&gt;
  white-space: nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.subpage a {&lt;br /&gt;
  padding-left: 20px;&lt;br /&gt;
  background: #512410;&lt;br /&gt;
  display: inline-block;&lt;br /&gt;
  line-height: 30px;&lt;br /&gt;
  position: relative;&lt;br /&gt;
  color: #f1de8e;&lt;br /&gt;
  cursor: pointer;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.subpage a:before,&lt;br /&gt;
.subpage a:after {&lt;br /&gt;
  content: &amp;quot;&amp;quot;;&lt;br /&gt;
  position: absolute;&lt;br /&gt;
  width: 0;&lt;br /&gt;
  height: 0;&lt;br /&gt;
  right: 0;&lt;br /&gt;
  padding: 1px 0;&lt;br /&gt;
  border-top: 14px solid transparent;&lt;br /&gt;
  border-bottom: 14px solid transparent;&lt;br /&gt;
  border-left: 14px solid white;&lt;br /&gt;
  transform: translate(14px);&lt;br /&gt;
  z-index: 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.subpage a:after {&lt;br /&gt;
  border-left: 14px solid #512410;&lt;br /&gt;
  transform: translate(13px);&lt;br /&gt;
  z-index: 2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.subpage &amp;gt; li:last-child {&lt;br /&gt;
  padding-left: 20px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
ul.subpage &amp;gt; li:first-child {&lt;br /&gt;
  flex-shrink: 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
ul.subpage &amp;gt; li:first-child &amp;gt; a {&lt;br /&gt;
  height: 100%;&lt;br /&gt;
  display: flex;&lt;br /&gt;
  align-items: center;&lt;br /&gt;
  padding-left: 10px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
ul.subpage &amp;gt; li &amp;gt; a:hover {&lt;br /&gt;
  background: #9d5b37;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
ul.subpage &amp;gt; li &amp;gt; a:hover:after {&lt;br /&gt;
  border-left-color: #9d5b37;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.image-sizing img,&lt;br /&gt;
.image-sizing-200 img,&lt;br /&gt;
.image-sizing-none img {&lt;br /&gt;
  height: auto;&lt;br /&gt;
  width: auto;&lt;br /&gt;
  max-height: 300px;&lt;br /&gt;
  max-width: 100%;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.image-sizing-200 img {&lt;br /&gt;
  max-height: 200px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.image-sizing-none img {&lt;br /&gt;
  max-height: none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
div.ul-res ul {&lt;br /&gt;
  margin: 0;&lt;br /&gt;
  list-style: none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tab-glob {&lt;br /&gt;
  display: flex;&lt;br /&gt;
  flex-direction: row;&lt;br /&gt;
  margin: 10px 0;&lt;br /&gt;
  column-gap: 2px;&lt;br /&gt;
  align-items: flex-start;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tab-glob &amp;gt; :first-child {&lt;br /&gt;
  display: grid;&lt;br /&gt;
  grid-template-columns: max-content;&lt;br /&gt;
  row-gap: 2px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tab-glob &amp;gt; :first-child &amp;gt; * {&lt;br /&gt;
  border: 1px black solid;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tab-glob &amp;gt; :first-child &amp;gt; *:not(.fondfenetre) {&lt;br /&gt;
  font-weight: bold;&lt;br /&gt;
  display: flex;&lt;br /&gt;
  justify-content: center;&lt;br /&gt;
  align-items: center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tab-glob &amp;gt; :nth-child(2) {&lt;br /&gt;
  width: 100%;&lt;br /&gt;
  overflow-x: auto;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tab-glob &amp;gt; :nth-child(2) &amp;gt; :first-child {&lt;br /&gt;
  display: grid;&lt;br /&gt;
  grid-template-columns: repeat(10, minmax(75px, 1fr));&lt;br /&gt;
  gap: 2px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tab-glob &amp;gt; :nth-child(2) &amp;gt; :first-child &amp;gt; * {&lt;br /&gt;
  border: 1px black solid;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tab-glob &amp;gt; :nth-child(2) &amp;gt; :first-child &amp;gt; :not(.fondfenetre) {&lt;br /&gt;
  display: flex;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tab-glob &amp;gt; :nth-child(2) &amp;gt; :first-child &amp;gt; :not(.fondfenetre) &amp;gt; * {&lt;br /&gt;
  margin: auto;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.list-equip {&lt;br /&gt;
  padding: 5px;&lt;br /&gt;
  border: 1px solid #2f1d1f;&lt;br /&gt;
  display: flex;&lt;br /&gt;
  flex-direction: column;&lt;br /&gt;
  align-items: center;&lt;br /&gt;
  gap: 5px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.list-equip &amp;gt; :first-child {&lt;br /&gt;
  width: 100%;&lt;br /&gt;
  line-height: 25px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.list-equip &amp;gt; :first-child &amp;gt; * {&lt;br /&gt;
  padding: 0 5px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.fabrication {&lt;br /&gt;
  position: relative;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.fabrication &amp;gt; * {&lt;br /&gt;
  position: absolute;&lt;br /&gt;
  top: -188px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.fabrication &amp;gt; .bottom-fab,&lt;br /&gt;
.fabrication &amp;gt; .bottom-fab ~ * {&lt;br /&gt;
  top: -58px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.fabrication &amp;gt; * &amp;gt; *:nth-child(2) {&lt;br /&gt;
  position: relative;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.fabrication &amp;gt; * &amp;gt; *:nth-child(2) &amp;gt; * {&lt;br /&gt;
  position: absolute;&lt;br /&gt;
  top: -18px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.fabrication &amp;gt; * &amp;gt; *:nth-child(n + 3) {&lt;br /&gt;
  position: absolute;&lt;br /&gt;
  top: 100px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.info-boutique ul {&lt;br /&gt;
  list-style-image: none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.info-boutique p:last-child {&lt;br /&gt;
  margin-bottom: 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
kbd {&lt;br /&gt;
  background-color: #eee;&lt;br /&gt;
  border-radius: 3px;&lt;br /&gt;
  border: 1px solid #b4b4b4;&lt;br /&gt;
  box-shadow: 0 1px 1px rgb(0 0 0 / 20%), 0 2px 0 0 rgb(255 255 255 / 70%) inset;&lt;br /&gt;
  color: #333;&lt;br /&gt;
  display: inline-block;&lt;br /&gt;
  font-size: 0.85em;&lt;br /&gt;
  font-weight: 700;&lt;br /&gt;
  line-height: 1;&lt;br /&gt;
  padding: 2px 4px;&lt;br /&gt;
  white-space: nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.top-button {&lt;br /&gt;
  display: flex;&lt;br /&gt;
  justify-content: center;&lt;br /&gt;
  align-items: center;&lt;br /&gt;
  opacity: 0;&lt;br /&gt;
  cursor: pointer;&lt;br /&gt;
  position: fixed;&lt;br /&gt;
  bottom: 10px;&lt;br /&gt;
  right: 10px;&lt;br /&gt;
  width: 32px;&lt;br /&gt;
  height: 32px;&lt;br /&gt;
  background: linear-gradient(&lt;br /&gt;
    180deg,&lt;br /&gt;
    rgba(124, 200, 65, 1) 0%,&lt;br /&gt;
    rgba(113, 161, 85, 1) 50%,&lt;br /&gt;
    rgba(64, 117, 39, 1) 50%,&lt;br /&gt;
    rgba(46, 97, 31, 1) 100%&lt;br /&gt;
  );&lt;br /&gt;
  border: 1px solid #d0af52;&lt;br /&gt;
  box-shadow: 1px 1px 2px #000, inset 1px 1px #090200, inset -1px -1px #090200;&lt;br /&gt;
  transform: translateY(100px);&lt;br /&gt;
  transition: all 0.5s ease;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.top-button:after {&lt;br /&gt;
  content: &amp;quot;&amp;quot;;&lt;br /&gt;
  height: 32px;&lt;br /&gt;
  width: 32px;&lt;br /&gt;
  background-image: url(&amp;quot;data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fffacb' height='32' viewBox='0 -960 960 960' width='32'%3E%3Cpath d='m296-345-56-56 240-240 240 240-56 56-184-184-184 184Z'/%3E%3C/svg%3E&amp;quot;);&lt;br /&gt;
  background-repeat: no-repeat;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.show-button {&lt;br /&gt;
  opacity: 1;&lt;br /&gt;
  transform: translateY(0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.ul-row ul {&lt;br /&gt;
  display: flex;&lt;br /&gt;
  column-gap: 30px;&lt;br /&gt;
  flex-wrap: wrap;&lt;br /&gt;
  overflow: hidden;&lt;br /&gt;
  margin: 0;&lt;br /&gt;
  list-style-image: none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.flex {&lt;br /&gt;
  display: flex;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#catlinks {&lt;br /&gt;
  margin-top: 10px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.improved-collapsible &amp;gt; .mw-collapsible-toggle {&lt;br /&gt;
  grid-area: 1 / -1;&lt;br /&gt;
  display: flex;&lt;br /&gt;
  justify-content: flex-end;&lt;br /&gt;
  align-items: center;&lt;br /&gt;
  float: initial;&lt;br /&gt;
  z-index: 1;&lt;br /&gt;
  padding-right: 5px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.improved-collapsible .mw-collapsible-toggle:before {&lt;br /&gt;
  content: &amp;quot;&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.improved-collapsible .mw-collapsible-text {&lt;br /&gt;
  display: none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.improved-collapsible .mw-collapsible-toggle:after {&lt;br /&gt;
  width: 32px;&lt;br /&gt;
  height: 32px;&lt;br /&gt;
  content: &amp;quot;&amp;quot;;&lt;br /&gt;
  background-image: url(&amp;quot;data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23000000' height='32' viewBox='0 -960 960 960' width='32'%3E%3Cpath d='M480-345 240-585l56-56 184 184 184-184 56 56-240 240Z'/%3E%3C/svg%3E&amp;quot;);&lt;br /&gt;
  background-repeat: no-repeat;&lt;br /&gt;
  transition: transform 0.2s ease-in-out;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.improved-collapsible .mw-collapsible-toggle-expanded:after {&lt;br /&gt;
  transform: rotate(-180deg);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tooltip-icon {&lt;br /&gt;
  background-image: url(&amp;quot;data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' height='24' viewBox='0 -960 960 960' width='24'%3E%3Cpath d='M443-285h75v-234h-75v234Zm36.895-311Q496-596 507-606.895q11-10.894 11-27Q518-650 507.105-661q-10.894-11-27-11Q464-672 453-661.105q-11 10.894-11 27Q442-618 452.895-607q10.894 11 27 11ZM480-90q-80.907 0-152.065-30.763-71.159-30.763-123.797-83.5Q151.5-257 120.75-328.087 90-399.175 90-480q0-80.907 30.763-152.065 30.763-71.159 83.5-123.797Q257-808.5 328.087-839.25 399.175-870 480-870q80.907 0 152.065 30.763 71.159 30.763 123.797 83.5Q808.5-703 839.25-631.913 870-560.825 870-480q0 80.907-30.763 152.065-30.763 71.159-83.5 123.797Q703-151.5 631.913-120.75 560.825-90 480-90Zm0-75q131.5 0 223.25-91.75T795-480q0-131.5-91.75-223.25T480-795q-131.5 0-223.25 91.75T165-480q0 131.5 91.75 223.25T480-165Zm0-315Z'/%3E%3C/svg%3E&amp;quot;);&lt;br /&gt;
  background-repeat: no-repeat;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tooltip-info {&lt;br /&gt;
  position: absolute;&lt;br /&gt;
  bottom: calc(100% + 8px);&lt;br /&gt;
  left: 50%;&lt;br /&gt;
  transform: translateX(-50%);&lt;br /&gt;
  max-width: 290px;&lt;br /&gt;
  width: max-content;&lt;br /&gt;
  z-index: 50;&lt;br /&gt;
  opacity: 0;&lt;br /&gt;
  visibility: hidden;&lt;br /&gt;
  transition: opacity 0.2s ease, visibility 0.2s ease;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tooltip-info:after {&lt;br /&gt;
  content: &amp;quot;&amp;quot;;&lt;br /&gt;
  border: 8px solid transparent;&lt;br /&gt;
  border-top-color: inherit;&lt;br /&gt;
  position: absolute;&lt;br /&gt;
  left: calc(50% - 8px);&lt;br /&gt;
  top: 100%;&lt;br /&gt;
  z-index: 50;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tooltip-icon:hover &amp;gt; .tooltip-info {&lt;br /&gt;
  opacity: 1;&lt;br /&gt;
  visibility: visible;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
input,&lt;br /&gt;
input[type=&amp;quot;checkbox&amp;quot;],&lt;br /&gt;
select {&lt;br /&gt;
  border: 3px #d0e0e3 solid;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
input[type=&amp;quot;checkbox&amp;quot;] {&lt;br /&gt;
  background-color: white;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
input[type=&amp;quot;checkbox&amp;quot;]:checked {&lt;br /&gt;
  background-color: #19bd94;&lt;br /&gt;
  border: none;&lt;br /&gt;
  position: relative;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
input[type=&amp;quot;checkbox&amp;quot;]:checked:after {&lt;br /&gt;
  content: &amp;quot;&amp;quot;;&lt;br /&gt;
  position: absolute;&lt;br /&gt;
  background: transparent;&lt;br /&gt;
  left: 20%;&lt;br /&gt;
  top: 20%;&lt;br /&gt;
  width: 45%;&lt;br /&gt;
  height: 25%;&lt;br /&gt;
  transform: rotate(-45deg);&lt;br /&gt;
  border: 0.18em white solid;&lt;br /&gt;
  border-top: none;&lt;br /&gt;
  border-right: none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
input:focus,&lt;br /&gt;
select:focus {&lt;br /&gt;
  border: 3px rgb(102, 175, 233) solid;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
input:focus:not([type='checkbox']),&lt;br /&gt;
select:focus {&lt;br /&gt;
  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075),&lt;br /&gt;
    0 0 8px rgba(102, 175, 233, 0.6);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.label-hover label:hover {&lt;br /&gt;
  background-color: rgba(0, 0, 0, 0.1);&lt;br /&gt;
  border-radius: 8px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.cacheTel,&lt;br /&gt;
.tabber-container &amp;gt; :last-child &amp;gt; :not(.tabber-active),&lt;br /&gt;
.tabber-noactive {&lt;br /&gt;
  display: none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes pnj-square {&lt;br /&gt;
  from {&lt;br /&gt;
    background-color: #f80000;&lt;br /&gt;
  }&lt;br /&gt;
  to {&lt;br /&gt;
    background-color: white;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes pnj-circle {&lt;br /&gt;
  from {&lt;br /&gt;
    border-color: #984c48;&lt;br /&gt;
  }&lt;br /&gt;
  to {&lt;br /&gt;
    border-color: white;&lt;br /&gt;
  }&lt;br /&gt;
  from {&lt;br /&gt;
    scale: 1;&lt;br /&gt;
  }&lt;br /&gt;
  to {&lt;br /&gt;
    scale: 0.1;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes loading {&lt;br /&gt;
  0% {&lt;br /&gt;
    transform: scale(1.5);&lt;br /&gt;
  }&lt;br /&gt;
  100% {&lt;br /&gt;
    transform: scale(1);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@media screen and (max-width: 768px) {&lt;br /&gt;
  .texte-long {&lt;br /&gt;
    white-space: normal;&lt;br /&gt;
    overflow: visible;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  .grid2 {&lt;br /&gt;
    grid-template-columns: repeat(2, 1fr) !important;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  .grid3 {&lt;br /&gt;
    grid-template-columns: repeat(3, auto) !important;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  .container {&lt;br /&gt;
    flex-direction: column;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  .cacheTel,&lt;br /&gt;
  .subpage &amp;gt; li:nth-last-child(2) &amp;gt; a {&lt;br /&gt;
    display: block;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  .top-button {&lt;br /&gt;
    background: rgba(0, 0, 0, 0.7);&lt;br /&gt;
    color: #999;&lt;br /&gt;
    border: none;&lt;br /&gt;
    box-shadow: none;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  .top-button::after {&lt;br /&gt;
    background-image: url(&amp;quot;data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23ffffff' height='24' viewBox='0 -960 960 960' width='24'%3E%3Cpath d='M440-80v-647L256-544l-56-56 280-280 280 280-56 57-184-184v647h-80Z'/%3E%3C/svg%3E&amp;quot;);&lt;br /&gt;
    height: 24px;&lt;br /&gt;
    width: 24px;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  .tooltip-icon {&lt;br /&gt;
    position: static;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  .tooltip-info {&lt;br /&gt;
    position: fixed;&lt;br /&gt;
    left: 20px;&lt;br /&gt;
    right: 20px;&lt;br /&gt;
    bottom: 50px;&lt;br /&gt;
    max-width: none;&lt;br /&gt;
    width: auto;&lt;br /&gt;
    transform: none;&lt;br /&gt;
    height: max-content;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  .subpage &amp;gt; li &amp;gt; a,&lt;br /&gt;
  .cacheOrdi,&lt;br /&gt;
  .tooltip-info:after {&lt;br /&gt;
    display: none;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@media screen and (max-width: 340px) {&lt;br /&gt;
  #mw-content {&lt;br /&gt;
    padding-left: 10px;&lt;br /&gt;
    padding-right: 10px;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@media screen and (min-width: 851px) {&lt;br /&gt;
  html {&lt;br /&gt;
    scroll-padding-top: 3.325em;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;/div&gt;</summary>
		<author><name>Dexter</name></author>
		
	</entry>
	<entry>
		<id>https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Script/Colorblind.js&amp;diff=107410</id>
		<title>MediaWiki:Script/Colorblind.js</title>
		<link rel="alternate" type="text/html" href="https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Script/Colorblind.js&amp;diff=107410"/>
		<updated>2025-05-28T19:50:31Z</updated>

		<summary type="html">&lt;p&gt;Dexter : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;class SpawnLayerManager {&lt;br /&gt;
  static SPAWN_COLOR_KEY = &amp;quot;mt2.spawn.color&amp;quot;;&lt;br /&gt;
  static OPTION_MAPPING = {&lt;br /&gt;
    0: &amp;quot;🟥 Rouge&amp;quot;,&lt;br /&gt;
    50: &amp;quot;🟫 Marron&amp;quot;,&lt;br /&gt;
    140: &amp;quot;🟩 Vert&amp;quot;,&lt;br /&gt;
    230: &amp;quot;🟦 Bleu&amp;quot;,&lt;br /&gt;
    290: &amp;quot;🟪 Violet&amp;quot;,&lt;br /&gt;
    black: &amp;quot;⬛ Noir&amp;quot;,&lt;br /&gt;
    white: &amp;quot;⬜ Blanc&amp;quot;,&lt;br /&gt;
  };&lt;br /&gt;
  static STYLE_MAPPING = {&lt;br /&gt;
    position: &amp;quot;absolute&amp;quot;,&lt;br /&gt;
    top: &amp;quot;0&amp;quot;,&lt;br /&gt;
    left: &amp;quot;0&amp;quot;,&lt;br /&gt;
    margin: &amp;quot;4px&amp;quot;,&lt;br /&gt;
    background: &amp;quot;#434242b3&amp;quot;,&lt;br /&gt;
    color: &amp;quot;white&amp;quot;,&lt;br /&gt;
    borderRadius: &amp;quot;5px&amp;quot;,&lt;br /&gt;
    cursor: &amp;quot;pointer&amp;quot;,&lt;br /&gt;
    border: &amp;quot;1px white solid&amp;quot;,&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  constructor(containerSelector = &amp;quot;.spawn-map-container&amp;quot;) {&lt;br /&gt;
    this.containerSelector = containerSelector;&lt;br /&gt;
    this.currentFilter = null;&lt;br /&gt;
    this.selects = [];&lt;br /&gt;
    this.spawnLayers = [];&lt;br /&gt;
    this.isClipboardImageSupported = this._isClipboardImageSupported();&lt;br /&gt;
    this._initialize();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  _isClipboardImageSupported() {&lt;br /&gt;
    const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);&lt;br /&gt;
    return !!(navigator.clipboard?.write &amp;amp;&amp;amp; window.ClipboardItem) &amp;amp;&amp;amp; !isSafari;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  _initialize() {&lt;br /&gt;
    const containers = this._getContainers();&lt;br /&gt;
    if (!containers.length) return;&lt;br /&gt;
&lt;br /&gt;
    containers.forEach((container) =&amp;gt; this._setupContainer(container));&lt;br /&gt;
&lt;br /&gt;
    const savedColor = this._getSavedColor();&lt;br /&gt;
    if (savedColor) this._applyColor(savedColor);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  _getContainers() {&lt;br /&gt;
    return document.querySelectorAll(this.containerSelector);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  _getSavedColor() {&lt;br /&gt;
    return localStorage.getItem(SpawnLayerManager.SPAWN_COLOR_KEY);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  _saveColor(value) {&lt;br /&gt;
    localStorage.setItem(SpawnLayerManager.SPAWN_COLOR_KEY, value);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  _setupContainer(container) {&lt;br /&gt;
    const [mapContainer, spawnContainer] = container.children;&lt;br /&gt;
&lt;br /&gt;
    if (!mapContainer || !spawnContainer) return;&lt;br /&gt;
&lt;br /&gt;
    const map = mapContainer.querySelector(&amp;quot;img&amp;quot;);&lt;br /&gt;
    const spawnLayer = spawnContainer.querySelector(&amp;quot;img&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (!map || !spawnLayer) return;&lt;br /&gt;
&lt;br /&gt;
    const select = this._createColorSelect();&lt;br /&gt;
    spawnContainer.appendChild(select);&lt;br /&gt;
&lt;br /&gt;
    this.selects.push(select);&lt;br /&gt;
    this.spawnLayers.push(spawnLayer);&lt;br /&gt;
&lt;br /&gt;
    select.addEventListener(&amp;quot;change&amp;quot;, (e) =&amp;gt; this._onColorChange(e));&lt;br /&gt;
&lt;br /&gt;
    if (this.isClipboardImageSupported) {&lt;br /&gt;
      this._setupCopyButton(spawnContainer, map, spawnLayer);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  _createColorSelect() {&lt;br /&gt;
    const select = document.createElement(&amp;quot;select&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    for (const [value, label] of Object.entries(&lt;br /&gt;
      SpawnLayerManager.OPTION_MAPPING&lt;br /&gt;
    )) {&lt;br /&gt;
      const option = document.createElement(&amp;quot;option&amp;quot;);&lt;br /&gt;
      option.value = value;&lt;br /&gt;
      option.textContent = label;&lt;br /&gt;
      select.appendChild(option);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    Object.assign(select.style, SpawnLayerManager.STYLE_MAPPING);&lt;br /&gt;
    return select;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  _onColorChange(event) {&lt;br /&gt;
    const value = event.target.value;&lt;br /&gt;
    this._applyColor(value);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  _applyColor(value) {&lt;br /&gt;
    if (!SpawnLayerManager.OPTION_MAPPING.hasOwnProperty(value)) return;&lt;br /&gt;
&lt;br /&gt;
    const filter = this._getFilterForValue(value);&lt;br /&gt;
    this.currentFilter = filter;&lt;br /&gt;
&lt;br /&gt;
    this.selects.forEach((select) =&amp;gt; (select.value = value));&lt;br /&gt;
    this.spawnLayers.forEach((layer) =&amp;gt; (layer.style.filter = filter));&lt;br /&gt;
    this._saveColor(value);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  _getFilterForValue(value) {&lt;br /&gt;
    switch (value) {&lt;br /&gt;
      case &amp;quot;black&amp;quot;:&lt;br /&gt;
        return &amp;quot;invert(1) brightness(0) contrast(100%)&amp;quot;;&lt;br /&gt;
      case &amp;quot;white&amp;quot;:&lt;br /&gt;
        return &amp;quot;invert(1) sepia(1) saturate(100%) brightness(3)&amp;quot;;&lt;br /&gt;
      default:&lt;br /&gt;
        return `hue-rotate(${value}deg)`;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  _setupCopyButton(spawnContainer, map, spawnLayer) {&lt;br /&gt;
    const copyButton = spawnContainer.querySelector(&amp;quot;.copy-to-clipboard&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (!copyButton) return;&lt;br /&gt;
&lt;br /&gt;
    const defaultEmoji = copyButton.querySelector(&amp;quot;[data-default]&amp;quot;);&lt;br /&gt;
    const clickedEmoji = copyButton.querySelector(&amp;quot;[data-clicked]&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (!defaultEmoji || !clickedEmoji) return;&lt;br /&gt;
&lt;br /&gt;
    showElement(copyButton);&lt;br /&gt;
&lt;br /&gt;
    copyButton.addEventListener(&amp;quot;click&amp;quot;, () =&amp;gt; {&lt;br /&gt;
      this._copyCombinedImageToClipboard(map, spawnLayer);&lt;br /&gt;
      this._copyAnimation(defaultEmoji, clickedEmoji);&lt;br /&gt;
    });&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  _copyCombinedImageToClipboard(map, spawnLayer) {&lt;br /&gt;
    const canvas = document.createElement(&amp;quot;canvas&amp;quot;);&lt;br /&gt;
    canvas.width = Math.max(map.naturalWidth, spawnLayer.naturalWidth);&lt;br /&gt;
    canvas.height = Math.max(map.naturalHeight, spawnLayer.naturalHeight);&lt;br /&gt;
&lt;br /&gt;
    const ctx = canvas.getContext(&amp;quot;2d&amp;quot;);&lt;br /&gt;
    ctx.drawImage(map, 0, 0);&lt;br /&gt;
&lt;br /&gt;
    const filteredLayer = this._drawFilteredLayer(spawnLayer);&lt;br /&gt;
    ctx.drawImage(filteredLayer, 0, 0);&lt;br /&gt;
&lt;br /&gt;
    this._copyCanvasContentsToClipboard(canvas);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  _drawFilteredLayer(layer) {&lt;br /&gt;
    const canvas = document.createElement(&amp;quot;canvas&amp;quot;);&lt;br /&gt;
    canvas.width = layer.naturalWidth;&lt;br /&gt;
    canvas.height = layer.naturalHeight;&lt;br /&gt;
&lt;br /&gt;
    const ctx = canvas.getContext(&amp;quot;2d&amp;quot;);&lt;br /&gt;
    ctx.filter = this.currentFilter || &amp;quot;none&amp;quot;;&lt;br /&gt;
    ctx.drawImage(layer, 0, 0);&lt;br /&gt;
&lt;br /&gt;
    return canvas;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  async _getBlobFromCanvas(canvas) {&lt;br /&gt;
    return new Promise((resolve, reject) =&amp;gt; {&lt;br /&gt;
      canvas.toBlob((blob) =&amp;gt; {&lt;br /&gt;
        if (blob) {&lt;br /&gt;
          resolve(blob);&lt;br /&gt;
        } else {&lt;br /&gt;
          reject(new Error(&amp;quot;Canvas toBlob failed&amp;quot;));&lt;br /&gt;
        }&lt;br /&gt;
      });&lt;br /&gt;
    });&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  async _copyCanvasContentsToClipboard(canvas) {&lt;br /&gt;
    try {&lt;br /&gt;
      const blob = await this._getBlobFromCanvas(canvas);&lt;br /&gt;
      const data = [new ClipboardItem({ [blob.type]: blob })];&lt;br /&gt;
      await navigator.clipboard.write(data);&lt;br /&gt;
    } catch (error) {&lt;br /&gt;
      console.error(error);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  _copyAnimation(defaultEmoji, clickedEmoji) {&lt;br /&gt;
    hideElement(defaultEmoji);&lt;br /&gt;
    showElement(clickedEmoji);&lt;br /&gt;
&lt;br /&gt;
    setTimeout(() =&amp;gt; {&lt;br /&gt;
      hideElement(clickedEmoji);&lt;br /&gt;
      showElement(defaultEmoji);&lt;br /&gt;
    }, 1500);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
new SpawnLayerManager();&lt;/div&gt;</summary>
		<author><name>Dexter</name></author>
		
	</entry>
	<entry>
		<id>https://fr-wiki.metin2.gameforge.com/index.php?title=Mod%C3%A8le:Main_Page/News2&amp;diff=107347</id>
		<title>Modèle:Main Page/News2</title>
		<link rel="alternate" type="text/html" href="https://fr-wiki.metin2.gameforge.com/index.php?title=Mod%C3%A8le:Main_Page/News2&amp;diff=107347"/>
		<updated>2025-05-08T05:00:04Z</updated>

		<summary type="html">&lt;p&gt;Dexter : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;margin: 10px 0px 5px 0px&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;cadre&amp;quot; style=&amp;quot;border-color: #88283a; box-shadow: 2px 2px 5px black; font-size: 11px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-size: 12px;&amp;quot;&amp;gt;'''L'équipe''' [[image:Icone_france.png|12px]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;grid3&amp;quot; style=&amp;quot;display: grid; grid-template-columns: repeat(4, minmax(170px, 1fr)); grid-gap: 5px; text-align: center;&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: center; margin: 10px auto 5px; color: #CC00FF; font-weight: bold; font-size: 1.25em;&amp;quot;&amp;gt;ÉQUIPE WIKI&lt;br /&gt;
&amp;lt;div style=&amp;quot;margin-left: 20px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div&amp;gt;[[Image:Wm.png|150px|link=Wiki Manager]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;margin-left: 15px; color: #000000;&amp;quot;&amp;gt;Dexter&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div&amp;gt;[[Image:Superwiki.png|150px|link=Super Rédacteur Wiki]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;margin-left: 15px;&amp;quot;&amp;gt;[[Utilisateur:Khojine|Khojine]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: center; margin: 10px auto 5px; color: #CC0000; font-weight: bold; font-size: 1.25em;&amp;quot;&amp;gt;ÉQUIPE JEU&lt;br /&gt;
&amp;lt;div style=&amp;quot;margin-left: 20px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div&amp;gt;[[Image:Ga.png|150px|link=Game Admins]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;margin-left: 15px; color: #000000;&amp;quot;&amp;gt;Apogia&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;margin-left: 15px; color: #000000;&amp;quot;&amp;gt;[[Utilisateur:Cassini|Cassini]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div&amp;gt;[[Image:Sgm.png|150px|link=Super Game Master]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;margin-left: 15px; color: #000000;&amp;quot;&amp;gt;SunBlue&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;margin-left: 15px; color: #000000;&amp;quot;&amp;gt;Phobos&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div&amp;gt;[[Image:gm.png|150px|link=Game Master]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;margin-left: 15px; color: #000000;&amp;quot;&amp;gt;Elya&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;margin-left: 15px; color: #000000;&amp;quot;&amp;gt;Lesath&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;margin-left: 15px; color: #000000;&amp;quot;&amp;gt;Athina&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;margin-left: 15px; color: #000000;&amp;quot;&amp;gt;Elaris&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;margin-left: 15px; color: #000000;&amp;quot;&amp;gt;Niryu&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: center; margin: 10px auto 5px; color: #009900; font-weight: bold; font-size: 1.25em;&amp;quot;&amp;gt;ÉQUIPE FORUM&lt;br /&gt;
&amp;lt;div style=&amp;quot;margin-left: 20px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div&amp;gt;[[Image:Ba.png|150px|link=Board Admins]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;margin-left: 15px; color: #000000;&amp;quot;&amp;gt;Mr. Robot&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;margin-left: 15px; color: #000000;&amp;quot;&amp;gt;Szopen&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div&amp;gt;[[Image:Bm.png|150px|link=Modérateurs]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;margin-left: 15px; color: #000000;&amp;quot;&amp;gt;Dexter&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;margin-left: 15px; color: #000000;&amp;quot;&amp;gt;Inuyasha&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: center; margin: 10px auto 5px; color: #D66F14; font-weight: bold; font-size: 1.25em;&amp;quot;&amp;gt;ÉQUIPE MANAGER&lt;br /&gt;
&amp;lt;div&amp;gt;[[Image:COMAmetin2.png|150px|link=Team Manager]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;margin-left: 15px; color: #000000;&amp;quot;&amp;gt;Paso&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div&amp;gt;[[Image:TMmetin2.png|150px|link=Team Manager]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;margin-left: 15px; color: #000000;&amp;quot;&amp;gt;[[Utilisateur:Daitya|Daitya]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
----&lt;br /&gt;
&amp;lt;p style=&amp;quot;text-align:center&amp;quot;&amp;gt;'''Recrutement Wiki''' :&amp;lt;br/&amp;gt;&amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;&amp;lt;big&amp;gt;'''Ouvert !'''&amp;lt;/big&amp;gt;&amp;lt;/font&amp;gt;&amp;lt;/p&amp;gt;&lt;br /&gt;
----&lt;br /&gt;
&amp;lt;p style=&amp;quot;text-align:center&amp;quot;&amp;gt;Si vous constatez des erreurs ou avez des questions '''sur le wiki et uniquement sur le wiki''', vous pouvez nous contacter via l'adresse mail suivante :&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;center&amp;quot;&amp;gt;&amp;lt;div style=&amp;quot;padding: 2px 17px; display: inline-block; border: 1px solid #97100d; font-weight: bold; font-size: 1.2em;&amp;quot;&amp;gt;wiki@metin2.fr&amp;lt;/div&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Dexter</name></author>
		
	</entry>
	<entry>
		<id>https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Script/Colorblind.js&amp;diff=107346</id>
		<title>MediaWiki:Script/Colorblind.js</title>
		<link rel="alternate" type="text/html" href="https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Script/Colorblind.js&amp;diff=107346"/>
		<updated>2025-05-08T04:42:16Z</updated>

		<summary type="html">&lt;p&gt;Dexter : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;class SpawnLayerManager {&lt;br /&gt;
  static SPAWN_COLOR_KEY = &amp;quot;mt2.spawn.color&amp;quot;;&lt;br /&gt;
  static OPTION_MAPPING = {&lt;br /&gt;
    0: &amp;quot;🟥 Rouge&amp;quot;,&lt;br /&gt;
    50: &amp;quot;🟫 Marron&amp;quot;,&lt;br /&gt;
    140: &amp;quot;🟩 Vert&amp;quot;,&lt;br /&gt;
    230: &amp;quot;🟦 Bleu&amp;quot;,&lt;br /&gt;
    290: &amp;quot;🟪 Violet&amp;quot;,&lt;br /&gt;
    black: &amp;quot;⬛ Noir&amp;quot;,&lt;br /&gt;
    white: &amp;quot;⬜ Blanc&amp;quot;,&lt;br /&gt;
  };&lt;br /&gt;
  static STYLE_MAPPING = {&lt;br /&gt;
    position: &amp;quot;absolute&amp;quot;,&lt;br /&gt;
    top: &amp;quot;0&amp;quot;,&lt;br /&gt;
    left: &amp;quot;0&amp;quot;,&lt;br /&gt;
    margin: &amp;quot;4px&amp;quot;,&lt;br /&gt;
    background: &amp;quot;#434242b3&amp;quot;,&lt;br /&gt;
    color: &amp;quot;white&amp;quot;,&lt;br /&gt;
    borderRadius: &amp;quot;5px&amp;quot;,&lt;br /&gt;
    cursor: &amp;quot;pointer&amp;quot;,&lt;br /&gt;
    border: &amp;quot;1px white solid&amp;quot;,&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  constructor(containerSelector = &amp;quot;.spawn-map-container&amp;quot;) {&lt;br /&gt;
    this.containerSelector = containerSelector;&lt;br /&gt;
    this.currentFilter = null;&lt;br /&gt;
    this.selects = [];&lt;br /&gt;
    this.spawnLayers = [];&lt;br /&gt;
    this.isClipboardImageSupported = this._isClipboardImageSupported();&lt;br /&gt;
    this._initialize();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  _isClipboardImageSupported() {&lt;br /&gt;
    return !!(navigator.clipboard?.write &amp;amp;&amp;amp; window.ClipboardItem);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  _initialize() {&lt;br /&gt;
    const containers = this._getContainers();&lt;br /&gt;
    if (!containers.length) return;&lt;br /&gt;
&lt;br /&gt;
    containers.forEach((container) =&amp;gt; this._setupContainer(container));&lt;br /&gt;
&lt;br /&gt;
    const savedColor = this._getSavedColor();&lt;br /&gt;
    if (savedColor) this._applyColor(savedColor);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  _getContainers() {&lt;br /&gt;
    return document.querySelectorAll(this.containerSelector);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  _getSavedColor() {&lt;br /&gt;
    return localStorage.getItem(SpawnLayerManager.SPAWN_COLOR_KEY);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  _saveColor(value) {&lt;br /&gt;
    localStorage.setItem(SpawnLayerManager.SPAWN_COLOR_KEY, value);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  _setupContainer(container) {&lt;br /&gt;
    const [mapContainer, spawnContainer] = container.children;&lt;br /&gt;
&lt;br /&gt;
    if (!mapContainer || !spawnContainer) return;&lt;br /&gt;
&lt;br /&gt;
    const map = mapContainer.querySelector(&amp;quot;img&amp;quot;);&lt;br /&gt;
    const spawnLayer = spawnContainer.querySelector(&amp;quot;img&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (!map || !spawnLayer) return;&lt;br /&gt;
&lt;br /&gt;
    const select = this._createColorSelect();&lt;br /&gt;
    spawnContainer.appendChild(select);&lt;br /&gt;
&lt;br /&gt;
    this.selects.push(select);&lt;br /&gt;
    this.spawnLayers.push(spawnLayer);&lt;br /&gt;
&lt;br /&gt;
    select.addEventListener(&amp;quot;change&amp;quot;, (e) =&amp;gt; this._onColorChange(e));&lt;br /&gt;
&lt;br /&gt;
    if (this.isClipboardImageSupported) {&lt;br /&gt;
      this._setupCopyButton(spawnContainer, map, spawnLayer);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  _createColorSelect() {&lt;br /&gt;
    const select = document.createElement(&amp;quot;select&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    for (const [value, label] of Object.entries(&lt;br /&gt;
      SpawnLayerManager.OPTION_MAPPING&lt;br /&gt;
    )) {&lt;br /&gt;
      const option = document.createElement(&amp;quot;option&amp;quot;);&lt;br /&gt;
      option.value = value;&lt;br /&gt;
      option.textContent = label;&lt;br /&gt;
      select.appendChild(option);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    Object.assign(select.style, SpawnLayerManager.STYLE_MAPPING);&lt;br /&gt;
    return select;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  _onColorChange(event) {&lt;br /&gt;
    const value = event.target.value;&lt;br /&gt;
    this._applyColor(value);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  _applyColor(value) {&lt;br /&gt;
    if (!SpawnLayerManager.OPTION_MAPPING.hasOwnProperty(value)) return;&lt;br /&gt;
&lt;br /&gt;
    const filter = this._getFilterForValue(value);&lt;br /&gt;
    this.currentFilter = filter;&lt;br /&gt;
&lt;br /&gt;
    this.selects.forEach((select) =&amp;gt; (select.value = value));&lt;br /&gt;
    this.spawnLayers.forEach((layer) =&amp;gt; (layer.style.filter = filter));&lt;br /&gt;
    this._saveColor(value);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  _getFilterForValue(value) {&lt;br /&gt;
    switch (value) {&lt;br /&gt;
      case &amp;quot;black&amp;quot;:&lt;br /&gt;
        return &amp;quot;invert(1) brightness(0) contrast(100%)&amp;quot;;&lt;br /&gt;
      case &amp;quot;white&amp;quot;:&lt;br /&gt;
        return &amp;quot;invert(1) sepia(1) saturate(100%) brightness(3)&amp;quot;;&lt;br /&gt;
      default:&lt;br /&gt;
        return `hue-rotate(${value}deg)`;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  _setupCopyButton(spawnContainer, map, spawnLayer) {&lt;br /&gt;
    const copyButton = spawnContainer.querySelector(&amp;quot;.copy-to-clipboard&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (!copyButton) return;&lt;br /&gt;
&lt;br /&gt;
    const defaultEmoji = copyButton.querySelector(&amp;quot;[data-default]&amp;quot;);&lt;br /&gt;
    const clickedEmoji = copyButton.querySelector(&amp;quot;[data-clicked]&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (!defaultEmoji || !clickedEmoji) return;&lt;br /&gt;
&lt;br /&gt;
    showElement(copyButton);&lt;br /&gt;
&lt;br /&gt;
    copyButton.addEventListener(&amp;quot;click&amp;quot;, () =&amp;gt; {&lt;br /&gt;
      this._copyCombinedImageToClipboard(map, spawnLayer);&lt;br /&gt;
      this._copyAnimation(defaultEmoji, clickedEmoji);&lt;br /&gt;
    });&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  _copyCombinedImageToClipboard(map, spawnLayer) {&lt;br /&gt;
    const canvas = document.createElement(&amp;quot;canvas&amp;quot;);&lt;br /&gt;
    canvas.width = Math.max(map.width, spawnLayer.width);&lt;br /&gt;
    canvas.height = Math.max(map.height, spawnLayer.height);&lt;br /&gt;
&lt;br /&gt;
    const ctx = canvas.getContext(&amp;quot;2d&amp;quot;);&lt;br /&gt;
    ctx.drawImage(map, 0, 0);&lt;br /&gt;
&lt;br /&gt;
    const filteredLayer = this._drawFilteredLayer(spawnLayer);&lt;br /&gt;
    ctx.drawImage(filteredLayer, 0, 0);&lt;br /&gt;
&lt;br /&gt;
    this._copyCanvasContentsToClipboard(canvas);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  _drawFilteredLayer(layer) {&lt;br /&gt;
    const canvas = document.createElement(&amp;quot;canvas&amp;quot;);&lt;br /&gt;
    canvas.width = layer.width;&lt;br /&gt;
    canvas.height = layer.height;&lt;br /&gt;
&lt;br /&gt;
    const ctx = canvas.getContext(&amp;quot;2d&amp;quot;);&lt;br /&gt;
    ctx.filter = this.currentFilter || &amp;quot;none&amp;quot;;&lt;br /&gt;
    ctx.drawImage(layer, 0, 0);&lt;br /&gt;
&lt;br /&gt;
    return canvas;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  async _getBlobFromCanvas(canvas) {&lt;br /&gt;
    return new Promise((resolve, reject) =&amp;gt; {&lt;br /&gt;
      canvas.toBlob((blob) =&amp;gt; {&lt;br /&gt;
        if (blob) {&lt;br /&gt;
          resolve(blob);&lt;br /&gt;
        } else {&lt;br /&gt;
          reject(new Error(&amp;quot;Canvas toBlob failed&amp;quot;));&lt;br /&gt;
        }&lt;br /&gt;
      });&lt;br /&gt;
    });&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  async _copyCanvasContentsToClipboard(canvas) {&lt;br /&gt;
    try {&lt;br /&gt;
      const blob = await this._getBlobFromCanvas(canvas);&lt;br /&gt;
      const data = [new ClipboardItem({ [blob.type]: blob })];&lt;br /&gt;
      await navigator.clipboard.write(data);&lt;br /&gt;
    } catch (error) {&lt;br /&gt;
      console.error(error);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  _copyAnimation(defaultEmoji, clickedEmoji) {&lt;br /&gt;
    hideElement(defaultEmoji);&lt;br /&gt;
    showElement(clickedEmoji);&lt;br /&gt;
&lt;br /&gt;
    setTimeout(() =&amp;gt; {&lt;br /&gt;
      hideElement(clickedEmoji);&lt;br /&gt;
      showElement(defaultEmoji);&lt;br /&gt;
    }, 1500);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
new SpawnLayerManager();&lt;/div&gt;</summary>
		<author><name>Dexter</name></author>
		
	</entry>
	<entry>
		<id>https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Common.css&amp;diff=107345</id>
		<title>MediaWiki:Common.css</title>
		<link rel="alternate" type="text/html" href="https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Common.css&amp;diff=107345"/>
		<updated>2025-05-08T04:41:37Z</updated>

		<summary type="html">&lt;p&gt;Dexter : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;/* Le CSS placé ici sera chargé sur toutes les pages */&lt;br /&gt;
&lt;br /&gt;
html {&lt;br /&gt;
  scroll-behavior: smooth;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
  body {&lt;br /&gt;
    background-image: url('https://fr-wiki.metin2.gameforge.com/images/b/bf/Fondhalloween.png');&lt;br /&gt;
  }&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
body {&lt;br /&gt;
  background-image: url(&amp;quot;https://fr-wiki.metin2.gameforge.com/images/1/15/Fond2015.jpg&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#mw-content ul {&lt;br /&gt;
  margin-bottom: 0.3em;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#mw-content ol {&lt;br /&gt;
  list-style: none;&lt;br /&gt;
  counter-reset: custom-counter;&lt;br /&gt;
  margin: 0.3em 0 0.3em 1.6em;&lt;br /&gt;
  padding: 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
ol li {&lt;br /&gt;
  padding: 0;&lt;br /&gt;
  padding-left: 5px;&lt;br /&gt;
  counter-increment: custom-counter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
ol li::marker {&lt;br /&gt;
  content: counter(custom-counter) &amp;quot;.  &amp;quot;;&lt;br /&gt;
  font-weight: bold;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
td,&lt;br /&gt;
th {&lt;br /&gt;
  padding: 2px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.map span.mw-collapsible-toggle {&lt;br /&gt;
  padding-right: 10px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
table.map a.mw-collapsible-text,&lt;br /&gt;
.prettytable &amp;gt; span.mw-collapsible-toggle,&lt;br /&gt;
.prettytable &amp;gt; span.mw-collapsible-toggle &amp;gt; a {&lt;br /&gt;
  color: #ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.boxesheaderbackground,&lt;br /&gt;
.cadre &amp;gt; div:first-child {&lt;br /&gt;
  background: repeat&lt;br /&gt;
    url(&amp;quot;https://fr-wiki.metin2.gameforge.com/images/a/a7/Boxheaderbrown.png&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.cadre {&lt;br /&gt;
  border: 1px solid #2f1d1f;&lt;br /&gt;
  border-radius: 15px 0;&lt;br /&gt;
  width: 100%;&lt;br /&gt;
  box-shadow: 3px 3px 9px 0px #544e41;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.cadre &amp;gt; div:first-child {&lt;br /&gt;
  text-align: center;&lt;br /&gt;
  color: white;&lt;br /&gt;
  line-height: 25px;&lt;br /&gt;
  overflow: hidden;&lt;br /&gt;
  border-top-left-radius: 15px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.fondfenetre,&lt;br /&gt;
.sous-titre,&lt;br /&gt;
table.pretty-table th {&lt;br /&gt;
  background: url(&amp;quot;https://fr-wiki.metin2.gameforge.com/images/8/89/Fondfenetre.png&amp;quot;)&lt;br /&gt;
    repeat;&lt;br /&gt;
  color: white;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
table.pretty-table td {&lt;br /&gt;
  padding: 5px 10px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
table.pretty-table th {&lt;br /&gt;
  padding: 2px 10px;&lt;br /&gt;
  font-weight: normal;&lt;br /&gt;
  font-size: 1.1em;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
table.pretty-table tbody &amp;gt; *:nth-child(2n + 1) &amp;gt; td {&lt;br /&gt;
  background: rgba(0, 0, 0, 0.1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
table.pretty-table tr:hover {&lt;br /&gt;
  background: rgba(0, 0, 0, 0.05);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
table.pretty-table tr:first-child &amp;gt; th:first-child {&lt;br /&gt;
  border-radius: 8px 0 0 0;&lt;br /&gt;
  overflow: hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
table.pretty-table caption {&lt;br /&gt;
  margin-top: 10px;&lt;br /&gt;
  font-weight: bold;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.fondfenetre a,&lt;br /&gt;
.fondfenetre span,&lt;br /&gt;
table.pretty-table th a,&lt;br /&gt;
table.pretty-table th span {&lt;br /&gt;
  color: white;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
table.sticky-header-row thead tr {&lt;br /&gt;
  position: sticky;&lt;br /&gt;
  top: 0;&lt;br /&gt;
  z-index: 10;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
table.sticky-header-column th:first-child {&lt;br /&gt;
  position: sticky;&lt;br /&gt;
  left: 0;&lt;br /&gt;
  z-index: 20;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sous-titre {&lt;br /&gt;
  max-width: 180px;&lt;br /&gt;
  border: 1px solid black;&lt;br /&gt;
  border-radius: 8px;&lt;br /&gt;
  color: white;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.modeleAnnonce {&lt;br /&gt;
  border-image: url(&amp;quot;https://fr-wiki.metin2.gameforge.com/images/f/fb/Modeleannonce.png&amp;quot;)&lt;br /&gt;
    17 35 3 fill / auto / 0 repeat;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.container {&lt;br /&gt;
  display: flex;&lt;br /&gt;
  flex-direction: row;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.monster-card {&lt;br /&gt;
  border: 1px black solid;&lt;br /&gt;
  padding: 5px;&lt;br /&gt;
  max-width: 400px;&lt;br /&gt;
  box-sizing: border-box;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.monster-card &amp;gt; :first-child {&lt;br /&gt;
  display: flex;&lt;br /&gt;
  justify-content: space-between;&lt;br /&gt;
  margin-bottom: 5px;&lt;br /&gt;
  line-height: 25px;&lt;br /&gt;
  padding: 0 5px;&lt;br /&gt;
  background: none;&lt;br /&gt;
  background-color: black;&lt;br /&gt;
  color: white;&lt;br /&gt;
  white-space: nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.monster-card &amp;gt; :first-child a {&lt;br /&gt;
  color: white;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.monster-card &amp;gt; :nth-child(2) {&lt;br /&gt;
  display: flex;&lt;br /&gt;
  justify-content: space-between;&lt;br /&gt;
  margin-bottom: 5px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.monster-card &amp;gt; :nth-child(3) {&lt;br /&gt;
  background: rgba(0, 0, 0, 0.1);&lt;br /&gt;
  display: grid;&lt;br /&gt;
  justify-content: center;&lt;br /&gt;
  align-items: start;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
button.brown {&lt;br /&gt;
  background: #651e10;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
button.brown-transparent {&lt;br /&gt;
  background: #651e10cc;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
button.brown:hover,&lt;br /&gt;
button.brown:focus {&lt;br /&gt;
  background: #551a0e;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
button.red {&lt;br /&gt;
  background: #ef4444;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
button.red:hover,&lt;br /&gt;
button.red:focus {&lt;br /&gt;
  background: #b91c1c;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
button:active {&lt;br /&gt;
  opacity: 0.8;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.button {&lt;br /&gt;
  border: 2px solid grey;&lt;br /&gt;
  padding: 0 12px;&lt;br /&gt;
  line-height: 25px;&lt;br /&gt;
  border-radius: 16px;&lt;br /&gt;
  background: rgba(234, 234, 234);&lt;br /&gt;
  cursor: pointer;&lt;br /&gt;
  display: inline-block;&lt;br /&gt;
  position: relative;&lt;br /&gt;
  user-select: none;&lt;br /&gt;
  white-space: nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.button:hover {&lt;br /&gt;
  background: transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.modal {&lt;br /&gt;
  opacity: 0;&lt;br /&gt;
  visibility: hidden;&lt;br /&gt;
  transform: scale(1.1);&lt;br /&gt;
  transition: visibility 0s linear 0.25s, opacity 0.25s 0s, transform 0.25s;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.close-button {&lt;br /&gt;
  transition: color 0.2s linear, background-color 0.2s linear;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.close-button:hover {&lt;br /&gt;
  background-color: red;&lt;br /&gt;
  color: #ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.show-modal {&lt;br /&gt;
  opacity: 1;&lt;br /&gt;
  visibility: visible;&lt;br /&gt;
  transform: scale(1);&lt;br /&gt;
  transition: visibility 0s linear 0s, opacity 0.25s 0s, transform 0.25s;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.cacheOrdi,&lt;br /&gt;
.gen-active {&lt;br /&gt;
  display: block;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.texte-long,&lt;br /&gt;
.texte-long-2 {&lt;br /&gt;
  text-overflow: ellipsis;&lt;br /&gt;
  white-space: nowrap;&lt;br /&gt;
  overflow: hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.texte-long:hover,&lt;br /&gt;
.texte-long-2:hover {&lt;br /&gt;
  white-space: normal;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.shop-img img {&lt;br /&gt;
  height: auto;&lt;br /&gt;
  width: auto;&lt;br /&gt;
  max-height: 130px;&lt;br /&gt;
  max-width: 130px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#mw-content .soulignement &amp;gt; a:link {&lt;br /&gt;
  text-decoration: none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* Remplacer popInfo et popContenu par pop-parent et pop-content */&lt;br /&gt;
.popContenu {&lt;br /&gt;
  display: inline-block;&lt;br /&gt;
  transition: all 0.4s ease;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.popInfo:hover .popContenu {&lt;br /&gt;
  opacity: 1 !important;&lt;br /&gt;
  transition: all 0.4s ease;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.pop-parent:hover .pop-content {&lt;br /&gt;
  opacity: 1;&lt;br /&gt;
  transition: opacity 0.4s ease;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.pop-content {&lt;br /&gt;
  opacity: 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.cadreFenetre,&lt;br /&gt;
.game-window {&lt;br /&gt;
  border: solid;&lt;br /&gt;
  border-image: url(&amp;quot;https://fr-wiki.metin2.gameforge.com/images/1/11/Cadrefenetre.png&amp;quot;)&lt;br /&gt;
    11 fill / auto / 0 repeat;&lt;br /&gt;
  padding: 10px;&lt;br /&gt;
  backdrop-filter: blur(4px);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tabber-active.button {&lt;br /&gt;
  background: rgba(75, 85, 95);&lt;br /&gt;
  color: white;&lt;br /&gt;
  border: 2px solid rgba(75, 85, 95);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
ul.subpage {&lt;br /&gt;
  display: flex;&lt;br /&gt;
  list-style: none;&lt;br /&gt;
  margin: 0 0 10px;&lt;br /&gt;
  padding: 0;&lt;br /&gt;
  background: rgba(81, 36, 16, 0.3);&lt;br /&gt;
  overflow: hidden;&lt;br /&gt;
  line-height: 30px;&lt;br /&gt;
  white-space: nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.subpage a {&lt;br /&gt;
  padding-left: 20px;&lt;br /&gt;
  background: #512410;&lt;br /&gt;
  display: inline-block;&lt;br /&gt;
  line-height: 30px;&lt;br /&gt;
  position: relative;&lt;br /&gt;
  color: #f1de8e;&lt;br /&gt;
  cursor: pointer;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.subpage a:before,&lt;br /&gt;
.subpage a:after {&lt;br /&gt;
  content: &amp;quot;&amp;quot;;&lt;br /&gt;
  position: absolute;&lt;br /&gt;
  width: 0;&lt;br /&gt;
  height: 0;&lt;br /&gt;
  right: 0;&lt;br /&gt;
  padding: 1px 0;&lt;br /&gt;
  border-top: 14px solid transparent;&lt;br /&gt;
  border-bottom: 14px solid transparent;&lt;br /&gt;
  border-left: 14px solid white;&lt;br /&gt;
  transform: translate(14px);&lt;br /&gt;
  z-index: 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.subpage a:after {&lt;br /&gt;
  border-left: 14px solid #512410;&lt;br /&gt;
  transform: translate(13px);&lt;br /&gt;
  z-index: 2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.subpage &amp;gt; li:last-child {&lt;br /&gt;
  padding-left: 20px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
ul.subpage &amp;gt; li:first-child {&lt;br /&gt;
  flex-shrink: 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
ul.subpage &amp;gt; li:first-child &amp;gt; a {&lt;br /&gt;
  height: 100%;&lt;br /&gt;
  display: flex;&lt;br /&gt;
  align-items: center;&lt;br /&gt;
  padding-left: 10px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
ul.subpage &amp;gt; li &amp;gt; a:hover {&lt;br /&gt;
  background: #9d5b37;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
ul.subpage &amp;gt; li &amp;gt; a:hover:after {&lt;br /&gt;
  border-left-color: #9d5b37;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.image-sizing img,&lt;br /&gt;
.image-sizing-200 img,&lt;br /&gt;
.image-sizing-none img {&lt;br /&gt;
  height: auto;&lt;br /&gt;
  width: auto;&lt;br /&gt;
  max-height: 300px;&lt;br /&gt;
  max-width: 100%;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.image-sizing-200 img {&lt;br /&gt;
  max-height: 200px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.image-sizing-none img {&lt;br /&gt;
  max-height: none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
div.ul-res ul {&lt;br /&gt;
  margin: 0;&lt;br /&gt;
  list-style: none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tab-glob {&lt;br /&gt;
  display: flex;&lt;br /&gt;
  flex-direction: row;&lt;br /&gt;
  margin: 10px 0;&lt;br /&gt;
  column-gap: 2px;&lt;br /&gt;
  align-items: flex-start;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tab-glob &amp;gt; :first-child {&lt;br /&gt;
  display: grid;&lt;br /&gt;
  grid-template-columns: max-content;&lt;br /&gt;
  row-gap: 2px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tab-glob &amp;gt; :first-child &amp;gt; * {&lt;br /&gt;
  border: 1px black solid;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tab-glob &amp;gt; :first-child &amp;gt; *:not(.fondfenetre) {&lt;br /&gt;
  font-weight: bold;&lt;br /&gt;
  display: flex;&lt;br /&gt;
  justify-content: center;&lt;br /&gt;
  align-items: center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tab-glob &amp;gt; :nth-child(2) {&lt;br /&gt;
  width: 100%;&lt;br /&gt;
  overflow-x: auto;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tab-glob &amp;gt; :nth-child(2) &amp;gt; :first-child {&lt;br /&gt;
  display: grid;&lt;br /&gt;
  grid-template-columns: repeat(10, minmax(75px, 1fr));&lt;br /&gt;
  gap: 2px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tab-glob &amp;gt; :nth-child(2) &amp;gt; :first-child &amp;gt; * {&lt;br /&gt;
  border: 1px black solid;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tab-glob &amp;gt; :nth-child(2) &amp;gt; :first-child &amp;gt; :not(.fondfenetre) {&lt;br /&gt;
  display: flex;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tab-glob &amp;gt; :nth-child(2) &amp;gt; :first-child &amp;gt; :not(.fondfenetre) &amp;gt; * {&lt;br /&gt;
  margin: auto;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.list-equip {&lt;br /&gt;
  padding: 5px;&lt;br /&gt;
  border: 1px solid #2f1d1f;&lt;br /&gt;
  display: flex;&lt;br /&gt;
  flex-direction: column;&lt;br /&gt;
  align-items: center;&lt;br /&gt;
  gap: 5px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.list-equip &amp;gt; :first-child {&lt;br /&gt;
  width: 100%;&lt;br /&gt;
  line-height: 25px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.list-equip &amp;gt; :first-child &amp;gt; * {&lt;br /&gt;
  padding: 0 5px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.fabrication {&lt;br /&gt;
  position: relative;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.fabrication &amp;gt; * {&lt;br /&gt;
  position: absolute;&lt;br /&gt;
  top: -188px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.fabrication &amp;gt; .bottom-fab,&lt;br /&gt;
.fabrication &amp;gt; .bottom-fab ~ * {&lt;br /&gt;
  top: -58px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.fabrication &amp;gt; * &amp;gt; *:nth-child(2) {&lt;br /&gt;
  position: relative;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.fabrication &amp;gt; * &amp;gt; *:nth-child(2) &amp;gt; * {&lt;br /&gt;
  position: absolute;&lt;br /&gt;
  top: -18px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.fabrication &amp;gt; * &amp;gt; *:nth-child(n + 3) {&lt;br /&gt;
  position: absolute;&lt;br /&gt;
  top: 100px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.info-boutique ul {&lt;br /&gt;
  list-style-image: none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.info-boutique p:last-child {&lt;br /&gt;
  margin-bottom: 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
kbd {&lt;br /&gt;
  background-color: #eee;&lt;br /&gt;
  border-radius: 3px;&lt;br /&gt;
  border: 1px solid #b4b4b4;&lt;br /&gt;
  box-shadow: 0 1px 1px rgb(0 0 0 / 20%), 0 2px 0 0 rgb(255 255 255 / 70%) inset;&lt;br /&gt;
  color: #333;&lt;br /&gt;
  display: inline-block;&lt;br /&gt;
  font-size: 0.85em;&lt;br /&gt;
  font-weight: 700;&lt;br /&gt;
  line-height: 1;&lt;br /&gt;
  padding: 2px 4px;&lt;br /&gt;
  white-space: nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.top-button {&lt;br /&gt;
  display: flex;&lt;br /&gt;
  justify-content: center;&lt;br /&gt;
  align-items: center;&lt;br /&gt;
  opacity: 0;&lt;br /&gt;
  cursor: pointer;&lt;br /&gt;
  position: fixed;&lt;br /&gt;
  bottom: 10px;&lt;br /&gt;
  right: 10px;&lt;br /&gt;
  width: 32px;&lt;br /&gt;
  height: 32px;&lt;br /&gt;
  background: linear-gradient(&lt;br /&gt;
    180deg,&lt;br /&gt;
    rgba(124, 200, 65, 1) 0%,&lt;br /&gt;
    rgba(113, 161, 85, 1) 50%,&lt;br /&gt;
    rgba(64, 117, 39, 1) 50%,&lt;br /&gt;
    rgba(46, 97, 31, 1) 100%&lt;br /&gt;
  );&lt;br /&gt;
  border: 1px solid #d0af52;&lt;br /&gt;
  box-shadow: 1px 1px 2px #000, inset 1px 1px #090200, inset -1px -1px #090200;&lt;br /&gt;
  transform: translateY(100px);&lt;br /&gt;
  transition: all 0.5s ease;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.top-button:after {&lt;br /&gt;
  content: &amp;quot;&amp;quot;;&lt;br /&gt;
  height: 32px;&lt;br /&gt;
  width: 32px;&lt;br /&gt;
  background-image: url(&amp;quot;data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fffacb' height='32' viewBox='0 -960 960 960' width='32'%3E%3Cpath d='m296-345-56-56 240-240 240 240-56 56-184-184-184 184Z'/%3E%3C/svg%3E&amp;quot;);&lt;br /&gt;
  background-repeat: no-repeat;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.show-button {&lt;br /&gt;
  opacity: 1;&lt;br /&gt;
  transform: translateY(0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.ul-row ul {&lt;br /&gt;
  display: flex;&lt;br /&gt;
  column-gap: 30px;&lt;br /&gt;
  flex-wrap: wrap;&lt;br /&gt;
  overflow: hidden;&lt;br /&gt;
  margin: 0;&lt;br /&gt;
  list-style-image: none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.flex {&lt;br /&gt;
  display: flex;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#catlinks {&lt;br /&gt;
  margin-top: 10px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.improved-collapsible &amp;gt; .mw-collapsible-toggle {&lt;br /&gt;
  grid-area: 1 / -1;&lt;br /&gt;
  display: flex;&lt;br /&gt;
  justify-content: flex-end;&lt;br /&gt;
  align-items: center;&lt;br /&gt;
  float: initial;&lt;br /&gt;
  z-index: 1;&lt;br /&gt;
  padding-right: 5px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.improved-collapsible .mw-collapsible-toggle:before {&lt;br /&gt;
  content: &amp;quot;&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.improved-collapsible .mw-collapsible-text {&lt;br /&gt;
  display: none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.improved-collapsible .mw-collapsible-toggle:after {&lt;br /&gt;
  width: 32px;&lt;br /&gt;
  height: 32px;&lt;br /&gt;
  content: &amp;quot;&amp;quot;;&lt;br /&gt;
  background-image: url(&amp;quot;data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23000000' height='32' viewBox='0 -960 960 960' width='32'%3E%3Cpath d='M480-345 240-585l56-56 184 184 184-184 56 56-240 240Z'/%3E%3C/svg%3E&amp;quot;);&lt;br /&gt;
  background-repeat: no-repeat;&lt;br /&gt;
  transition: transform 0.2s ease-in-out;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.improved-collapsible .mw-collapsible-toggle-expanded:after {&lt;br /&gt;
  transform: rotate(-180deg);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tooltip-icon {&lt;br /&gt;
  background-image: url(&amp;quot;data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' height='24' viewBox='0 -960 960 960' width='24'%3E%3Cpath d='M443-285h75v-234h-75v234Zm36.895-311Q496-596 507-606.895q11-10.894 11-27Q518-650 507.105-661q-10.894-11-27-11Q464-672 453-661.105q-11 10.894-11 27Q442-618 452.895-607q10.894 11 27 11ZM480-90q-80.907 0-152.065-30.763-71.159-30.763-123.797-83.5Q151.5-257 120.75-328.087 90-399.175 90-480q0-80.907 30.763-152.065 30.763-71.159 83.5-123.797Q257-808.5 328.087-839.25 399.175-870 480-870q80.907 0 152.065 30.763 71.159 30.763 123.797 83.5Q808.5-703 839.25-631.913 870-560.825 870-480q0 80.907-30.763 152.065-30.763 71.159-83.5 123.797Q703-151.5 631.913-120.75 560.825-90 480-90Zm0-75q131.5 0 223.25-91.75T795-480q0-131.5-91.75-223.25T480-795q-131.5 0-223.25 91.75T165-480q0 131.5 91.75 223.25T480-165Zm0-315Z'/%3E%3C/svg%3E&amp;quot;);&lt;br /&gt;
  background-repeat: no-repeat;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tooltip-info {&lt;br /&gt;
  position: absolute;&lt;br /&gt;
  bottom: calc(100% + 8px);&lt;br /&gt;
  left: 50%;&lt;br /&gt;
  transform: translateX(-50%);&lt;br /&gt;
  max-width: 290px;&lt;br /&gt;
  width: max-content;&lt;br /&gt;
  z-index: 50;&lt;br /&gt;
  opacity: 0;&lt;br /&gt;
  visibility: hidden;&lt;br /&gt;
  transition: opacity 0.2s ease, visibility 0.2s ease;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tooltip-info:after {&lt;br /&gt;
  content: &amp;quot;&amp;quot;;&lt;br /&gt;
  border: 8px solid transparent;&lt;br /&gt;
  border-top-color: inherit;&lt;br /&gt;
  position: absolute;&lt;br /&gt;
  left: calc(50% - 8px);&lt;br /&gt;
  top: 100%;&lt;br /&gt;
  z-index: 50;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tooltip-icon:hover &amp;gt; .tooltip-info {&lt;br /&gt;
  opacity: 1;&lt;br /&gt;
  visibility: visible;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
input,&lt;br /&gt;
input[type=&amp;quot;checkbox&amp;quot;],&lt;br /&gt;
select {&lt;br /&gt;
  border: 3px #d0e0e3 solid;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
input[type=&amp;quot;checkbox&amp;quot;] {&lt;br /&gt;
  background-color: white;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
input[type=&amp;quot;checkbox&amp;quot;]:checked {&lt;br /&gt;
  background-color: #19bd94;&lt;br /&gt;
  border: none;&lt;br /&gt;
  position: relative;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
input[type=&amp;quot;checkbox&amp;quot;]:checked:after {&lt;br /&gt;
  content: &amp;quot;&amp;quot;;&lt;br /&gt;
  position: absolute;&lt;br /&gt;
  background: transparent;&lt;br /&gt;
  left: 20%;&lt;br /&gt;
  top: 20%;&lt;br /&gt;
  width: 45%;&lt;br /&gt;
  height: 25%;&lt;br /&gt;
  transform: rotate(-45deg);&lt;br /&gt;
  border: 0.18em white solid;&lt;br /&gt;
  border-top: none;&lt;br /&gt;
  border-right: none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
input:focus,&lt;br /&gt;
select:focus {&lt;br /&gt;
  border: 3px rgb(102, 175, 233) solid;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
input:focus:not([type='checkbox']),&lt;br /&gt;
select:focus {&lt;br /&gt;
  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075),&lt;br /&gt;
    0 0 8px rgba(102, 175, 233, 0.6);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.label-hover label:hover {&lt;br /&gt;
  background-color: rgba(0, 0, 0, 0.1);&lt;br /&gt;
  border-radius: 8px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.cacheTel,&lt;br /&gt;
.tabber-container &amp;gt; :last-child &amp;gt; :not(.tabber-active),&lt;br /&gt;
.tabber-noactive {&lt;br /&gt;
  display: none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes pnj-square {&lt;br /&gt;
  from {&lt;br /&gt;
    background-color: #f80000;&lt;br /&gt;
  }&lt;br /&gt;
  to {&lt;br /&gt;
    background-color: white;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes pnj-circle {&lt;br /&gt;
  from {&lt;br /&gt;
    border-color: #984c48;&lt;br /&gt;
  }&lt;br /&gt;
  to {&lt;br /&gt;
    border-color: white;&lt;br /&gt;
  }&lt;br /&gt;
  from {&lt;br /&gt;
    scale: 1;&lt;br /&gt;
  }&lt;br /&gt;
  to {&lt;br /&gt;
    scale: 0.1;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes loading {&lt;br /&gt;
  0% {&lt;br /&gt;
    transform: scale(1.5);&lt;br /&gt;
  }&lt;br /&gt;
  100% {&lt;br /&gt;
    transform: scale(1);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@media screen and (max-width: 768px) {&lt;br /&gt;
  .texte-long {&lt;br /&gt;
    white-space: normal;&lt;br /&gt;
    overflow: visible;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  .grid2 {&lt;br /&gt;
    grid-template-columns: repeat(2, 1fr) !important;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  .grid3 {&lt;br /&gt;
    grid-template-columns: repeat(3, auto) !important;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  .container {&lt;br /&gt;
    flex-direction: column;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  .cacheTel,&lt;br /&gt;
  .subpage &amp;gt; li:nth-last-child(2) &amp;gt; a {&lt;br /&gt;
    display: block;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  .top-button {&lt;br /&gt;
    background: rgba(0, 0, 0, 0.7);&lt;br /&gt;
    color: #999;&lt;br /&gt;
    border: none;&lt;br /&gt;
    box-shadow: none;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  .top-button::after {&lt;br /&gt;
    background-image: url(&amp;quot;data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23ffffff' height='24' viewBox='0 -960 960 960' width='24'%3E%3Cpath d='M440-80v-647L256-544l-56-56 280-280 280 280-56 57-184-184v647h-80Z'/%3E%3C/svg%3E&amp;quot;);&lt;br /&gt;
    height: 24px;&lt;br /&gt;
    width: 24px;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  .tooltip-icon {&lt;br /&gt;
    position: static;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  .tooltip-info {&lt;br /&gt;
    position: fixed;&lt;br /&gt;
    left: 20px;&lt;br /&gt;
    right: 20px;&lt;br /&gt;
    bottom: 50px;&lt;br /&gt;
    max-width: none;&lt;br /&gt;
    width: auto;&lt;br /&gt;
    transform: none;&lt;br /&gt;
    height: max-content;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  .subpage &amp;gt; li &amp;gt; a,&lt;br /&gt;
  .cacheOrdi,&lt;br /&gt;
  .tooltip-info:after {&lt;br /&gt;
    display: none;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@media screen and (max-width: 340px) {&lt;br /&gt;
  #mw-content {&lt;br /&gt;
    padding-left: 10px;&lt;br /&gt;
    padding-right: 10px;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@media screen and (min-width: 851px) {&lt;br /&gt;
  html {&lt;br /&gt;
    scroll-padding-top: 3.325em;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;/div&gt;</summary>
		<author><name>Dexter</name></author>
		
	</entry>
	<entry>
		<id>https://fr-wiki.metin2.gameforge.com/index.php?title=Mod%C3%A8le:Main_Page/News2&amp;diff=107333</id>
		<title>Modèle:Main Page/News2</title>
		<link rel="alternate" type="text/html" href="https://fr-wiki.metin2.gameforge.com/index.php?title=Mod%C3%A8le:Main_Page/News2&amp;diff=107333"/>
		<updated>2025-05-01T21:08:02Z</updated>

		<summary type="html">&lt;p&gt;Dexter : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;margin: 10px 0px 5px 0px&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;cadre&amp;quot; style=&amp;quot;border-color: #88283a; box-shadow: 2px 2px 5px black; font-size: 11px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-size: 12px;&amp;quot;&amp;gt;'''L'équipe''' [[image:Icone_france.png|12px]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;grid3&amp;quot; style=&amp;quot;display: grid; grid-template-columns: repeat(4, minmax(170px, 1fr)); grid-gap: 5px; text-align: center;&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: center; margin: 10px auto 5px; color: #CC00FF; font-weight: bold; font-size: 1.25em;&amp;quot;&amp;gt;ÉQUIPE WIKI&lt;br /&gt;
&amp;lt;div style=&amp;quot;margin-left: 20px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div&amp;gt;[[Image:Wm.png|150px|link=Wiki Manager]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;margin-left: 15px; color: #000000;&amp;quot;&amp;gt;Dexter&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div&amp;gt;[[Image:Redacteurwiki.png|150px|link=Rédacteurs Wiki]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;margin-left: 15px;&amp;quot;&amp;gt;[[Utilisateur:Equinox|Equinox]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;margin-left: 15px;&amp;quot;&amp;gt;[[Utilisateur:Gyoza|Gyoza]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;margin-left: 15px;&amp;quot;&amp;gt;[[Utilisateur:Khojine|Khojine]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: center; margin: 10px auto 5px; color: #CC0000; font-weight: bold; font-size: 1.25em;&amp;quot;&amp;gt;ÉQUIPE JEU&lt;br /&gt;
&amp;lt;div style=&amp;quot;margin-left: 20px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div&amp;gt;[[Image:Ga.png|150px|link=Game Admins]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;margin-left: 15px; color: #000000;&amp;quot;&amp;gt;Apogia&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;margin-left: 15px; color: #000000;&amp;quot;&amp;gt;[[Utilisateur:Cassini|Cassini]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div&amp;gt;[[Image:Sgm.png|150px|link=Super Game Master]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;margin-left: 15px; color: #000000;&amp;quot;&amp;gt;SunBlue&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;margin-left: 15px; color: #000000;&amp;quot;&amp;gt;Phobos&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div&amp;gt;[[Image:gm.png|150px|link=Game Master]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;margin-left: 15px; color: #000000;&amp;quot;&amp;gt;Elya&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;margin-left: 15px; color: #000000;&amp;quot;&amp;gt;Lesath&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;margin-left: 15px; color: #000000;&amp;quot;&amp;gt;Athina&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;margin-left: 15px; color: #000000;&amp;quot;&amp;gt;Elaris&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;margin-left: 15px; color: #000000;&amp;quot;&amp;gt;Niryu&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: center; margin: 10px auto 5px; color: #009900; font-weight: bold; font-size: 1.25em;&amp;quot;&amp;gt;ÉQUIPE FORUM&lt;br /&gt;
&amp;lt;div style=&amp;quot;margin-left: 20px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div&amp;gt;[[Image:Ba.png|150px|link=Board Admins]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;margin-left: 15px; color: #000000;&amp;quot;&amp;gt;Mr. Robot&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;margin-left: 15px; color: #000000;&amp;quot;&amp;gt;Szopen&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div&amp;gt;[[Image:Bm.png|150px|link=Modérateurs]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;margin-left: 15px; color: #000000;&amp;quot;&amp;gt;Dexter&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;margin-left: 15px; color: #000000;&amp;quot;&amp;gt;Inuyasha&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;text-align: center; margin: 10px auto 5px; color: #D66F14; font-weight: bold; font-size: 1.25em;&amp;quot;&amp;gt;ÉQUIPE MANAGER&lt;br /&gt;
&amp;lt;div&amp;gt;[[Image:COMAmetin2.png|150px|link=Team Manager]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;margin-left: 15px; color: #000000;&amp;quot;&amp;gt;Paso&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div&amp;gt;[[Image:TMmetin2.png|150px|link=Team Manager]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;margin-left: 15px; color: #000000;&amp;quot;&amp;gt;[[Utilisateur:Daitya|Daitya]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
----&lt;br /&gt;
&amp;lt;p style=&amp;quot;text-align:center&amp;quot;&amp;gt;'''Recrutement Wiki''' :&amp;lt;br/&amp;gt;&amp;lt;font color=&amp;quot;green&amp;quot;&amp;gt;&amp;lt;big&amp;gt;'''Ouvert !'''&amp;lt;/big&amp;gt;&amp;lt;/font&amp;gt;&amp;lt;/p&amp;gt;&lt;br /&gt;
----&lt;br /&gt;
&amp;lt;p style=&amp;quot;text-align:center&amp;quot;&amp;gt;Si vous constatez des erreurs ou avez des questions '''sur le wiki et uniquement sur le wiki''', vous pouvez nous contacter via l'adresse mail suivante :&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;center&amp;quot;&amp;gt;&amp;lt;div style=&amp;quot;padding: 2px 17px; display: inline-block; border: 1px solid #97100d; font-weight: bold; font-size: 1.2em;&amp;quot;&amp;gt;wiki@metin2.fr&amp;lt;/div&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Dexter</name></author>
		
	</entry>
	<entry>
		<id>https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Common.css&amp;diff=107309</id>
		<title>MediaWiki:Common.css</title>
		<link rel="alternate" type="text/html" href="https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Common.css&amp;diff=107309"/>
		<updated>2025-04-27T05:24:43Z</updated>

		<summary type="html">&lt;p&gt;Dexter : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;/* Le CSS placé ici sera chargé sur toutes les pages */&lt;br /&gt;
&lt;br /&gt;
html {&lt;br /&gt;
  scroll-behavior: smooth;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
  body {&lt;br /&gt;
    background-image: url('https://fr-wiki.metin2.gameforge.com/images/b/bf/Fondhalloween.png');&lt;br /&gt;
  }&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
body {&lt;br /&gt;
  background-image: url(&amp;quot;https://fr-wiki.metin2.gameforge.com/images/1/15/Fond2015.jpg&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#mw-content ul {&lt;br /&gt;
  margin-bottom: 0.3em;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#mw-content ol {&lt;br /&gt;
  list-style: none;&lt;br /&gt;
  counter-reset: custom-counter;&lt;br /&gt;
  margin: 0.3em 0 0.3em 1.6em;&lt;br /&gt;
  padding: 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
ol li {&lt;br /&gt;
  padding: 0;&lt;br /&gt;
  padding-left: 5px;&lt;br /&gt;
  counter-increment: custom-counter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
ol li::marker {&lt;br /&gt;
  content: counter(custom-counter) &amp;quot;.  &amp;quot;;&lt;br /&gt;
  font-weight: bold;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
td,&lt;br /&gt;
th {&lt;br /&gt;
  padding: 2px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.map span.mw-collapsible-toggle {&lt;br /&gt;
  padding-right: 10px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
table.map a.mw-collapsible-text,&lt;br /&gt;
.prettytable &amp;gt; span.mw-collapsible-toggle,&lt;br /&gt;
.prettytable &amp;gt; span.mw-collapsible-toggle &amp;gt; a {&lt;br /&gt;
  color: #ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.boxesheaderbackground,&lt;br /&gt;
.cadre &amp;gt; div:first-child {&lt;br /&gt;
  background: repeat&lt;br /&gt;
    url(&amp;quot;https://fr-wiki.metin2.gameforge.com/images/a/a7/Boxheaderbrown.png&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.cadre {&lt;br /&gt;
  border: 1px solid #2f1d1f;&lt;br /&gt;
  border-radius: 15px 0;&lt;br /&gt;
  width: 100%;&lt;br /&gt;
  box-shadow: 3px 3px 9px 0px #544e41;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.cadre &amp;gt; div:first-child {&lt;br /&gt;
  text-align: center;&lt;br /&gt;
  color: white;&lt;br /&gt;
  line-height: 25px;&lt;br /&gt;
  overflow: hidden;&lt;br /&gt;
  border-top-left-radius: 15px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.fondfenetre,&lt;br /&gt;
.sous-titre,&lt;br /&gt;
table.pretty-table th {&lt;br /&gt;
  background: url(&amp;quot;https://fr-wiki.metin2.gameforge.com/images/8/89/Fondfenetre.png&amp;quot;)&lt;br /&gt;
    repeat;&lt;br /&gt;
  color: white;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
table.pretty-table td {&lt;br /&gt;
  padding: 5px 10px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
table.pretty-table th {&lt;br /&gt;
  padding: 2px 10px;&lt;br /&gt;
  font-weight: normal;&lt;br /&gt;
  font-size: 1.1em;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
table.pretty-table tbody &amp;gt; *:nth-child(2n + 1) &amp;gt; td {&lt;br /&gt;
  background: rgba(0, 0, 0, 0.1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
table.pretty-table tr:hover {&lt;br /&gt;
  background: rgba(0, 0, 0, 0.05);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
table.pretty-table tr:first-child &amp;gt; th:first-child {&lt;br /&gt;
  border-radius: 8px 0 0 0;&lt;br /&gt;
  overflow: hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
table.pretty-table caption {&lt;br /&gt;
  margin-top: 10px;&lt;br /&gt;
  font-weight: bold;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.fondfenetre a,&lt;br /&gt;
.fondfenetre span,&lt;br /&gt;
table.pretty-table th a,&lt;br /&gt;
table.pretty-table th span {&lt;br /&gt;
  color: white;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
table.sticky-header-row thead tr {&lt;br /&gt;
  position: sticky;&lt;br /&gt;
  top: 0;&lt;br /&gt;
  z-index: 10;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
table.sticky-header-column th:first-child {&lt;br /&gt;
  position: sticky;&lt;br /&gt;
  left: 0;&lt;br /&gt;
  z-index: 20;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sous-titre {&lt;br /&gt;
  max-width: 180px;&lt;br /&gt;
  border: 1px solid black;&lt;br /&gt;
  border-radius: 8px;&lt;br /&gt;
  color: white;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.modeleAnnonce {&lt;br /&gt;
  border-image: url(&amp;quot;https://fr-wiki.metin2.gameforge.com/images/f/fb/Modeleannonce.png&amp;quot;)&lt;br /&gt;
    17 35 3 fill / auto / 0 repeat;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.container {&lt;br /&gt;
  display: flex;&lt;br /&gt;
  flex-direction: row;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.monster-card {&lt;br /&gt;
  border: 1px black solid;&lt;br /&gt;
  padding: 5px;&lt;br /&gt;
  max-width: 400px;&lt;br /&gt;
  box-sizing: border-box;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.monster-card &amp;gt; :first-child {&lt;br /&gt;
  display: flex;&lt;br /&gt;
  justify-content: space-between;&lt;br /&gt;
  margin-bottom: 5px;&lt;br /&gt;
  line-height: 25px;&lt;br /&gt;
  padding: 0 5px;&lt;br /&gt;
  background: none;&lt;br /&gt;
  background-color: black;&lt;br /&gt;
  color: white;&lt;br /&gt;
  white-space: nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.monster-card &amp;gt; :first-child a {&lt;br /&gt;
  color: white;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.monster-card &amp;gt; :nth-child(2) {&lt;br /&gt;
  display: flex;&lt;br /&gt;
  justify-content: space-between;&lt;br /&gt;
  margin-bottom: 5px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.monster-card &amp;gt; :nth-child(3) {&lt;br /&gt;
  background: rgba(0, 0, 0, 0.1);&lt;br /&gt;
  display: grid;&lt;br /&gt;
  justify-content: center;&lt;br /&gt;
  align-items: start;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
button.brown {&lt;br /&gt;
  background: #651e10;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
button.brown-transparent {&lt;br /&gt;
  background: #651e10cc;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
button.brown:hover,&lt;br /&gt;
button.brown:focus {&lt;br /&gt;
  background: #551a0e;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
button.red {&lt;br /&gt;
  background: #ef4444;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
button.red:hover,&lt;br /&gt;
button.red:focus {&lt;br /&gt;
  background: #b91c1c;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
button:active {&lt;br /&gt;
  opacity: 0.8;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.button {&lt;br /&gt;
  border: 2px solid grey;&lt;br /&gt;
  padding: 0 12px;&lt;br /&gt;
  line-height: 25px;&lt;br /&gt;
  border-radius: 16px;&lt;br /&gt;
  background: rgba(234, 234, 234);&lt;br /&gt;
  cursor: pointer;&lt;br /&gt;
  display: inline-block;&lt;br /&gt;
  position: relative;&lt;br /&gt;
  user-select: none;&lt;br /&gt;
  white-space: nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.button:hover {&lt;br /&gt;
  background: transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.modal {&lt;br /&gt;
  opacity: 0;&lt;br /&gt;
  visibility: hidden;&lt;br /&gt;
  transform: scale(1.1);&lt;br /&gt;
  transition: visibility 0s linear 0.25s, opacity 0.25s 0s, transform 0.25s;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.close-button {&lt;br /&gt;
  transition: color 0.2s linear, background-color 0.2s linear;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.close-button:hover {&lt;br /&gt;
  background-color: red;&lt;br /&gt;
  color: #ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.show-modal {&lt;br /&gt;
  opacity: 1;&lt;br /&gt;
  visibility: visible;&lt;br /&gt;
  transform: scale(1);&lt;br /&gt;
  transition: visibility 0s linear 0s, opacity 0.25s 0s, transform 0.25s;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.cacheOrdi,&lt;br /&gt;
.gen-active {&lt;br /&gt;
  display: block;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.texte-long,&lt;br /&gt;
.texte-long-2 {&lt;br /&gt;
  text-overflow: ellipsis;&lt;br /&gt;
  white-space: nowrap;&lt;br /&gt;
  overflow: hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.texte-long:hover,&lt;br /&gt;
.texte-long-2:hover {&lt;br /&gt;
  white-space: normal;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.shop-img img {&lt;br /&gt;
  height: auto;&lt;br /&gt;
  width: auto;&lt;br /&gt;
  max-height: 130px;&lt;br /&gt;
  max-width: 130px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#mw-content .soulignement &amp;gt; a:link {&lt;br /&gt;
  text-decoration: none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.popContenu {&lt;br /&gt;
  display: inline-block;&lt;br /&gt;
  transition: all 0.4s ease;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.popInfo:hover .popContenu {&lt;br /&gt;
  opacity: 1 !important;&lt;br /&gt;
  transition: all 0.4s ease;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.cadreFenetre {&lt;br /&gt;
  border: solid;&lt;br /&gt;
  border-image: url(&amp;quot;https://fr-wiki.metin2.gameforge.com/images/1/11/Cadrefenetre.png&amp;quot;)&lt;br /&gt;
    11 fill / auto / 0 repeat;&lt;br /&gt;
  padding: 10px;&lt;br /&gt;
  backdrop-filter: blur(4px);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tabber-active.button {&lt;br /&gt;
  background: rgba(75, 85, 95);&lt;br /&gt;
  color: white;&lt;br /&gt;
  border: 2px solid rgba(75, 85, 95);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
ul.subpage {&lt;br /&gt;
  display: flex;&lt;br /&gt;
  list-style: none;&lt;br /&gt;
  margin: 0 0 10px;&lt;br /&gt;
  padding: 0;&lt;br /&gt;
  background: rgba(81, 36, 16, 0.3);&lt;br /&gt;
  overflow: hidden;&lt;br /&gt;
  line-height: 30px;&lt;br /&gt;
  white-space: nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.subpage a {&lt;br /&gt;
  padding-left: 20px;&lt;br /&gt;
  background: #512410;&lt;br /&gt;
  display: inline-block;&lt;br /&gt;
  line-height: 30px;&lt;br /&gt;
  position: relative;&lt;br /&gt;
  color: #f1de8e;&lt;br /&gt;
  cursor: pointer;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.subpage a:before,&lt;br /&gt;
.subpage a:after {&lt;br /&gt;
  content: &amp;quot;&amp;quot;;&lt;br /&gt;
  position: absolute;&lt;br /&gt;
  width: 0;&lt;br /&gt;
  height: 0;&lt;br /&gt;
  right: 0;&lt;br /&gt;
  padding: 1px 0;&lt;br /&gt;
  border-top: 14px solid transparent;&lt;br /&gt;
  border-bottom: 14px solid transparent;&lt;br /&gt;
  border-left: 14px solid white;&lt;br /&gt;
  transform: translate(14px);&lt;br /&gt;
  z-index: 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.subpage a:after {&lt;br /&gt;
  border-left: 14px solid #512410;&lt;br /&gt;
  transform: translate(13px);&lt;br /&gt;
  z-index: 2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.subpage &amp;gt; li:last-child {&lt;br /&gt;
  padding-left: 20px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
ul.subpage &amp;gt; li:first-child {&lt;br /&gt;
  flex-shrink: 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
ul.subpage &amp;gt; li:first-child &amp;gt; a {&lt;br /&gt;
  height: 100%;&lt;br /&gt;
  display: flex;&lt;br /&gt;
  align-items: center;&lt;br /&gt;
  padding-left: 10px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
ul.subpage &amp;gt; li &amp;gt; a:hover {&lt;br /&gt;
  background: #9d5b37;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
ul.subpage &amp;gt; li &amp;gt; a:hover:after {&lt;br /&gt;
  border-left-color: #9d5b37;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.image-sizing img,&lt;br /&gt;
.image-sizing-200 img,&lt;br /&gt;
.image-sizing-none img {&lt;br /&gt;
  height: auto;&lt;br /&gt;
  width: auto;&lt;br /&gt;
  max-height: 300px;&lt;br /&gt;
  max-width: 100%;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.image-sizing-200 img {&lt;br /&gt;
  max-height: 200px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.image-sizing-none img {&lt;br /&gt;
  max-height: none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
div.ul-res ul {&lt;br /&gt;
  margin: 0;&lt;br /&gt;
  list-style: none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tab-glob {&lt;br /&gt;
  display: flex;&lt;br /&gt;
  flex-direction: row;&lt;br /&gt;
  margin: 10px 0;&lt;br /&gt;
  column-gap: 2px;&lt;br /&gt;
  align-items: flex-start;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tab-glob &amp;gt; :first-child {&lt;br /&gt;
  display: grid;&lt;br /&gt;
  grid-template-columns: max-content;&lt;br /&gt;
  row-gap: 2px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tab-glob &amp;gt; :first-child &amp;gt; * {&lt;br /&gt;
  border: 1px black solid;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tab-glob &amp;gt; :first-child &amp;gt; *:not(.fondfenetre) {&lt;br /&gt;
  font-weight: bold;&lt;br /&gt;
  display: flex;&lt;br /&gt;
  justify-content: center;&lt;br /&gt;
  align-items: center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tab-glob &amp;gt; :nth-child(2) {&lt;br /&gt;
  width: 100%;&lt;br /&gt;
  overflow-x: auto;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tab-glob &amp;gt; :nth-child(2) &amp;gt; :first-child {&lt;br /&gt;
  display: grid;&lt;br /&gt;
  grid-template-columns: repeat(10, minmax(75px, 1fr));&lt;br /&gt;
  gap: 2px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tab-glob &amp;gt; :nth-child(2) &amp;gt; :first-child &amp;gt; * {&lt;br /&gt;
  border: 1px black solid;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tab-glob &amp;gt; :nth-child(2) &amp;gt; :first-child &amp;gt; :not(.fondfenetre) {&lt;br /&gt;
  display: flex;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tab-glob &amp;gt; :nth-child(2) &amp;gt; :first-child &amp;gt; :not(.fondfenetre) &amp;gt; * {&lt;br /&gt;
  margin: auto;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.list-equip {&lt;br /&gt;
  padding: 5px;&lt;br /&gt;
  border: 1px solid #2f1d1f;&lt;br /&gt;
  display: flex;&lt;br /&gt;
  flex-direction: column;&lt;br /&gt;
  align-items: center;&lt;br /&gt;
  gap: 5px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.list-equip &amp;gt; :first-child {&lt;br /&gt;
  width: 100%;&lt;br /&gt;
  line-height: 25px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.list-equip &amp;gt; :first-child &amp;gt; * {&lt;br /&gt;
  padding: 0 5px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.fabrication {&lt;br /&gt;
  position: relative;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.fabrication &amp;gt; * {&lt;br /&gt;
  position: absolute;&lt;br /&gt;
  top: -188px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.fabrication &amp;gt; .bottom-fab,&lt;br /&gt;
.fabrication &amp;gt; .bottom-fab ~ * {&lt;br /&gt;
  top: -58px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.fabrication &amp;gt; * &amp;gt; *:nth-child(2) {&lt;br /&gt;
  position: relative;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.fabrication &amp;gt; * &amp;gt; *:nth-child(2) &amp;gt; * {&lt;br /&gt;
  position: absolute;&lt;br /&gt;
  top: -18px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.fabrication &amp;gt; * &amp;gt; *:nth-child(n + 3) {&lt;br /&gt;
  position: absolute;&lt;br /&gt;
  top: 100px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.info-boutique ul {&lt;br /&gt;
  list-style-image: none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.info-boutique p:last-child {&lt;br /&gt;
  margin-bottom: 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
kbd {&lt;br /&gt;
  background-color: #eee;&lt;br /&gt;
  border-radius: 3px;&lt;br /&gt;
  border: 1px solid #b4b4b4;&lt;br /&gt;
  box-shadow: 0 1px 1px rgb(0 0 0 / 20%), 0 2px 0 0 rgb(255 255 255 / 70%) inset;&lt;br /&gt;
  color: #333;&lt;br /&gt;
  display: inline-block;&lt;br /&gt;
  font-size: 0.85em;&lt;br /&gt;
  font-weight: 700;&lt;br /&gt;
  line-height: 1;&lt;br /&gt;
  padding: 2px 4px;&lt;br /&gt;
  white-space: nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.top-button {&lt;br /&gt;
  display: flex;&lt;br /&gt;
  justify-content: center;&lt;br /&gt;
  align-items: center;&lt;br /&gt;
  opacity: 0;&lt;br /&gt;
  cursor: pointer;&lt;br /&gt;
  position: fixed;&lt;br /&gt;
  bottom: 10px;&lt;br /&gt;
  right: 10px;&lt;br /&gt;
  width: 32px;&lt;br /&gt;
  height: 32px;&lt;br /&gt;
  background: linear-gradient(&lt;br /&gt;
    180deg,&lt;br /&gt;
    rgba(124, 200, 65, 1) 0%,&lt;br /&gt;
    rgba(113, 161, 85, 1) 50%,&lt;br /&gt;
    rgba(64, 117, 39, 1) 50%,&lt;br /&gt;
    rgba(46, 97, 31, 1) 100%&lt;br /&gt;
  );&lt;br /&gt;
  border: 1px solid #d0af52;&lt;br /&gt;
  box-shadow: 1px 1px 2px #000, inset 1px 1px #090200, inset -1px -1px #090200;&lt;br /&gt;
  transform: translateY(100px);&lt;br /&gt;
  transition: all 0.5s ease;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.top-button:after {&lt;br /&gt;
  content: &amp;quot;&amp;quot;;&lt;br /&gt;
  height: 32px;&lt;br /&gt;
  width: 32px;&lt;br /&gt;
  background-image: url(&amp;quot;data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fffacb' height='32' viewBox='0 -960 960 960' width='32'%3E%3Cpath d='m296-345-56-56 240-240 240 240-56 56-184-184-184 184Z'/%3E%3C/svg%3E&amp;quot;);&lt;br /&gt;
  background-repeat: no-repeat;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.show-button {&lt;br /&gt;
  opacity: 1;&lt;br /&gt;
  transform: translateY(0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.ul-row ul {&lt;br /&gt;
  display: flex;&lt;br /&gt;
  column-gap: 30px;&lt;br /&gt;
  flex-wrap: wrap;&lt;br /&gt;
  overflow: hidden;&lt;br /&gt;
  margin: 0;&lt;br /&gt;
  list-style-image: none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.flex {&lt;br /&gt;
  display: flex;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#catlinks {&lt;br /&gt;
  margin-top: 10px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.improved-collapsible &amp;gt; .mw-collapsible-toggle {&lt;br /&gt;
  grid-area: 1 / -1;&lt;br /&gt;
  display: flex;&lt;br /&gt;
  justify-content: flex-end;&lt;br /&gt;
  align-items: center;&lt;br /&gt;
  float: initial;&lt;br /&gt;
  z-index: 1;&lt;br /&gt;
  padding-right: 5px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.improved-collapsible .mw-collapsible-toggle:before {&lt;br /&gt;
  content: &amp;quot;&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.improved-collapsible .mw-collapsible-text {&lt;br /&gt;
  display: none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.improved-collapsible .mw-collapsible-toggle:after {&lt;br /&gt;
  width: 32px;&lt;br /&gt;
  height: 32px;&lt;br /&gt;
  content: &amp;quot;&amp;quot;;&lt;br /&gt;
  background-image: url(&amp;quot;data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23000000' height='32' viewBox='0 -960 960 960' width='32'%3E%3Cpath d='M480-345 240-585l56-56 184 184 184-184 56 56-240 240Z'/%3E%3C/svg%3E&amp;quot;);&lt;br /&gt;
  background-repeat: no-repeat;&lt;br /&gt;
  transition: transform 0.2s ease-in-out;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.improved-collapsible .mw-collapsible-toggle-expanded:after {&lt;br /&gt;
  transform: rotate(-180deg);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tooltip-icon {&lt;br /&gt;
  background-image: url(&amp;quot;data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' height='24' viewBox='0 -960 960 960' width='24'%3E%3Cpath d='M443-285h75v-234h-75v234Zm36.895-311Q496-596 507-606.895q11-10.894 11-27Q518-650 507.105-661q-10.894-11-27-11Q464-672 453-661.105q-11 10.894-11 27Q442-618 452.895-607q10.894 11 27 11ZM480-90q-80.907 0-152.065-30.763-71.159-30.763-123.797-83.5Q151.5-257 120.75-328.087 90-399.175 90-480q0-80.907 30.763-152.065 30.763-71.159 83.5-123.797Q257-808.5 328.087-839.25 399.175-870 480-870q80.907 0 152.065 30.763 71.159 30.763 123.797 83.5Q808.5-703 839.25-631.913 870-560.825 870-480q0 80.907-30.763 152.065-30.763 71.159-83.5 123.797Q703-151.5 631.913-120.75 560.825-90 480-90Zm0-75q131.5 0 223.25-91.75T795-480q0-131.5-91.75-223.25T480-795q-131.5 0-223.25 91.75T165-480q0 131.5 91.75 223.25T480-165Zm0-315Z'/%3E%3C/svg%3E&amp;quot;);&lt;br /&gt;
  background-repeat: no-repeat;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tooltip-info {&lt;br /&gt;
  position: absolute;&lt;br /&gt;
  bottom: calc(100% + 8px);&lt;br /&gt;
  left: 50%;&lt;br /&gt;
  transform: translateX(-50%);&lt;br /&gt;
  max-width: 290px;&lt;br /&gt;
  width: max-content;&lt;br /&gt;
  z-index: 50;&lt;br /&gt;
  opacity: 0;&lt;br /&gt;
  visibility: hidden;&lt;br /&gt;
  transition: opacity 0.2s ease, visibility 0.2s ease;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tooltip-info:after {&lt;br /&gt;
  content: &amp;quot;&amp;quot;;&lt;br /&gt;
  border: 8px solid transparent;&lt;br /&gt;
  border-top-color: inherit;&lt;br /&gt;
  position: absolute;&lt;br /&gt;
  left: calc(50% - 8px);&lt;br /&gt;
  top: 100%;&lt;br /&gt;
  z-index: 50;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tooltip-icon:hover &amp;gt; .tooltip-info {&lt;br /&gt;
  opacity: 1;&lt;br /&gt;
  visibility: visible;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
input,&lt;br /&gt;
input[type=&amp;quot;checkbox&amp;quot;],&lt;br /&gt;
select {&lt;br /&gt;
  border: 3px #d0e0e3 solid;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
input[type=&amp;quot;checkbox&amp;quot;] {&lt;br /&gt;
  background-color: white;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
input[type=&amp;quot;checkbox&amp;quot;]:checked {&lt;br /&gt;
  background-color: #19bd94;&lt;br /&gt;
  border: none;&lt;br /&gt;
  position: relative;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
input[type=&amp;quot;checkbox&amp;quot;]:checked:after {&lt;br /&gt;
  content: &amp;quot;&amp;quot;;&lt;br /&gt;
  position: absolute;&lt;br /&gt;
  background: transparent;&lt;br /&gt;
  left: 20%;&lt;br /&gt;
  top: 20%;&lt;br /&gt;
  width: 45%;&lt;br /&gt;
  height: 25%;&lt;br /&gt;
  transform: rotate(-45deg);&lt;br /&gt;
  border: 0.18em white solid;&lt;br /&gt;
  border-top: none;&lt;br /&gt;
  border-right: none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
input:focus,&lt;br /&gt;
select:focus {&lt;br /&gt;
  border: 3px rgb(102, 175, 233) solid;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
input:focus:not([type='checkbox']),&lt;br /&gt;
select:focus {&lt;br /&gt;
  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075),&lt;br /&gt;
    0 0 8px rgba(102, 175, 233, 0.6);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.label-hover label:hover {&lt;br /&gt;
  background-color: rgba(0, 0, 0, 0.1);&lt;br /&gt;
  border-radius: 8px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.cacheTel,&lt;br /&gt;
.tabber-container &amp;gt; :last-child &amp;gt; :not(.tabber-active),&lt;br /&gt;
.tabber-noactive {&lt;br /&gt;
  display: none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes pnj-square {&lt;br /&gt;
  from {&lt;br /&gt;
    background-color: #f80000;&lt;br /&gt;
  }&lt;br /&gt;
  to {&lt;br /&gt;
    background-color: white;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes pnj-circle {&lt;br /&gt;
  from {&lt;br /&gt;
    border-color: #984c48;&lt;br /&gt;
  }&lt;br /&gt;
  to {&lt;br /&gt;
    border-color: white;&lt;br /&gt;
  }&lt;br /&gt;
  from {&lt;br /&gt;
    scale: 1;&lt;br /&gt;
  }&lt;br /&gt;
  to {&lt;br /&gt;
    scale: 0.1;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes loading {&lt;br /&gt;
  0% {&lt;br /&gt;
    transform: scale(1.5);&lt;br /&gt;
  }&lt;br /&gt;
  100% {&lt;br /&gt;
    transform: scale(1);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@media screen and (max-width: 768px) {&lt;br /&gt;
  .texte-long {&lt;br /&gt;
    white-space: normal;&lt;br /&gt;
    overflow: visible;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  .grid2 {&lt;br /&gt;
    grid-template-columns: repeat(2, 1fr) !important;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  .grid3 {&lt;br /&gt;
    grid-template-columns: repeat(3, auto) !important;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  .container {&lt;br /&gt;
    flex-direction: column;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  .cacheTel,&lt;br /&gt;
  .subpage &amp;gt; li:nth-last-child(2) &amp;gt; a {&lt;br /&gt;
    display: block;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  .top-button {&lt;br /&gt;
    background: rgba(0, 0, 0, 0.7);&lt;br /&gt;
    color: #999;&lt;br /&gt;
    border: none;&lt;br /&gt;
    box-shadow: none;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  .top-button::after {&lt;br /&gt;
    background-image: url(&amp;quot;data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23ffffff' height='24' viewBox='0 -960 960 960' width='24'%3E%3Cpath d='M440-80v-647L256-544l-56-56 280-280 280 280-56 57-184-184v647h-80Z'/%3E%3C/svg%3E&amp;quot;);&lt;br /&gt;
    height: 24px;&lt;br /&gt;
    width: 24px;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  .tooltip-icon {&lt;br /&gt;
    position: static;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  .tooltip-info {&lt;br /&gt;
    position: fixed;&lt;br /&gt;
    left: 20px;&lt;br /&gt;
    right: 20px;&lt;br /&gt;
    bottom: 50px;&lt;br /&gt;
    max-width: none;&lt;br /&gt;
    width: auto;&lt;br /&gt;
    transform: none;&lt;br /&gt;
    height: max-content;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  .subpage &amp;gt; li &amp;gt; a,&lt;br /&gt;
  .cacheOrdi,&lt;br /&gt;
  .tooltip-info:after {&lt;br /&gt;
    display: none;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@media screen and (max-width: 340px) {&lt;br /&gt;
  #mw-content {&lt;br /&gt;
    padding-left: 10px;&lt;br /&gt;
    padding-right: 10px;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@media screen and (min-width: 851px) {&lt;br /&gt;
  html {&lt;br /&gt;
    scroll-padding-top: 3.325em;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;/div&gt;</summary>
		<author><name>Dexter</name></author>
		
	</entry>
	<entry>
		<id>https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Script/Calculator.js&amp;diff=107038</id>
		<title>MediaWiki:Script/Calculator.js</title>
		<link rel="alternate" type="text/html" href="https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Script/Calculator.js&amp;diff=107038"/>
		<updated>2025-04-01T16:04:49Z</updated>

		<summary type="html">&lt;p&gt;Dexter : v1.0&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;function removeAccent(str) {&lt;br /&gt;
  return str.normalize(&amp;quot;NFD&amp;quot;).replace(/[\u0300-\u036f]/g, &amp;quot;&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function pseudoFormat(str) {&lt;br /&gt;
  return removeAccent(str).replace(/[^A-Za-z0-9 \(\)\+_-]+/g, &amp;quot;&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isValueInArray(value, array) {&lt;br /&gt;
  return array.indexOf(value) !== -1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function splitFirst(value, delimiter) {&lt;br /&gt;
  var parts = value.split(delimiter);&lt;br /&gt;
  var first = parts[0];&lt;br /&gt;
  var rest = parts.slice(1).join(delimiter);&lt;br /&gt;
  return [first, rest];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function copyObject(object) {&lt;br /&gt;
  var copy = {};&lt;br /&gt;
  for (var key in object) {&lt;br /&gt;
    copy[key] = object[key];&lt;br /&gt;
  }&lt;br /&gt;
  return copy;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function compareNumbers(a, b) {&lt;br /&gt;
  return b - a;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isChecked(attribute) {&lt;br /&gt;
  return attribute === &amp;quot;on&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function floorMultiplication(firstFactor, secondFactor) {&lt;br /&gt;
  return Math.floor((firstFactor * secondFactor).toFixed(8));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function truncateNumber(number, precision) {&lt;br /&gt;
  return Math.floor(number * 10 ** precision) / 10 ** precision;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function newChangeEvent() {&lt;br /&gt;
  return new Event(&amp;quot;change&amp;quot;, { bubbles: true });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function openTargetTab(target) {&lt;br /&gt;
  var tabberContainer = target.closest(&amp;quot;.tabber-container&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (!tabberContainer) {&lt;br /&gt;
    return;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var [buttonsContainer, tabsContainer] = tabberContainer.children;&lt;br /&gt;
  var buttons = buttonsContainer.children;&lt;br /&gt;
  var tabs = tabsContainer.children;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; tabs.length; index++) {&lt;br /&gt;
    var tab = tabs[index];&lt;br /&gt;
    if (tab.contains(target) &amp;amp;&amp;amp; !tab.checkVisibility()) {&lt;br /&gt;
      buttons[index].click();&lt;br /&gt;
      break;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function openTargetCollapsible(target) {&lt;br /&gt;
  var collapsible = target.closest(&amp;quot;.improved-collapsible&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (!collapsible) {&lt;br /&gt;
    return;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var span = collapsible.firstElementChild;&lt;br /&gt;
&lt;br /&gt;
  if (!span.classList.contains(&amp;quot;mw-collapsible-toggle-expanded&amp;quot;)) {&lt;br /&gt;
    span.click();&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function editTableResultRow(row, valuesToDisplay, numberFormat) {&lt;br /&gt;
  row.innerHTML = &amp;quot;&amp;quot;;&lt;br /&gt;
  for (var index = 0; index &amp;lt; valuesToDisplay.length; index++) {&lt;br /&gt;
    var cell = row.insertCell();&lt;br /&gt;
    var textContent;&lt;br /&gt;
&lt;br /&gt;
    if (index &amp;gt;= 3) {&lt;br /&gt;
      textContent = numberFormat.format(valuesToDisplay[index]);&lt;br /&gt;
    } else {&lt;br /&gt;
      textContent = valuesToDisplay[index];&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    cell.textContent = textContent;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return row;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addRowToTableResultHistory(&lt;br /&gt;
  tableResultHistory,&lt;br /&gt;
  valuesToDisplay,&lt;br /&gt;
  deleteFightTemplate,&lt;br /&gt;
  numberFormat&lt;br /&gt;
) {&lt;br /&gt;
  var row = tableResultHistory.insertRow();&lt;br /&gt;
  editTableResultRow(row, valuesToDisplay, numberFormat);&lt;br /&gt;
  var cell = row.insertCell();&lt;br /&gt;
  cell.appendChild(deleteFightTemplate.cloneNode(true));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function processSavedDamage(savedDamage, damageWeightedByType, battleValues) {&lt;br /&gt;
  const { damageTypeWeights, attackTypeMapping } = battleValues;&lt;br /&gt;
&lt;br /&gt;
  for (const key in savedDamage) {&lt;br /&gt;
    const [weight, damageByType] = savedDamage[key];&lt;br /&gt;
&lt;br /&gt;
    for (let index = 0; index &amp;lt; 4; index++) {&lt;br /&gt;
      const damageWeighted = damageWeightedByType[attackTypeMapping[index]];&lt;br /&gt;
      const damageByTypeIndex = damageByType[index];&lt;br /&gt;
&lt;br /&gt;
      if (damageByTypeIndex.length === 0) continue;&lt;br /&gt;
&lt;br /&gt;
      const currentWeight =&lt;br /&gt;
        (weight * damageTypeWeights[index]) / damageByTypeIndex.length;&lt;br /&gt;
&lt;br /&gt;
      for (const damage of damageByTypeIndex) {&lt;br /&gt;
        damageWeighted[damage] = (damageWeighted[damage] || 0) + currentWeight;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcMeanDamage(damageWeightedByType, totalCardinal) {&lt;br /&gt;
  var sumDamage = 0;&lt;br /&gt;
&lt;br /&gt;
  for (var damageTypeName in damageWeightedByType) {&lt;br /&gt;
    if (damageTypeName === &amp;quot;miss&amp;quot;) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var damageWeighted = damageWeightedByType[damageTypeName];&lt;br /&gt;
&lt;br /&gt;
    for (var damage in damageWeighted) {&lt;br /&gt;
      sumDamage += damage * damageWeighted[damage];&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return sumDamage / totalCardinal;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function prepareDamageData(damageWeightedByType, attackValues) {&lt;br /&gt;
  const totalCardinal = attackValues.totalCardinal;&lt;br /&gt;
  const scatterDataByType = {};&lt;br /&gt;
  const criticalAttackRange = attackValues.criticalAttackRange;&lt;br /&gt;
&lt;br /&gt;
  let minDamage = Infinity;&lt;br /&gt;
  let maxDamage = 0;&lt;br /&gt;
  let sumDamage = 0;&lt;br /&gt;
&lt;br /&gt;
  let possibleDamageCount = 0;&lt;br /&gt;
  let possibleDamageCountTemp = 0;&lt;br /&gt;
  let uniqueDamageCount = 0;&lt;br /&gt;
&lt;br /&gt;
  for (const damageTypeName in damageWeightedByType) {&lt;br /&gt;
    if (damageTypeName === &amp;quot;miss&amp;quot;) {&lt;br /&gt;
      scatterDataByType.miss = damageWeightedByType.miss;&lt;br /&gt;
      possibleDamageCount++;&lt;br /&gt;
      uniqueDamageCount++;&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
    const damageWeighted = damageWeightedByType[damageTypeName];&lt;br /&gt;
    const scatterData = [];&lt;br /&gt;
&lt;br /&gt;
    scatterDataByType[damageTypeName] = scatterData;&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      (damageTypeName === &amp;quot;criticalHit&amp;quot; ||&lt;br /&gt;
        damageTypeName === &amp;quot;criticalPiercingHit&amp;quot;) &amp;amp;&amp;amp;&lt;br /&gt;
      criticalAttackRange&lt;br /&gt;
    ) {&lt;br /&gt;
      possibleDamageCountTemp =&lt;br /&gt;
        attackValues.possibleDamageCount * criticalAttackRange.length;&lt;br /&gt;
    } else {&lt;br /&gt;
      possibleDamageCountTemp = attackValues.possibleDamageCount;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    for (let damage in damageWeighted) {&lt;br /&gt;
      damage = +damage;&lt;br /&gt;
&lt;br /&gt;
      if (damage &amp;lt; minDamage) {&lt;br /&gt;
        minDamage = damage;&lt;br /&gt;
      }&lt;br /&gt;
      if (damage &amp;gt; maxDamage) {&lt;br /&gt;
        maxDamage = damage;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      const weight = damageWeighted[damage];&lt;br /&gt;
      const probability = weight / totalCardinal;&lt;br /&gt;
&lt;br /&gt;
      sumDamage += damage * weight;&lt;br /&gt;
      damageWeighted[damage] = probability;&lt;br /&gt;
      scatterData.push({ x: damage, y: probability });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    const scatterDataLength = scatterData.length;&lt;br /&gt;
&lt;br /&gt;
    if (!scatterDataLength) {&lt;br /&gt;
      delete scatterDataByType[damageTypeName];&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    possibleDamageCount += possibleDamageCountTemp;&lt;br /&gt;
    uniqueDamageCount += scatterDataLength;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (minDamage === Infinity) {&lt;br /&gt;
    minDamage = 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  attackValues.possibleDamageCount = possibleDamageCount;&lt;br /&gt;
&lt;br /&gt;
  return [&lt;br /&gt;
    sumDamage / totalCardinal,&lt;br /&gt;
    minDamage,&lt;br /&gt;
    maxDamage,&lt;br /&gt;
    scatterDataByType,&lt;br /&gt;
    uniqueDamageCount,&lt;br /&gt;
  ];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function aggregateDamage(scatterData, maxPoints) {&lt;br /&gt;
  var dataLength = scatterData.length;&lt;br /&gt;
  var remainingData = dataLength;&lt;br /&gt;
  var aggregateScatterData = [];&lt;br /&gt;
&lt;br /&gt;
  for (var groupIndex = 0; groupIndex &amp;lt; maxPoints; groupIndex++) {&lt;br /&gt;
    var groupLength = Math.floor(remainingData / (maxPoints - groupIndex));&lt;br /&gt;
    var startIndex = dataLength - remainingData;&lt;br /&gt;
    var aggregateDamage = 0;&lt;br /&gt;
    var aggregateProbability = 0;&lt;br /&gt;
&lt;br /&gt;
    for (var index = startIndex; index &amp;lt; startIndex + groupLength; index++) {&lt;br /&gt;
      var { x: damage, y: probability } = scatterData[index];&lt;br /&gt;
      aggregateDamage += damage * probability;&lt;br /&gt;
      aggregateProbability += probability;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    aggregateScatterData.push({&lt;br /&gt;
      x: aggregateDamage / aggregateProbability,&lt;br /&gt;
      y: aggregateProbability,&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    remainingData -= groupLength;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return aggregateScatterData;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addToDamageChart(battle, scatterDataByType) {&lt;br /&gt;
  const { chart, datasetsStyle, maxPoints, reduceChartPointsContainer } =&lt;br /&gt;
    battle.damageChart;&lt;br /&gt;
  const isReducePointsChecked = battle.reduceChartPoints.checked;&lt;br /&gt;
  const datasets = chart.data.datasets;&lt;br /&gt;
&lt;br /&gt;
  let isFirstDataset = true;&lt;br /&gt;
&lt;br /&gt;
  datasets.length = 0;&lt;br /&gt;
&lt;br /&gt;
  for (let index = 0; index &amp;lt; datasetsStyle.length; index++) {&lt;br /&gt;
    const dataset = copyObject(datasetsStyle[index]);&lt;br /&gt;
&lt;br /&gt;
    if (!scatterDataByType.hasOwnProperty(dataset.name)) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    const scatterData = scatterDataByType[dataset.name];&lt;br /&gt;
    const canBeReduced = scatterData.length &amp;gt; 2 * maxPoints;&lt;br /&gt;
&lt;br /&gt;
    dataset.hidden = !isFirstDataset;&lt;br /&gt;
    dataset.canBeReduced = canBeReduced;&lt;br /&gt;
&lt;br /&gt;
    if (canBeReduced &amp;amp;&amp;amp; isReducePointsChecked) {&lt;br /&gt;
      dataset.data = aggregateDamage(scatterData, maxPoints);&lt;br /&gt;
    } else {&lt;br /&gt;
      dataset.data = scatterData;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isFirstDataset) {&lt;br /&gt;
      isFirstDataset = false;&lt;br /&gt;
&lt;br /&gt;
      if (canBeReduced) {&lt;br /&gt;
        showElement(reduceChartPointsContainer);&lt;br /&gt;
&lt;br /&gt;
        if (!isReducePointsChecked) {&lt;br /&gt;
          handleChartAnimations(chart, false);&lt;br /&gt;
        }&lt;br /&gt;
      } else {&lt;br /&gt;
        hideElement(reduceChartPointsContainer);&lt;br /&gt;
        handleChartAnimations(chart, true);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    datasets.push(dataset);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  chart.data.missPercentage = scatterDataByType.miss;&lt;br /&gt;
  chart.update();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addToBonusVariationChart(&lt;br /&gt;
  damageByBonus,&lt;br /&gt;
  augmentationByBonus,&lt;br /&gt;
  xLabel,&lt;br /&gt;
  chart&lt;br /&gt;
) {&lt;br /&gt;
  chart.data.datasets[0].data = damageByBonus;&lt;br /&gt;
  chart.data.datasets[1].data = augmentationByBonus;&lt;br /&gt;
  chart.options.scales.x.title.text = xLabel;&lt;br /&gt;
  chart.update();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleChartAnimations(chart, addAnimations) {&lt;br /&gt;
  chart.options.animation = addAnimations;&lt;br /&gt;
  chart.options.animations.colors = addAnimations;&lt;br /&gt;
  chart.options.animations.x = addAnimations;&lt;br /&gt;
  chart.options.transitions.active.animation.duration = addAnimations * 1000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateDamageChartDescription(battle, uniqueDamageCount) {&lt;br /&gt;
  const {&lt;br /&gt;
    chartDescriptionContainer,&lt;br /&gt;
    uniqueDamageCounters,&lt;br /&gt;
    numberFormats: { default: defaultFormat },&lt;br /&gt;
  } = battle;&lt;br /&gt;
&lt;br /&gt;
  if (uniqueDamageCount &amp;gt; 1) {&lt;br /&gt;
    uniqueDamageCounters.forEach(function (element) {&lt;br /&gt;
      element.textContent = defaultFormat.format(uniqueDamageCount);&lt;br /&gt;
    });&lt;br /&gt;
    showElement(chartDescriptionContainer);&lt;br /&gt;
  } else {&lt;br /&gt;
    hideElement(chartDescriptionContainer);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getMonsterName(monsterVnum) {&lt;br /&gt;
  var monsterAttributes = monsterData[monsterVnum];&lt;br /&gt;
  return monsterAttributes[monsterAttributes.length - 1];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getTranslatedMonsterName(monsterVnum) {&lt;br /&gt;
  return translation.monsters[monsterVnum];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterClass(selectedRace, classChoice, selectValueIsChanged = false) {&lt;br /&gt;
  for (var radioNode of classChoice) {&lt;br /&gt;
    var radioGrandParent = radioNode.parentElement.parentElement;&lt;br /&gt;
&lt;br /&gt;
    if (radioNode.getAttribute(&amp;quot;data-race&amp;quot;) === selectedRace) {&lt;br /&gt;
      if (!selectValueIsChanged) {&lt;br /&gt;
        radioNode.checked = true;&lt;br /&gt;
        selectValueIsChanged = true;&lt;br /&gt;
      }&lt;br /&gt;
      showElement(radioGrandParent);&lt;br /&gt;
    } else {&lt;br /&gt;
      hideElement(radioGrandParent);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterWeapon(&lt;br /&gt;
  selectedRace,&lt;br /&gt;
  weaponElement,&lt;br /&gt;
  weaponCategory,&lt;br /&gt;
  allowedWeaponsPerRace,&lt;br /&gt;
  selectValueIsChanged = false&lt;br /&gt;
) {&lt;br /&gt;
  var allowedWeapons = allowedWeaponsPerRace[selectedRace];&lt;br /&gt;
&lt;br /&gt;
  if (!selectValueIsChanged) {&lt;br /&gt;
    var weaponType = createWeapon(weaponElement.value).type;&lt;br /&gt;
&lt;br /&gt;
    if (!isValueInArray(weaponType, allowedWeapons)) {&lt;br /&gt;
      weaponElement.value = 0;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var children = weaponCategory.children;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; children.length; index++) {&lt;br /&gt;
    var child = children[index];&lt;br /&gt;
&lt;br /&gt;
    if (isValueInArray(index, allowedWeapons)) {&lt;br /&gt;
      showElement(child);&lt;br /&gt;
    } else {&lt;br /&gt;
      hideElement(child);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function changePolymorphValues(characterCreation, monsterVnum, monsterImage) {&lt;br /&gt;
  var { polymorphMonster, polymorphMonsterImage } = characterCreation;&lt;br /&gt;
&lt;br /&gt;
  polymorphMonster.value = monsterVnum;&lt;br /&gt;
  polymorphMonsterImage.value = monsterImage;&lt;br /&gt;
&lt;br /&gt;
  polymorphMonster.dispatchEvent(newChangeEvent());&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function resetImageFromWiki(image) {&lt;br /&gt;
  image.removeAttribute(&amp;quot;srcset&amp;quot;);&lt;br /&gt;
  image.removeAttribute(&amp;quot;data-file-width&amp;quot;);&lt;br /&gt;
  image.removeAttribute(&amp;quot;data-file-height&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleImageFromWiki(image, newSrc) {&lt;br /&gt;
  image.src = newSrc;&lt;br /&gt;
  image.alt = newSrc.split(&amp;quot;/&amp;quot;).pop();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handlePolymorphDisplay(characters, monsterVnum, monsterSrc) {&lt;br /&gt;
  var { translateMonsters, polymorphDisplay } = characters;&lt;br /&gt;
  var oldImage = polymorphDisplay.firstChild;&lt;br /&gt;
  var oldLink = oldImage.nextElementSibling;&lt;br /&gt;
  var monsterName = getMonsterName(monsterVnum);&lt;br /&gt;
  var displayName = translateMonsters&lt;br /&gt;
    ? getTranslatedMonsterName(monsterVnum)&lt;br /&gt;
    : monsterName;&lt;br /&gt;
  var newLink = createWikiLink(monsterName, displayName);&lt;br /&gt;
&lt;br /&gt;
  resetImageFromWiki(oldImage);&lt;br /&gt;
  handleImageFromWiki(oldImage, monsterSrc);&lt;br /&gt;
&lt;br /&gt;
  polymorphDisplay.replaceChild(newLink, oldLink);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createWikiLink(pageName, displayName) {&lt;br /&gt;
  var wikiLink = document.createElement(&amp;quot;a&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  wikiLink.href = mw.util.getUrl(pageName);&lt;br /&gt;
  wikiLink.title = pageName;&lt;br /&gt;
  wikiLink.textContent = displayName || pageName;&lt;br /&gt;
&lt;br /&gt;
  return wikiLink;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSelectedWeapon(weaponCategory) {&lt;br /&gt;
  return weaponCategory.querySelector(&amp;quot;input[type='radio']:checked&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleWeaponDisplay(&lt;br /&gt;
  weaponCategory,&lt;br /&gt;
  weaponDisplay,&lt;br /&gt;
  weaponVnum,&lt;br /&gt;
  newWeapon&lt;br /&gt;
) {&lt;br /&gt;
  var newWeapon = newWeapon || getSelectedWeapon(weaponCategory);&lt;br /&gt;
&lt;br /&gt;
  var newImage = newWeapon.nextElementSibling;&lt;br /&gt;
  var newText = document.createElement(&amp;quot;span&amp;quot;);&lt;br /&gt;
  var oldImage = weaponDisplay.firstChild;&lt;br /&gt;
  var oldText = oldImage.nextElementSibling;&lt;br /&gt;
  var weaponTooltip = newImage.nextElementSibling;&lt;br /&gt;
  var originalWeaponName = weaponTooltip.dataset.o;&lt;br /&gt;
  var weaponName = weaponTooltip.textContent;&lt;br /&gt;
&lt;br /&gt;
  if (weaponVnum == 0) {&lt;br /&gt;
    newText.textContent = weaponName;&lt;br /&gt;
  } else {&lt;br /&gt;
    var weaponLink = createWikiLink(originalWeaponName, weaponName);&lt;br /&gt;
    newText.appendChild(weaponLink);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  weaponDisplay.replaceChild(newImage.cloneNode(), oldImage);&lt;br /&gt;
  weaponDisplay.replaceChild(newText, oldText);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterUpgrade(&lt;br /&gt;
  weaponUpgrade,&lt;br /&gt;
  weaponVnum,&lt;br /&gt;
  randomAttackValue,&lt;br /&gt;
  randomMagicAttackValue&lt;br /&gt;
) {&lt;br /&gt;
  var weapon = createWeapon(weaponVnum);&lt;br /&gt;
  var currentUpgrade = Number(weaponUpgrade.value);&lt;br /&gt;
  var weaponUpgradeChildren = weaponUpgrade.children;&lt;br /&gt;
&lt;br /&gt;
  if (weapon.isSerpent) {&lt;br /&gt;
    showElement(randomAttackValue);&lt;br /&gt;
&lt;br /&gt;
    if (weapon.isMagic) {&lt;br /&gt;
      showElement(randomMagicAttackValue);&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    hideElement(randomAttackValue);&lt;br /&gt;
    hideElement(randomMagicAttackValue);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (weapon.maxUpgrade &amp;lt; 1) {&lt;br /&gt;
    hideElement(weaponUpgrade.parentElement);&lt;br /&gt;
  } else {&lt;br /&gt;
    showElement(weaponUpgrade.parentElement);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (var upgrade = 0; upgrade &amp;lt;= weapon.maxUpgrade; upgrade++) {&lt;br /&gt;
    showElement(weaponUpgradeChildren[upgrade]);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (&lt;br /&gt;
    var upgrade = weapon.maxUpgrade + 1;&lt;br /&gt;
    upgrade &amp;lt; weaponUpgradeChildren.length;&lt;br /&gt;
    upgrade++&lt;br /&gt;
  ) {&lt;br /&gt;
    hideElement(weaponUpgradeChildren[upgrade]);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (currentUpgrade &amp;gt; weapon.maxUpgrade) {&lt;br /&gt;
    weaponUpgrade.value = weapon.maxUpgrade;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterCheckbox(checkbox, element) {&lt;br /&gt;
  if (checkbox.checked) {&lt;br /&gt;
    showElement(element);&lt;br /&gt;
  } else {&lt;br /&gt;
    hideElement(element);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterSkills(selectedClass, skillElementsToFilter) {&lt;br /&gt;
  for (var element of skillElementsToFilter) {&lt;br /&gt;
    if (isValueInArray(selectedClass, element.dataset.class)) {&lt;br /&gt;
      showElement(element);&lt;br /&gt;
    } else {&lt;br /&gt;
      hideElement(element);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterForm(characters, battle) {&lt;br /&gt;
  var { saveButton, characterCreation, toggleSiblings } = characters;&lt;br /&gt;
  var allowedWeaponsPerRace = battle.constants.allowedWeaponsPerRace;&lt;br /&gt;
  var battleChoice = battle.battleChoice;&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;change&amp;quot;, function (event) {&lt;br /&gt;
    var target = event.target;&lt;br /&gt;
    var targetName = target.name;&lt;br /&gt;
&lt;br /&gt;
    saveButtonOrange(saveButton);&lt;br /&gt;
    characters.unsavedChanges = true;&lt;br /&gt;
&lt;br /&gt;
    switch (targetName) {&lt;br /&gt;
      case &amp;quot;race&amp;quot;:&lt;br /&gt;
        var selectedRace = target.value;&lt;br /&gt;
        var classChoice = characterCreation.class;&lt;br /&gt;
        var weaponElement = characterCreation.weapon;&lt;br /&gt;
&lt;br /&gt;
        filterClass(selectedRace, classChoice);&lt;br /&gt;
        filterWeapon(&lt;br /&gt;
          selectedRace,&lt;br /&gt;
          weaponElement,&lt;br /&gt;
          characters.weaponCategory,&lt;br /&gt;
          allowedWeaponsPerRace&lt;br /&gt;
        );&lt;br /&gt;
        handleWeaponDisplay(&lt;br /&gt;
          characters.weaponCategory,&lt;br /&gt;
          characters.weaponDisplay,&lt;br /&gt;
          weaponElement.value&lt;br /&gt;
        );&lt;br /&gt;
        filterUpgrade(&lt;br /&gt;
          characterCreation.weaponUpgrade,&lt;br /&gt;
          weaponElement.value,&lt;br /&gt;
          characters.randomAttackValue,&lt;br /&gt;
          characters.randomMagicAttackValue&lt;br /&gt;
        );&lt;br /&gt;
        filterSkills(classChoice.value, characters.skillElementsToFilter);&lt;br /&gt;
        handleBonusVariationUpdate(&lt;br /&gt;
          characterCreation,&lt;br /&gt;
          characters.bonusVariation,&lt;br /&gt;
          true&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        battleChoice.resetAttackType = true;&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;class&amp;quot;:&lt;br /&gt;
        filterSkills(target.value, characters.skillElementsToFilter);&lt;br /&gt;
        handleBonusVariationUpdate(&lt;br /&gt;
          characterCreation,&lt;br /&gt;
          characters.bonusVariation,&lt;br /&gt;
          true&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        battleChoice.resetAttackType = true;&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;weapon&amp;quot;:&lt;br /&gt;
        var weaponElement = characterCreation.weapon;&lt;br /&gt;
&lt;br /&gt;
        handleWeaponDisplay(&lt;br /&gt;
          characters.weaponCategory,&lt;br /&gt;
          characters.weaponDisplay,&lt;br /&gt;
          weaponElement.value,&lt;br /&gt;
          target&lt;br /&gt;
        );&lt;br /&gt;
        filterUpgrade(&lt;br /&gt;
          characterCreation.weaponUpgrade,&lt;br /&gt;
          target.value,&lt;br /&gt;
          characters.randomAttackValue,&lt;br /&gt;
          characters.randomMagicAttackValue&lt;br /&gt;
        );&lt;br /&gt;
        handleBonusVariationUpdate(&lt;br /&gt;
          characterCreation,&lt;br /&gt;
          characters.bonusVariation&lt;br /&gt;
        );&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;isRiding&amp;quot;:&lt;br /&gt;
        battleChoice.resetAttackType = true;&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;isPolymorph&amp;quot;:&lt;br /&gt;
        battleChoice.resetAttackType = true;&lt;br /&gt;
        break;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (toggleSiblings.hasOwnProperty(targetName)) {&lt;br /&gt;
      filterCheckbox(target, toggleSiblings[targetName]);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      targetName.startsWith(&amp;quot;attackSkill&amp;quot;) ||&lt;br /&gt;
      targetName.startsWith(&amp;quot;horseSkill&amp;quot;)&lt;br /&gt;
    ) {&lt;br /&gt;
      battleChoice.resetAttackType = true;&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addUniquePseudo(characterDataObject, savedCharactersPseudo) {&lt;br /&gt;
  var characterPseudo = String(characterDataObject.name);&lt;br /&gt;
  var originalPseudo = characterPseudo;&lt;br /&gt;
  var count = 0;&lt;br /&gt;
&lt;br /&gt;
  var regex = /(.*)(\d)$/;&lt;br /&gt;
  var match = characterPseudo.match(regex);&lt;br /&gt;
&lt;br /&gt;
  if (match) {&lt;br /&gt;
    originalPseudo = match[1];&lt;br /&gt;
    count = match[2];&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  while (isValueInArray(characterPseudo, savedCharactersPseudo)) {&lt;br /&gt;
    characterPseudo = originalPseudo + count;&lt;br /&gt;
    count++;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  characterDataObject.name = characterPseudo;&lt;br /&gt;
  return [characterDataObject, characterPseudo];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function convertToNumber(value) {&lt;br /&gt;
  var valueNumber = Number(value);&lt;br /&gt;
  return isNaN(valueNumber) ? value : valueNumber;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getLocalStorageValue(key, defaultValue) {&lt;br /&gt;
  var storedValue = localStorage.getItem(key);&lt;br /&gt;
&lt;br /&gt;
  if (storedValue) {&lt;br /&gt;
    return JSON.parse(storedValue);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return defaultValue;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSavedCharacters() {&lt;br /&gt;
  return getLocalStorageValue(&amp;quot;mt2-calc.characters.saved&amp;quot;, {});&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSavedMonsters() {&lt;br /&gt;
  return getLocalStorageValue(&amp;quot;mt2-calc.monsters.saved&amp;quot;, {});&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSavedFights() {&lt;br /&gt;
  return getLocalStorageValue(&amp;quot;mt2-calc.fights.saved&amp;quot;, []);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getLastLang() {&lt;br /&gt;
  return getLocalStorageValue(&amp;quot;mt2-calc.language.last-used&amp;quot;, &amp;quot;&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveToLocalStorage(key, value) {&lt;br /&gt;
  localStorage.setItem(key, JSON.stringify(value));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateSavedCharacters(savedCharacters) {&lt;br /&gt;
  saveToLocalStorage(&amp;quot;mt2-calc.characters.saved&amp;quot;, savedCharacters);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateSavedMonsters(savedMonsters) {&lt;br /&gt;
  saveToLocalStorage(&amp;quot;mt2-calc.monsters.saved&amp;quot;, savedMonsters);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateSavedFights(savedFights) {&lt;br /&gt;
  saveToLocalStorage(&amp;quot;mt2-calc.fights.saved&amp;quot;, savedFights);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateLastLang(lang) {&lt;br /&gt;
  saveToLocalStorage(&amp;quot;mt2-calc.language.last-used&amp;quot;, lang);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveCharacter(&lt;br /&gt;
  savedCharacters,&lt;br /&gt;
  characterCreation,&lt;br /&gt;
  battle,&lt;br /&gt;
  newCharacter,&lt;br /&gt;
  characterDataObject&lt;br /&gt;
) {&lt;br /&gt;
  if (!characterDataObject) {&lt;br /&gt;
    var characterData = new FormData(characterCreation);&lt;br /&gt;
    var characterDataObject = {};&lt;br /&gt;
&lt;br /&gt;
    characterData.forEach(function (value, key) {&lt;br /&gt;
      characterDataObject[key] = convertToNumber(value);&lt;br /&gt;
    });&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var characterPseudo = characterDataObject.name;&lt;br /&gt;
  var { battleChoice } = battle;&lt;br /&gt;
&lt;br /&gt;
  savedCharacters[characterPseudo] = characterDataObject;&lt;br /&gt;
  updateSavedCharacters(savedCharacters);&lt;br /&gt;
&lt;br /&gt;
  if (newCharacter) {&lt;br /&gt;
    addBattleChoice(battleChoice, characterPseudo, characterDataObject);&lt;br /&gt;
  } else {&lt;br /&gt;
    updateBattleChoiceImage(&lt;br /&gt;
      battleChoice,&lt;br /&gt;
      characterPseudo,&lt;br /&gt;
      characterDataObject.race&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (battleChoice.resetAttackType) {&lt;br /&gt;
    if (isCharacterSelected(characterPseudo, battleChoice.attacker.selected)) {&lt;br /&gt;
      filterAttackTypeSelectionCharacter(&lt;br /&gt;
        characterDataObject,&lt;br /&gt;
        battleChoice.attackType&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
    battleChoice.resetAttackType = false;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveButtonGreen(saveButton) {&lt;br /&gt;
  saveButton.classList.remove(&amp;quot;unsaved-character&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveButtonOrange(saveButton) {&lt;br /&gt;
  saveButton.classList.add(&amp;quot;unsaved-character&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function characterCreationListener(characters, battle) {&lt;br /&gt;
  var { characterCreation, saveButton, weaponCategory } = characters;&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;submit&amp;quot;, handleSubmitForm);&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;invalid&amp;quot;, handleInvalidInput, true);&lt;br /&gt;
  document.addEventListener(&amp;quot;keydown&amp;quot;, handleSaveShortcut);&lt;br /&gt;
  weaponCategory.addEventListener(&amp;quot;mouseover&amp;quot;, handleTooltipOverflow);&lt;br /&gt;
&lt;br /&gt;
  function handleSubmitForm(event) {&lt;br /&gt;
    event.preventDefault();&lt;br /&gt;
&lt;br /&gt;
    if (characters.unsavedChanges) {&lt;br /&gt;
      saveCharacter(characters.savedCharacters, characterCreation, battle);&lt;br /&gt;
      saveButtonGreen(saveButton);&lt;br /&gt;
      characters.unsavedChanges = false;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function handleInvalidInput(event) {&lt;br /&gt;
    var target = event.target;&lt;br /&gt;
&lt;br /&gt;
    if (target.checkVisibility()) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var autoCorrectInput = target.closest(&amp;quot;.auto-correct-input&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      autoCorrectInput &amp;amp;&amp;amp;&lt;br /&gt;
      autoCorrectInput.classList.contains(&amp;quot;tabber-noactive&amp;quot;)&lt;br /&gt;
    ) {&lt;br /&gt;
      target.value = target.defaultValue;&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    openTargetTab(target);&lt;br /&gt;
    openTargetCollapsible(target);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function handleSaveShortcut(event) {&lt;br /&gt;
    if (event.ctrlKey &amp;amp;&amp;amp; event.key === &amp;quot;s&amp;quot;) {&lt;br /&gt;
      event.preventDefault();&lt;br /&gt;
      saveButton.click();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function handleTooltipOverflow(event) {&lt;br /&gt;
    var label = event.target.closest(&amp;quot;label&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (label) {&lt;br /&gt;
      var tooltip = label.lastChild;&lt;br /&gt;
&lt;br /&gt;
      if (tooltip.classList.contains(&amp;quot;popContenu&amp;quot;)) {&lt;br /&gt;
        var tooltipRect = tooltip.getBoundingClientRect();&lt;br /&gt;
        var modalRect = weaponCategory.getBoundingClientRect();&lt;br /&gt;
&lt;br /&gt;
        if (tooltipRect.right &amp;gt; modalRect.right) {&lt;br /&gt;
          tooltip.style.left = &amp;quot;-100%&amp;quot;;&lt;br /&gt;
        } else if (tooltipRect.left &amp;lt; modalRect.left) {&lt;br /&gt;
          tooltip.style.left = &amp;quot;200%&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function downloadData(content, type, filename) {&lt;br /&gt;
  var link = document.createElement(&amp;quot;a&amp;quot;);&lt;br /&gt;
  var blob = new Blob([content], { type: type });&lt;br /&gt;
  var blobURL = URL.createObjectURL(blob);&lt;br /&gt;
&lt;br /&gt;
  link.href = blobURL;&lt;br /&gt;
  link.download = filename;&lt;br /&gt;
  document.body.appendChild(link);&lt;br /&gt;
&lt;br /&gt;
  link.click();&lt;br /&gt;
  document.body.removeChild(link);&lt;br /&gt;
  URL.revokeObjectURL(blobURL);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function uploadCharacter(&lt;br /&gt;
  selectedFiles,&lt;br /&gt;
  characters,&lt;br /&gt;
  characterTemplate,&lt;br /&gt;
  charactersContainer,&lt;br /&gt;
  battle&lt;br /&gt;
) {&lt;br /&gt;
  var selectFilesLength = selectedFiles.length;&lt;br /&gt;
  var defaultPseudo = characters.defaultText.pseudo;&lt;br /&gt;
&lt;br /&gt;
  for (var fileIndex = 0; fileIndex &amp;lt; selectFilesLength; fileIndex++) {&lt;br /&gt;
    var selectedFile = selectedFiles[fileIndex];&lt;br /&gt;
&lt;br /&gt;
    if (selectedFile.type === &amp;quot;text/plain&amp;quot;) {&lt;br /&gt;
      var reader = new FileReader();&lt;br /&gt;
      reader.onload = function (e) {&lt;br /&gt;
        var fileContent = e.target.result;&lt;br /&gt;
        try {&lt;br /&gt;
          var characterDataObject = JSON.parse(fileContent);&lt;br /&gt;
&lt;br /&gt;
          if (characterDataObject.hasOwnProperty(&amp;quot;name&amp;quot;)) {&lt;br /&gt;
            var characterPseudo = String(characterDataObject.name);&lt;br /&gt;
&lt;br /&gt;
            hideElement(characters.characterCreation);&lt;br /&gt;
            characterPseudo = validPseudo(characterPseudo, defaultPseudo);&lt;br /&gt;
&lt;br /&gt;
            [characterDataObject, characterPseudo] = addUniquePseudo(&lt;br /&gt;
              characterDataObject,&lt;br /&gt;
              Object.keys(characters.savedCharacters)&lt;br /&gt;
            );&lt;br /&gt;
            var selectedCharacter = handleNewCharacter(&lt;br /&gt;
              characters,&lt;br /&gt;
              characterTemplate,&lt;br /&gt;
              charactersContainer,&lt;br /&gt;
              battle,&lt;br /&gt;
              characterPseudo&lt;br /&gt;
            )[0];&lt;br /&gt;
&lt;br /&gt;
            if (selectFilesLength === 1) {&lt;br /&gt;
              updateForm(&lt;br /&gt;
                characterDataObject,&lt;br /&gt;
                characters.characterCreation,&lt;br /&gt;
                characters,&lt;br /&gt;
                selectedCharacter,&lt;br /&gt;
                battle&lt;br /&gt;
              );&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            saveCharacter(&lt;br /&gt;
              characters.savedCharacters,&lt;br /&gt;
              characters.characterCreation,&lt;br /&gt;
              battle,&lt;br /&gt;
              true,&lt;br /&gt;
              characterDataObject&lt;br /&gt;
            );&lt;br /&gt;
          }&lt;br /&gt;
        } catch (error) {&lt;br /&gt;
          console.warn(error);&lt;br /&gt;
          if (error.name === &amp;quot;TypeError&amp;quot;) {&lt;br /&gt;
            // delete the character&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
      };&lt;br /&gt;
      reader.readAsText(selectedFile);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleUploadCharacter(&lt;br /&gt;
  characters,&lt;br /&gt;
  characterTemplate,&lt;br /&gt;
  charactersContainer,&lt;br /&gt;
  battle&lt;br /&gt;
) {&lt;br /&gt;
  var characterInput = characters.characterInput;&lt;br /&gt;
  var dropZone = characters.dropZone;&lt;br /&gt;
&lt;br /&gt;
  characterInput.accept = &amp;quot;.txt&amp;quot;;&lt;br /&gt;
  characterInput.multiple = true;&lt;br /&gt;
  dropZone.setAttribute(&amp;quot;tabindex&amp;quot;, &amp;quot;0&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  dropZone.addEventListener(&amp;quot;click&amp;quot;, function () {&lt;br /&gt;
    characterInput.click();&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  dropZone.addEventListener(&amp;quot;dragover&amp;quot;, function (event) {&lt;br /&gt;
    event.preventDefault();&lt;br /&gt;
    dropZone.classList.add(&amp;quot;drop-zone--dragover&amp;quot;);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  [&amp;quot;dragleave&amp;quot;, &amp;quot;dragend&amp;quot;].forEach(function (type) {&lt;br /&gt;
    dropZone.addEventListener(type, function () {&lt;br /&gt;
      dropZone.classList.remove(&amp;quot;drop-zone--dragover&amp;quot;);&lt;br /&gt;
    });&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  dropZone.addEventListener(&amp;quot;drop&amp;quot;, function (event) {&lt;br /&gt;
    event.preventDefault();&lt;br /&gt;
    uploadCharacter(&lt;br /&gt;
      event.dataTransfer.files,&lt;br /&gt;
      characters,&lt;br /&gt;
      characterTemplate,&lt;br /&gt;
      charactersContainer,&lt;br /&gt;
      battle&lt;br /&gt;
    );&lt;br /&gt;
    dropZone.classList.remove(&amp;quot;drop-zone--dragover&amp;quot;);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  characterInput.addEventListener(&amp;quot;change&amp;quot;, function (event) {&lt;br /&gt;
    uploadCharacter(&lt;br /&gt;
      event.target.files,&lt;br /&gt;
      characters,&lt;br /&gt;
      characterTemplate,&lt;br /&gt;
      charactersContainer,&lt;br /&gt;
      battle&lt;br /&gt;
    );&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function deleteCharacter(characters, pseudo, element, battle) {&lt;br /&gt;
  delete characters.savedCharacters[pseudo];&lt;br /&gt;
  element.remove();&lt;br /&gt;
&lt;br /&gt;
  updateSavedCharacters(characters.savedCharacters);&lt;br /&gt;
  removeBattleChoice(battle.battleChoice, pseudo, &amp;quot;character&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (&lt;br /&gt;
    !Object.keys(characters.savedCharacters).length ||&lt;br /&gt;
    characters.characterCreation.name.value === pseudo&lt;br /&gt;
  ) {&lt;br /&gt;
    saveButtonGreen(characters.saveButton);&lt;br /&gt;
    characters.unsavedChanges = false;&lt;br /&gt;
    hideElement(characters.characterCreation);&lt;br /&gt;
    showElement(characters.characterCreation.previousElementSibling);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function deleteMonster(characters, battle, monsterVnum) {&lt;br /&gt;
  var monsterElements = characters.monsterElements;&lt;br /&gt;
  var monsterType = characters.savedMonsters[monsterVnum].category;&lt;br /&gt;
&lt;br /&gt;
  if (monsterElements.hasOwnProperty(monsterVnum)) {&lt;br /&gt;
    monsterElements[monsterVnum].remove();&lt;br /&gt;
    delete monsterElements[monsterVnum];&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  delete characters.savedMonsters[monsterVnum];&lt;br /&gt;
&lt;br /&gt;
  updateSavedMonsters(characters.savedMonsters);&lt;br /&gt;
  removeBattleChoice(battle.battleChoice, monsterVnum, monsterType);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleStyle(characters, selectedElement) {&lt;br /&gt;
  var currentCharacter = characters.currentCharacter;&lt;br /&gt;
&lt;br /&gt;
  if (currentCharacter) {&lt;br /&gt;
    currentCharacter.classList.remove(&amp;quot;selected-character&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  selectedElement.classList.add(&amp;quot;selected-character&amp;quot;);&lt;br /&gt;
  characters.currentCharacter = selectedElement;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateForm(&lt;br /&gt;
  formData,&lt;br /&gt;
  characterCreation,&lt;br /&gt;
  characters,&lt;br /&gt;
  selectedElement,&lt;br /&gt;
  battle&lt;br /&gt;
) {&lt;br /&gt;
  saveButtonGreen(characters.saveButton);&lt;br /&gt;
  hideElement(characterCreation.previousElementSibling);&lt;br /&gt;
  showElement(characterCreation);&lt;br /&gt;
  handleStyle(characters, selectedElement);&lt;br /&gt;
&lt;br /&gt;
  characterCreation.reset();&lt;br /&gt;
&lt;br /&gt;
  for (var [name, value] of Object.entries(formData)) {&lt;br /&gt;
    var formElement = characterCreation[name];&lt;br /&gt;
&lt;br /&gt;
    if (!formElement) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (formElement.type === &amp;quot;checkbox&amp;quot;) {&lt;br /&gt;
      if (isChecked(value)) {&lt;br /&gt;
        formElement.checked = true;&lt;br /&gt;
      }&lt;br /&gt;
    } else {&lt;br /&gt;
      formElement.value = value;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  var selectedRace = characterCreation.race.value;&lt;br /&gt;
  var classChoice = characterCreation.class;&lt;br /&gt;
  var weaponElement = characterCreation.weapon;&lt;br /&gt;
&lt;br /&gt;
  filterClass(selectedRace, classChoice, true);&lt;br /&gt;
  filterWeapon(&lt;br /&gt;
    selectedRace,&lt;br /&gt;
    weaponElement,&lt;br /&gt;
    characters.weaponCategory,&lt;br /&gt;
    battle.constants.allowedWeaponsPerRace,&lt;br /&gt;
    true&lt;br /&gt;
  );&lt;br /&gt;
  handlePolymorphDisplay(&lt;br /&gt;
    characters,&lt;br /&gt;
    characterCreation.polymorphMonster.value,&lt;br /&gt;
    characterCreation.polymorphMonsterImage.value&lt;br /&gt;
  );&lt;br /&gt;
  handleWeaponDisplay(&lt;br /&gt;
    characters.weaponCategory,&lt;br /&gt;
    characters.weaponDisplay,&lt;br /&gt;
    weaponElement.value&lt;br /&gt;
  );&lt;br /&gt;
  filterUpgrade(&lt;br /&gt;
    characterCreation.weaponUpgrade,&lt;br /&gt;
    weaponElement.value,&lt;br /&gt;
    characters.randomAttackValue,&lt;br /&gt;
    characters.randomMagicAttackValue&lt;br /&gt;
  );&lt;br /&gt;
  for (var [targetName, sibling] of Object.entries(characters.toggleSiblings)) {&lt;br /&gt;
    filterCheckbox(characterCreation[targetName], sibling);&lt;br /&gt;
  }&lt;br /&gt;
  filterSkills(classChoice.value, characters.skillElementsToFilter);&lt;br /&gt;
  handleBonusVariationUpdate(characterCreation, characters.bonusVariation);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleClickOnCharacter(&lt;br /&gt;
  spanInput,&lt;br /&gt;
  target,&lt;br /&gt;
  characters,&lt;br /&gt;
  characterElement,&lt;br /&gt;
  battle,&lt;br /&gt;
  edition&lt;br /&gt;
) {&lt;br /&gt;
  var displayedPseudo = characters.characterCreation.name.value;&lt;br /&gt;
  var pseudo = spanInput.dataset.name;&lt;br /&gt;
  var { unsavedWarning, deleteWarning } = characters.defaultText;&lt;br /&gt;
&lt;br /&gt;
  if (edition) {&lt;br /&gt;
    if (!characters.unsavedChanges) {&lt;br /&gt;
      updateForm(&lt;br /&gt;
        characters.savedCharacters[pseudo],&lt;br /&gt;
        characters.characterCreation,&lt;br /&gt;
        characters,&lt;br /&gt;
        characterElement,&lt;br /&gt;
        battle&lt;br /&gt;
      );&lt;br /&gt;
    } else if (displayedPseudo === pseudo) {&lt;br /&gt;
      // pass&lt;br /&gt;
    } else {&lt;br /&gt;
      var result = confirm(unsavedWarning);&lt;br /&gt;
&lt;br /&gt;
      if (result) {&lt;br /&gt;
        updateForm(&lt;br /&gt;
          characters.savedCharacters[pseudo],&lt;br /&gt;
          characters.characterCreation,&lt;br /&gt;
          characters,&lt;br /&gt;
          characterElement,&lt;br /&gt;
          battle&lt;br /&gt;
        );&lt;br /&gt;
        characters.unsavedChanges = false;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    if (target.tagName === &amp;quot;path&amp;quot;) {&lt;br /&gt;
      target = target.parentElement;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    switch (target.dataset.icon) {&lt;br /&gt;
      case &amp;quot;duplicate&amp;quot;:&lt;br /&gt;
        if (!characters.unsavedChanges) {&lt;br /&gt;
          addNewCharacter(&lt;br /&gt;
            characters,&lt;br /&gt;
            characters.newCharacterTemplate,&lt;br /&gt;
            characters.charactersContainer,&lt;br /&gt;
            battle,&lt;br /&gt;
            pseudo&lt;br /&gt;
          );&lt;br /&gt;
        } else {&lt;br /&gt;
          var result = confirm(unsavedWarning);&lt;br /&gt;
&lt;br /&gt;
          if (result) {&lt;br /&gt;
            addNewCharacter(&lt;br /&gt;
              characters,&lt;br /&gt;
              characters.newCharacterTemplate,&lt;br /&gt;
              characters.charactersContainer,&lt;br /&gt;
              battle,&lt;br /&gt;
              pseudo&lt;br /&gt;
            );&lt;br /&gt;
            saveButtonGreen(characters.saveButton);&lt;br /&gt;
            characters.unsavedChanges = false;&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
        break;&lt;br /&gt;
&lt;br /&gt;
      case &amp;quot;download&amp;quot;:&lt;br /&gt;
        var character = characters.savedCharacters[pseudo];&lt;br /&gt;
        downloadData(&lt;br /&gt;
          JSON.stringify(character),&lt;br /&gt;
          &amp;quot;text/plain&amp;quot;,&lt;br /&gt;
          character.name + &amp;quot;.txt&amp;quot;&lt;br /&gt;
        );&lt;br /&gt;
        break;&lt;br /&gt;
&lt;br /&gt;
      case &amp;quot;delete&amp;quot;:&lt;br /&gt;
        var result = confirm(deleteWarning.replace(&amp;quot;[[]]&amp;quot;, pseudo));&lt;br /&gt;
        if (result) {&lt;br /&gt;
          deleteCharacter(characters, pseudo, characterElement, battle);&lt;br /&gt;
        }&lt;br /&gt;
        break;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleNewCharacter(&lt;br /&gt;
  characters,&lt;br /&gt;
  characterTemplate,&lt;br /&gt;
  charactersContainer,&lt;br /&gt;
  battle,&lt;br /&gt;
  pseudo&lt;br /&gt;
) {&lt;br /&gt;
  var newCharacterTemplate = characterTemplate.cloneNode(true);&lt;br /&gt;
  var spanInput = newCharacterTemplate.querySelector(&amp;quot;span.input&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  newCharacterTemplate.setAttribute(&amp;quot;tabindex&amp;quot;, &amp;quot;0&amp;quot;);&lt;br /&gt;
  charactersContainer.appendChild(newCharacterTemplate);&lt;br /&gt;
&lt;br /&gt;
  if (pseudo) {&lt;br /&gt;
    spanInput.textContent = pseudo;&lt;br /&gt;
    spanInput.setAttribute(&amp;quot;data-name&amp;quot;, pseudo);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  newCharacterTemplate.addEventListener(&amp;quot;click&amp;quot;, function (event) {&lt;br /&gt;
    var target = event.target;&lt;br /&gt;
&lt;br /&gt;
    if (target.tagName === &amp;quot;path&amp;quot; || target.tagName === &amp;quot;svg&amp;quot;) {&lt;br /&gt;
      handleClickOnCharacter(&lt;br /&gt;
        spanInput,&lt;br /&gt;
        target,&lt;br /&gt;
        characters,&lt;br /&gt;
        newCharacterTemplate,&lt;br /&gt;
        battle&lt;br /&gt;
      );&lt;br /&gt;
    } else {&lt;br /&gt;
      handleClickOnCharacter(&lt;br /&gt;
        spanInput,&lt;br /&gt;
        null,&lt;br /&gt;
        characters,&lt;br /&gt;
        newCharacterTemplate,&lt;br /&gt;
        battle,&lt;br /&gt;
        true&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  newCharacterTemplate.addEventListener(&amp;quot;keydown&amp;quot;, function (event) {&lt;br /&gt;
    if (event.keyCode === 13) {&lt;br /&gt;
      event.target.click();&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  return [newCharacterTemplate, spanInput];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function validPseudo(pseudo, defaultPseudo) {&lt;br /&gt;
  var newPseudo = pseudoFormat(pseudo);&lt;br /&gt;
&lt;br /&gt;
  if (!newPseudo) {&lt;br /&gt;
    return pseudoFormat(defaultPseudo);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return newPseudo;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addNewCharacter(&lt;br /&gt;
  characters,&lt;br /&gt;
  characterTemplate,&lt;br /&gt;
  charactersContainer,&lt;br /&gt;
  battle,&lt;br /&gt;
  pseudoToDuplicate&lt;br /&gt;
) {&lt;br /&gt;
  function editAndSetCharacterPseudoInput(selectedCharacter, spanInput) {&lt;br /&gt;
    var maxPseudoLength = 20;&lt;br /&gt;
    var defaultPseudo = characters.defaultText.pseudo;&lt;br /&gt;
&lt;br /&gt;
    var selection = window.getSelection();&lt;br /&gt;
    var range = document.createRange();&lt;br /&gt;
&lt;br /&gt;
    if (pseudoToDuplicate) {&lt;br /&gt;
      spanInput.textContent = pseudoToDuplicate;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    spanInput.contentEditable = true;&lt;br /&gt;
    spanInput.focus();&lt;br /&gt;
    range.selectNodeContents(spanInput);&lt;br /&gt;
    selection.removeAllRanges();&lt;br /&gt;
    selection.addRange(range);&lt;br /&gt;
&lt;br /&gt;
    function pseudoValidation() {&lt;br /&gt;
      var characterPseudo = validPseudo(spanInput.textContent, defaultPseudo);&lt;br /&gt;
      var characterDataObject = { name: characterPseudo };&lt;br /&gt;
&lt;br /&gt;
      if (pseudoToDuplicate) {&lt;br /&gt;
        characterDataObject = copyObject(&lt;br /&gt;
          characters.savedCharacters[pseudoToDuplicate]&lt;br /&gt;
        );&lt;br /&gt;
        characterDataObject.name = characterPseudo;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      [characterDataObject, characterPseudo] = addUniquePseudo(&lt;br /&gt;
        characterDataObject,&lt;br /&gt;
        Object.keys(characters.savedCharacters)&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      selection.removeAllRanges();&lt;br /&gt;
      spanInput.contentEditable = false;&lt;br /&gt;
      spanInput.textContent = characterPseudo;&lt;br /&gt;
      spanInput.setAttribute(&amp;quot;data-name&amp;quot;, characterPseudo);&lt;br /&gt;
&lt;br /&gt;
      updateForm(&lt;br /&gt;
        characterDataObject,&lt;br /&gt;
        characters.characterCreation,&lt;br /&gt;
        characters,&lt;br /&gt;
        selectedCharacter,&lt;br /&gt;
        battle&lt;br /&gt;
      );&lt;br /&gt;
      saveCharacter(&lt;br /&gt;
        characters.savedCharacters,&lt;br /&gt;
        characters.characterCreation,&lt;br /&gt;
        battle,&lt;br /&gt;
        true&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handleMaxLength(event) {&lt;br /&gt;
      if (spanInput.textContent.length &amp;gt; maxPseudoLength) {&lt;br /&gt;
        spanInput.textContent = spanInput.textContent.slice(0, maxPseudoLength);&lt;br /&gt;
        range.setStart(spanInput.childNodes[0], maxPseudoLength);&lt;br /&gt;
        selection.removeAllRanges();&lt;br /&gt;
        selection.addRange(range);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handleBlur() {&lt;br /&gt;
      spanInput.removeEventListener(&amp;quot;blur&amp;quot;, handleBlur);&lt;br /&gt;
      spanInput.removeEventListener(&amp;quot;input&amp;quot;, handleMaxLength);&lt;br /&gt;
      pseudoValidation();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handleKeyDown(event) {&lt;br /&gt;
      if (event.key === &amp;quot;Enter&amp;quot;) {&lt;br /&gt;
        event.preventDefault();&lt;br /&gt;
&lt;br /&gt;
        spanInput.removeEventListener(&amp;quot;keydown&amp;quot;, handleKeyDown);&lt;br /&gt;
        spanInput.removeEventListener(&amp;quot;blur&amp;quot;, handleBlur);&lt;br /&gt;
        spanInput.removeEventListener(&amp;quot;input&amp;quot;, handleMaxLength);&lt;br /&gt;
&lt;br /&gt;
        pseudoValidation();&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    spanInput.addEventListener(&amp;quot;input&amp;quot;, handleMaxLength);&lt;br /&gt;
    spanInput.addEventListener(&amp;quot;keydown&amp;quot;, handleKeyDown);&lt;br /&gt;
    spanInput.addEventListener(&amp;quot;blur&amp;quot;, handleBlur);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  hideElement(characters.characterCreation);&lt;br /&gt;
  var [selectedCharacter, spanInput] = handleNewCharacter(&lt;br /&gt;
    characters,&lt;br /&gt;
    characterTemplate,&lt;br /&gt;
    charactersContainer,&lt;br /&gt;
    battle&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  editAndSetCharacterPseudoInput(selectedCharacter, spanInput);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleFocus() {&lt;br /&gt;
  var tooltipLinks = document.querySelectorAll(&amp;quot;div.tooltip a&amp;quot;);&lt;br /&gt;
  tooltipLinks.forEach(function (link) {&lt;br /&gt;
    link.setAttribute(&amp;quot;tabindex&amp;quot;, -1);&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function resetBonusVariation(bonusVariation) {&lt;br /&gt;
  function resetInput(input) {&lt;br /&gt;
    input.removeAttribute(&amp;quot;min&amp;quot;);&lt;br /&gt;
    input.removeAttribute(&amp;quot;max&amp;quot;);&lt;br /&gt;
    input.defaultValue = 0;&lt;br /&gt;
    input.value = input.defaultValue;&lt;br /&gt;
  }&lt;br /&gt;
  var { minValue, maxValue, checkbox, container, disabledText, selectedText } =&lt;br /&gt;
    bonusVariation;&lt;br /&gt;
&lt;br /&gt;
  resetInput(minValue);&lt;br /&gt;
  resetInput(maxValue);&lt;br /&gt;
  showElement(disabledText);&lt;br /&gt;
  hideElement(selectedText);&lt;br /&gt;
  hideElement(container);&lt;br /&gt;
  checkbox.checked = false;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleBonusVariationUpdate(&lt;br /&gt;
  characterCreation,&lt;br /&gt;
  bonusVariation,&lt;br /&gt;
  resetSkill&lt;br /&gt;
) {&lt;br /&gt;
  var selectedBonus = characterCreation.bonusVariation.value;&lt;br /&gt;
  var displayName = characterCreation.bonusVariationName.value;&lt;br /&gt;
&lt;br /&gt;
  if (&lt;br /&gt;
    resetSkill &amp;amp;&amp;amp;&lt;br /&gt;
    (selectedBonus.startsWith(&amp;quot;attackSkill&amp;quot;) ||&lt;br /&gt;
      selectedBonus.startsWith(&amp;quot;horseSkill&amp;quot;) ||&lt;br /&gt;
      selectedBonus.startsWith(&amp;quot;skillBonus&amp;quot;))&lt;br /&gt;
  ) {&lt;br /&gt;
    resetBonusVariation(bonusVariation);&lt;br /&gt;
    return;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (&lt;br /&gt;
    characterCreation.hasOwnProperty(selectedBonus) &amp;amp;&amp;amp;&lt;br /&gt;
    selectedBonus != 0 &amp;amp;&amp;amp;&lt;br /&gt;
    displayName != 0&lt;br /&gt;
  ) {&lt;br /&gt;
    handleBonusVariation(&lt;br /&gt;
      characterCreation[selectedBonus],&lt;br /&gt;
      bonusVariation,&lt;br /&gt;
      displayName&lt;br /&gt;
    );&lt;br /&gt;
  } else {&lt;br /&gt;
    resetBonusVariation(bonusVariation);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getTargetContent(targetParent, targetName, isSkill) {&lt;br /&gt;
  var targetContent = &amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  if (targetParent.children.length &amp;lt;= 1) {&lt;br /&gt;
    targetContent = targetParent.textContent;&lt;br /&gt;
  } else if (targetName === &amp;quot;weaponUpgrade&amp;quot;) {&lt;br /&gt;
    targetContent = targetParent.children[1].textContent;&lt;br /&gt;
  } else if (targetName === &amp;quot;level&amp;quot;) {&lt;br /&gt;
    targetContent = targetParent.textContent.replace(&amp;quot;Lv&amp;quot;, &amp;quot;&amp;quot;).trim();&lt;br /&gt;
  } else if (isSkill) {&lt;br /&gt;
    var container = targetParent.children[1];&lt;br /&gt;
&lt;br /&gt;
    for (var index = 0; index &amp;lt; container.children.length; index++) {&lt;br /&gt;
      var element = container.children[index];&lt;br /&gt;
&lt;br /&gt;
      if (element.checkVisibility()) {&lt;br /&gt;
        targetContent += element.textContent;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    for (var index = 1; index &amp;lt; targetParent.children.length; index++) {&lt;br /&gt;
      var element = targetParent.children[index];&lt;br /&gt;
&lt;br /&gt;
      if (element.checkVisibility()) {&lt;br /&gt;
        targetContent += element.textContent;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return targetContent.trim();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleBonusVariation(target, bonusVariation, displayName) {&lt;br /&gt;
  var {&lt;br /&gt;
    minValue,&lt;br /&gt;
    maxValue,&lt;br /&gt;
    checkbox,&lt;br /&gt;
    container,&lt;br /&gt;
    disabledText,&lt;br /&gt;
    selectedText,&lt;br /&gt;
    displaySpan,&lt;br /&gt;
  } = bonusVariation;&lt;br /&gt;
&lt;br /&gt;
  var {&lt;br /&gt;
    min: targetMin,&lt;br /&gt;
    max: targetMax,&lt;br /&gt;
    name: targetName,&lt;br /&gt;
    value: targetValue,&lt;br /&gt;
    parentElement: targetParent,&lt;br /&gt;
    tagName,&lt;br /&gt;
  } = target;&lt;br /&gt;
&lt;br /&gt;
  targetMin = Number(targetMin);&lt;br /&gt;
  targetMax = Number(targetMax);&lt;br /&gt;
  targetValue = Number(targetValue);&lt;br /&gt;
&lt;br /&gt;
  var isSkill = tagName === &amp;quot;SELECT&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  if (isSkill) {&lt;br /&gt;
    var options = target.options;&lt;br /&gt;
&lt;br /&gt;
    targetMin = options[0].value;&lt;br /&gt;
    targetMax = options[options.length - 1].value;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  minValue.min = targetMin;&lt;br /&gt;
  minValue.max = targetMax;&lt;br /&gt;
  minValue.defaultValue = targetMin;&lt;br /&gt;
&lt;br /&gt;
  maxValue.min = targetMin;&lt;br /&gt;
  maxValue.max = targetMax;&lt;br /&gt;
  maxValue.defaultValue = targetMin;&lt;br /&gt;
&lt;br /&gt;
  hideElement(disabledText);&lt;br /&gt;
  showElement(selectedText);&lt;br /&gt;
&lt;br /&gt;
  if (displayName) {&lt;br /&gt;
    minValue.value = Math.min(Math.max(minValue.value, targetMin), targetMax);&lt;br /&gt;
    maxValue.value = Math.max(Math.min(maxValue.value, targetMax), targetMin);&lt;br /&gt;
&lt;br /&gt;
    displaySpan.textContent = displayName;&lt;br /&gt;
  } else {&lt;br /&gt;
    var { input, inputName, tabButton } = bonusVariation;&lt;br /&gt;
    var targetContent = getTargetContent(targetParent, targetName, isSkill);&lt;br /&gt;
&lt;br /&gt;
    input.value = targetName;&lt;br /&gt;
    inputName.value = targetContent;&lt;br /&gt;
    displaySpan.textContent = targetContent;&lt;br /&gt;
&lt;br /&gt;
    minValue.value = Math.max(targetValue - 10, targetMin);&lt;br /&gt;
    maxValue.value = Math.min(targetValue + 10, targetMax);&lt;br /&gt;
&lt;br /&gt;
    showElement(container);&lt;br /&gt;
    checkbox.checked = true;&lt;br /&gt;
&lt;br /&gt;
    tabButton.click();&lt;br /&gt;
    tabButton.scrollIntoView(true);&lt;br /&gt;
&lt;br /&gt;
    input.dispatchEvent(newChangeEvent());&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function characterManagement(characters, battle) {&lt;br /&gt;
  var {&lt;br /&gt;
    newCharacterTemplate: characterTemplate,&lt;br /&gt;
    charactersContainer,&lt;br /&gt;
    addNewCharacterButton,&lt;br /&gt;
    saveButton,&lt;br /&gt;
    characterCreation,&lt;br /&gt;
    bonusVariation,&lt;br /&gt;
    defaultText: { unsavedWarning },&lt;br /&gt;
  } = characters;&lt;br /&gt;
&lt;br /&gt;
  Object.keys(characters.savedCharacters).forEach(function (pseudo) {&lt;br /&gt;
    handleNewCharacter(&lt;br /&gt;
      characters,&lt;br /&gt;
      characterTemplate,&lt;br /&gt;
      charactersContainer,&lt;br /&gt;
      battle,&lt;br /&gt;
      pseudo&lt;br /&gt;
    );&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  addNewCharacterButton.addEventListener(&amp;quot;click&amp;quot;, function (event) {&lt;br /&gt;
    if (!characters.unsavedChanges) {&lt;br /&gt;
      addNewCharacter(&lt;br /&gt;
        characters,&lt;br /&gt;
        characterTemplate,&lt;br /&gt;
        charactersContainer,&lt;br /&gt;
        battle&lt;br /&gt;
      );&lt;br /&gt;
    } else {&lt;br /&gt;
      var result = confirm(unsavedWarning);&lt;br /&gt;
&lt;br /&gt;
      if (result) {&lt;br /&gt;
        addNewCharacter(&lt;br /&gt;
          characters,&lt;br /&gt;
          characterTemplate,&lt;br /&gt;
          charactersContainer,&lt;br /&gt;
          battle&lt;br /&gt;
        );&lt;br /&gt;
        saveButtonGreen(saveButton);&lt;br /&gt;
        characters.unsavedChanges = false;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  handleUploadCharacter(&lt;br /&gt;
    characters,&lt;br /&gt;
    characterTemplate,&lt;br /&gt;
    charactersContainer,&lt;br /&gt;
    battle&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  function handleLongPress(target) {&lt;br /&gt;
    if (target.tagName !== &amp;quot;INPUT&amp;quot; &amp;amp;&amp;amp; target.tagName !== &amp;quot;SELECT&amp;quot;) {&lt;br /&gt;
      target = target.querySelector(&amp;quot;input&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      !target ||&lt;br /&gt;
      (target.type !== &amp;quot;number&amp;quot; &amp;amp;&amp;amp;&lt;br /&gt;
        !target.classList.contains(&amp;quot;skill-select&amp;quot;) &amp;amp;&amp;amp;&lt;br /&gt;
        target.name !== &amp;quot;weaponUpgrade&amp;quot;) ||&lt;br /&gt;
      target.classList.contains(&amp;quot;disabled-variation&amp;quot;)&lt;br /&gt;
    ) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    handleBonusVariation(target, bonusVariation, null);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;click&amp;quot;, function (event) {&lt;br /&gt;
    if (event.shiftKey || event.ctrlKey) {&lt;br /&gt;
      handleLongPress(event.target);&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  var longPressTimer;&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;touchstart&amp;quot;, function (event) {&lt;br /&gt;
    longPressTimer = setTimeout(function () {&lt;br /&gt;
      handleLongPress(event.target);&lt;br /&gt;
    }, 800);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;touchend&amp;quot;, function () {&lt;br /&gt;
    clearTimeout(longPressTimer);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;touchmove&amp;quot;, function () {&lt;br /&gt;
    clearTimeout(longPressTimer);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  filterForm(characters, battle);&lt;br /&gt;
  characterCreationListener(characters, battle);&lt;br /&gt;
  handleFocus();&lt;br /&gt;
&lt;br /&gt;
  window.addEventListener(&amp;quot;beforeunload&amp;quot;, function (event) {&lt;br /&gt;
    if (characters.unsavedChanges) {&lt;br /&gt;
      event.preventDefault();&lt;br /&gt;
      return &amp;quot;&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addMonsterElement(characters, battle, monsterVnum, iframeInfo) {&lt;br /&gt;
  var { monsterTemplate, monstersContainer } = characters;&lt;br /&gt;
  var monsterElement = monsterTemplate.cloneNode(true);&lt;br /&gt;
  var spanInput = monsterElement.querySelector(&amp;quot;span.input&amp;quot;);&lt;br /&gt;
  var deleteSvg = monsterElement.querySelector(&amp;quot;svg&amp;quot;);&lt;br /&gt;
  var monsterName = getMonsterName(monsterVnum);&lt;br /&gt;
  var displayName = characters.translateMonsters&lt;br /&gt;
    ? getTranslatedMonsterName(monsterVnum)&lt;br /&gt;
    : monsterName;&lt;br /&gt;
  var link = createWikiLink(monsterName, displayName);&lt;br /&gt;
&lt;br /&gt;
  monsterElement.setAttribute(&amp;quot;tabindex&amp;quot;, &amp;quot;0&amp;quot;);&lt;br /&gt;
  spanInput.appendChild(link);&lt;br /&gt;
  monstersContainer.appendChild(monsterElement);&lt;br /&gt;
  characters.monsterElements[monsterVnum] = monsterElement;&lt;br /&gt;
&lt;br /&gt;
  deleteSvg.addEventListener(&amp;quot;click&amp;quot;, function () {&lt;br /&gt;
    var monster = characters.savedMonsters[monsterVnum];&lt;br /&gt;
    iframeInfo[monster.category].shouldBeUpdated = true;&lt;br /&gt;
&lt;br /&gt;
    deleteMonster(characters, battle, monsterVnum);&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addNewMonster(&lt;br /&gt;
  characters,&lt;br /&gt;
  battle,&lt;br /&gt;
  monsterVnum,&lt;br /&gt;
  monsterImage,&lt;br /&gt;
  iframeInfo,&lt;br /&gt;
  category&lt;br /&gt;
) {&lt;br /&gt;
  if (isValueInArray(monsterVnum, Object.keys(characters.savedMonsters)))&lt;br /&gt;
    return;&lt;br /&gt;
&lt;br /&gt;
  var newMonster = {&lt;br /&gt;
    image: monsterImage,&lt;br /&gt;
    category: category,&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  characters.savedMonsters[monsterVnum] = newMonster;&lt;br /&gt;
&lt;br /&gt;
  addMonsterElement(characters, battle, monsterVnum, iframeInfo);&lt;br /&gt;
  updateSavedMonsters(characters.savedMonsters);&lt;br /&gt;
  addBattleChoice(battle.battleChoice, monsterVnum, newMonster, true);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function translateiFrame(iframeDoc) {&lt;br /&gt;
  const filterName = iframeDoc.getElementById(&amp;quot;filter-name&amp;quot;);&lt;br /&gt;
  const { general, special } = translation;&lt;br /&gt;
  const translatedPlaceholder = special.placeholder;&lt;br /&gt;
&lt;br /&gt;
  if (filterName &amp;amp;&amp;amp; translatedPlaceholder) {&lt;br /&gt;
    filterName.placeholder = translatedPlaceholder;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (const element of iframeDoc.querySelectorAll(&amp;quot;[data-t]&amp;quot;)) {&lt;br /&gt;
    const translateText = general[element.dataset.t];&lt;br /&gt;
&lt;br /&gt;
    if (translateText) {&lt;br /&gt;
      element.textContent = translateText;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function translateMonsterCard(card, cardNameElement, monsterVnum) {&lt;br /&gt;
  const mapping = translation.mapping;&lt;br /&gt;
  const levelElement = card.querySelector(&amp;quot;[data-level]&amp;quot;);&lt;br /&gt;
  const typeElement = card.querySelector(&amp;quot;[data-type] a&amp;quot;);&lt;br /&gt;
  const damageElements = card.querySelectorAll(&amp;quot;[data-damage] a&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  cardNameElement.textContent = getTranslatedMonsterName(monsterVnum);&lt;br /&gt;
&lt;br /&gt;
  levelElement.textContent = levelElement.textContent.replace(&lt;br /&gt;
    &amp;quot;Boss&amp;quot;,&lt;br /&gt;
    translation.special.boss&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  if (typeElement) {&lt;br /&gt;
    typeElement.textContent = mapping[typeElement.textContent];&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  damageElements.forEach((damageElement) =&amp;gt; {&lt;br /&gt;
    damageElement.textContent = mapping[damageElement.textContent];&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addButtonsToCardsAndTranslate(&lt;br /&gt;
  characters,&lt;br /&gt;
  iframeDoc,&lt;br /&gt;
  iframeInfo,&lt;br /&gt;
  category&lt;br /&gt;
) {&lt;br /&gt;
  const buttonTemplates = characters.monsterButtonTemplates.children[0];&lt;br /&gt;
  const cardToEdit = iframeDoc.getElementById(&amp;quot;cards-container&amp;quot;).children;&lt;br /&gt;
  const { nameToVnum } = iframeInfo;&lt;br /&gt;
  const vnumToButtons = iframeInfo[category].vnumToButtons;&lt;br /&gt;
  const translateMonsters = characters.translateMonsters;&lt;br /&gt;
&lt;br /&gt;
  for (let cardIndex = 0; cardIndex &amp;lt; cardToEdit.length; cardIndex++) {&lt;br /&gt;
    const card = cardToEdit[cardIndex];&lt;br /&gt;
    const cardNameElement = card.querySelector(&amp;quot;[data-name]&amp;quot;).firstChild;&lt;br /&gt;
    const buttonTemplatesClone = buttonTemplates.cloneNode(true);&lt;br /&gt;
    const cardName = cardNameElement.title.replace(/\s/g, &amp;quot; &amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (!nameToVnum.hasOwnProperty(cardName)) {&lt;br /&gt;
      card.style.display = &amp;quot;none&amp;quot;;&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    const monsterVnum = nameToVnum[cardName];&lt;br /&gt;
&lt;br /&gt;
    buttonTemplatesClone.dataset.monsterId = monsterVnum;&lt;br /&gt;
    card.lastElementChild.appendChild(buttonTemplatesClone);&lt;br /&gt;
    vnumToButtons[monsterVnum] = buttonTemplatesClone.children;&lt;br /&gt;
&lt;br /&gt;
    if (translateMonsters) {&lt;br /&gt;
      translateMonsterCard(card, cardNameElement, monsterVnum);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (translateMonsters) {&lt;br /&gt;
    translateiFrame(iframeDoc);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateiFrameButtons(characters, iframeInfo, category) {&lt;br /&gt;
  var addedMonsters = Object.keys(characters.savedMonsters);&lt;br /&gt;
  var { currentiFrameIsMonster } = iframeInfo;&lt;br /&gt;
  var vnumToButtons = iframeInfo[category].vnumToButtons;&lt;br /&gt;
  var isPolymorphModal = category === &amp;quot;monster&amp;quot; &amp;amp;&amp;amp; !currentiFrameIsMonster;&lt;br /&gt;
&lt;br /&gt;
  for (var monsterVnum in vnumToButtons) {&lt;br /&gt;
    var [addButton, deleteButton, selectButton] = vnumToButtons[monsterVnum];&lt;br /&gt;
&lt;br /&gt;
    if (isPolymorphModal) {&lt;br /&gt;
      hideElement(addButton);&lt;br /&gt;
      hideElement(deleteButton);&lt;br /&gt;
      showElement(selectButton);&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isValueInArray(monsterVnum, addedMonsters)) {&lt;br /&gt;
      hideElement(addButton);&lt;br /&gt;
      showElement(deleteButton);&lt;br /&gt;
      hideElement(selectButton);&lt;br /&gt;
    } else {&lt;br /&gt;
      showElement(addButton);&lt;br /&gt;
      hideElement(deleteButton);&lt;br /&gt;
      hideElement(selectButton);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  iframeInfo.lastiFrameIsMonster = currentiFrameIsMonster;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getMonsterImage(buttonsContainer) {&lt;br /&gt;
  var elder = buttonsContainer.parentElement.firstElementChild;&lt;br /&gt;
  var image = elder.querySelector(&amp;quot;img&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (image) {&lt;br /&gt;
    return image.getAttribute(&amp;quot;src&amp;quot;) || &amp;quot;&amp;quot;;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return &amp;quot;&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleiFrame(iframeInfo, category) {&lt;br /&gt;
  var { characters, battle } = iframeInfo;&lt;br /&gt;
  var iframeInfoCategory = iframeInfo[category];&lt;br /&gt;
  var { iframe, pageName, vnumToButtons } = iframeInfoCategory;&lt;br /&gt;
  var loadingAnimation = iframeInfoCategory.iframe.previousElementSibling;&lt;br /&gt;
&lt;br /&gt;
  iframe.src = mw.util.getUrl(pageName);&lt;br /&gt;
&lt;br /&gt;
  window.addEventListener(&amp;quot;message&amp;quot;, function (event) {&lt;br /&gt;
    if (&lt;br /&gt;
      event.origin !== window.origin ||&lt;br /&gt;
      event.data?.type !== &amp;quot;filterReady&amp;quot; ||&lt;br /&gt;
      event.data.category !== category&lt;br /&gt;
    ) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
    var iframeDoc = iframe.contentDocument || iframe.contentWindow.document;&lt;br /&gt;
    var htmlElement = iframeDoc.documentElement;&lt;br /&gt;
    var iframeBody = iframeDoc.body;&lt;br /&gt;
    var content = iframeDoc.getElementById(&amp;quot;show-after-loading&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    htmlElement.setAttribute(&amp;quot;lang&amp;quot;, characters.currentLanguage);&lt;br /&gt;
    iframeBody.firstElementChild.replaceWith(content);&lt;br /&gt;
&lt;br /&gt;
    iframeBody.style.background = &amp;quot;transparent&amp;quot;;&lt;br /&gt;
    iframeBody.style.paddingRight = &amp;quot;10px&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    addButtonsToCardsAndTranslate(characters, iframeDoc, iframeInfo, category);&lt;br /&gt;
    updateiFrameButtons(characters, iframeInfo, category);&lt;br /&gt;
&lt;br /&gt;
    iframeInfoCategory.loadIsFinished = true;&lt;br /&gt;
&lt;br /&gt;
    hideElement(loadingAnimation);&lt;br /&gt;
    showElement(iframe);&lt;br /&gt;
&lt;br /&gt;
    iframeDoc.addEventListener(&amp;quot;click&amp;quot;, handleButtonClick);&lt;br /&gt;
&lt;br /&gt;
    function handleButtonClick(event) {&lt;br /&gt;
      var target = event.target;&lt;br /&gt;
      var link = target.closest(&amp;quot;a&amp;quot;);&lt;br /&gt;
      var buttonsContainer = target.closest(&amp;quot;.handle-monster&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
      if (link) {&lt;br /&gt;
        event.preventDefault();&lt;br /&gt;
        window.open(link.href, &amp;quot;_blank&amp;quot;);&lt;br /&gt;
      } else if (buttonsContainer) {&lt;br /&gt;
        var { monsterId: monsterVnum } = buttonsContainer.dataset;&lt;br /&gt;
&lt;br /&gt;
        // polymorph iframe&lt;br /&gt;
        if (category === &amp;quot;monster&amp;quot; &amp;amp;&amp;amp; !iframeInfo.currentiFrameIsMonster) {&lt;br /&gt;
          var monsterImage = getMonsterImage(buttonsContainer);&lt;br /&gt;
          changePolymorphValues(&lt;br /&gt;
            characters.characterCreation,&lt;br /&gt;
            monsterVnum,&lt;br /&gt;
            monsterImage&lt;br /&gt;
          );&lt;br /&gt;
          handlePolymorphDisplay(characters, monsterVnum, monsterImage);&lt;br /&gt;
          iframe.dispatchEvent(newChangeEvent());&lt;br /&gt;
        } else {&lt;br /&gt;
          var addedMonsters = Object.keys(characters.savedMonsters);&lt;br /&gt;
          var [addButton, deleteButton] = vnumToButtons[monsterVnum];&lt;br /&gt;
&lt;br /&gt;
          if (isValueInArray(monsterVnum, addedMonsters)) {&lt;br /&gt;
            deleteMonster(characters, battle, monsterVnum);&lt;br /&gt;
            showElement(addButton);&lt;br /&gt;
            hideElement(deleteButton);&lt;br /&gt;
          } else {&lt;br /&gt;
            var monsterImage = getMonsterImage(buttonsContainer);&lt;br /&gt;
            addNewMonster(&lt;br /&gt;
              characters,&lt;br /&gt;
              battle,&lt;br /&gt;
              monsterVnum,&lt;br /&gt;
              monsterImage,&lt;br /&gt;
              iframeInfo,&lt;br /&gt;
              category&lt;br /&gt;
            );&lt;br /&gt;
            hideElement(addButton);&lt;br /&gt;
            showElement(deleteButton);&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getNameToVnumMapping() {&lt;br /&gt;
  var nameToVnum = {};&lt;br /&gt;
&lt;br /&gt;
  for (var monsterVnum in monsterData) {&lt;br /&gt;
    nameToVnum[monsterData[monsterVnum][monsterData[monsterVnum].length - 1]] =&lt;br /&gt;
      monsterVnum;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return nameToVnum;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function monsterManagement(characters, battle) {&lt;br /&gt;
  var { monsteriFrame, stoneiFrame } = characters;&lt;br /&gt;
  var monsterVnums = Object.keys(monsterData);&lt;br /&gt;
&lt;br /&gt;
  var iframeInfo = {&lt;br /&gt;
    lastiFrameIsMonster: false,&lt;br /&gt;
    currentiFrameIsMonster: false,&lt;br /&gt;
    characters: characters,&lt;br /&gt;
    battle: battle,&lt;br /&gt;
    nameToVnum: getNameToVnumMapping(),&lt;br /&gt;
    monster: {&lt;br /&gt;
      isLoaded: false,&lt;br /&gt;
      loadIsFinished: false,&lt;br /&gt;
      shouldBeUpdated: false,&lt;br /&gt;
      vnumToButtons: {},&lt;br /&gt;
      pageName: &amp;quot;Monstres&amp;quot;,&lt;br /&gt;
      iframe: monsteriFrame,&lt;br /&gt;
    },&lt;br /&gt;
    stone: {&lt;br /&gt;
      isLoaded: false,&lt;br /&gt;
      loadIsFinished: false,&lt;br /&gt;
      shouldBeUpdated: false,&lt;br /&gt;
      vnumToButtons: {},&lt;br /&gt;
      pageName: &amp;quot;Pierres Metin&amp;quot;,&lt;br /&gt;
      iframe: stoneiFrame,&lt;br /&gt;
    },&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  document.addEventListener(&amp;quot;modalOpen&amp;quot;, function (event) {&lt;br /&gt;
    var modalName = event.detail.name;&lt;br /&gt;
&lt;br /&gt;
    if (modalName === &amp;quot;monster&amp;quot; || modalName === &amp;quot;stone&amp;quot;) {&lt;br /&gt;
      handleModal(event.target, modalName);&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  function handleModal(target, modalName) {&lt;br /&gt;
    var iframeInfoCategory = iframeInfo[modalName];&lt;br /&gt;
&lt;br /&gt;
    if (modalName === &amp;quot;monster&amp;quot;) {&lt;br /&gt;
      var isMonsteriFrame = target.id === &amp;quot;add-new-monster&amp;quot;;&lt;br /&gt;
      iframeInfo.currentiFrameIsMonster = isMonsteriFrame;&lt;br /&gt;
&lt;br /&gt;
      if (&lt;br /&gt;
        iframeInfoCategory.loadIsFinished &amp;amp;&amp;amp;&lt;br /&gt;
        ((isMonsteriFrame &amp;amp;&amp;amp; !iframeInfo.lastiFrameIsMonster) ||&lt;br /&gt;
          (!isMonsteriFrame &amp;amp;&amp;amp; iframeInfo.lastiFrameIsMonster))&lt;br /&gt;
      ) {&lt;br /&gt;
        iframeInfoCategory.shouldBeUpdated = true;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!iframeInfoCategory.isLoaded) {&lt;br /&gt;
      handleiFrame(iframeInfo, modalName);&lt;br /&gt;
      iframeInfoCategory.isLoaded = true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      iframeInfoCategory.loadIsFinished &amp;amp;&amp;amp;&lt;br /&gt;
      iframeInfoCategory.shouldBeUpdated&lt;br /&gt;
    ) {&lt;br /&gt;
      updateiFrameButtons(characters, iframeInfo, modalName);&lt;br /&gt;
      iframeInfoCategory.shouldBeUpdated = false;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  Object.keys(characters.savedMonsters)&lt;br /&gt;
    .slice()&lt;br /&gt;
    .forEach(function (monsterVnum) {&lt;br /&gt;
      if (isValueInArray(monsterVnum, monsterVnums)) {&lt;br /&gt;
        addMonsterElement(characters, battle, monsterVnum, iframeInfo);&lt;br /&gt;
      } else {&lt;br /&gt;
        deleteMonster(characters, battle, monsterVnum);&lt;br /&gt;
      }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function hideAttackType(container, input, attackType) {&lt;br /&gt;
  hideElement(container);&lt;br /&gt;
&lt;br /&gt;
  if (input.checked) {&lt;br /&gt;
    var defaultInput = attackType.defaultInput;&lt;br /&gt;
&lt;br /&gt;
    input.checked = false;&lt;br /&gt;
    defaultInput.checked = true;&lt;br /&gt;
    defaultInput.dispatchEvent(newChangeEvent());&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterAttackTypeSelectionCharacter(attacker, attackType) {&lt;br /&gt;
  var attackerClass = attacker.class;&lt;br /&gt;
  var attackerIsNotPolymorph = !isPolymorph(attacker);&lt;br /&gt;
  var { elements: attackTypeElements } = attackType;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; attackTypeElements.length; index++) {&lt;br /&gt;
    var { container, input, inputClass, inputValue } =&lt;br /&gt;
      attackTypeElements[index];&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      attackerIsNotPolymorph &amp;amp;&amp;amp;&lt;br /&gt;
      attacker[inputValue] &amp;amp;&amp;amp;&lt;br /&gt;
      (attackerClass === inputClass ||&lt;br /&gt;
        (inputValue.startsWith(&amp;quot;horseSkill&amp;quot;) &amp;amp;&amp;amp;&lt;br /&gt;
          isRiding(attacker) &amp;amp;&amp;amp;&lt;br /&gt;
          (!inputClass || isValueInArray(attackerClass, inputClass))))&lt;br /&gt;
    ) {&lt;br /&gt;
      showElement(container);&lt;br /&gt;
    } else {&lt;br /&gt;
      hideAttackType(container, input, attackType);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterAttackTypeSelectionMonster(attackType) {&lt;br /&gt;
  var attackTypeElements = attackType.elements;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; attackTypeElements.length; index++) {&lt;br /&gt;
    var { container, input } = attackTypeElements[index];&lt;br /&gt;
    hideAttackType(container, input, attackType);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function removeBattleElement(battleChoice, nameOrVnum, category, type) {&lt;br /&gt;
  var elements = battleChoice[category][type].elements;&lt;br /&gt;
&lt;br /&gt;
  if (elements.hasOwnProperty(nameOrVnum)) {&lt;br /&gt;
    elements[nameOrVnum].container.remove();&lt;br /&gt;
    delete elements[nameOrVnum];&lt;br /&gt;
    battleChoice[category][type].count--;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function removeBattleChoice(battleChoice, nameOrVnum, type) {&lt;br /&gt;
  battleChoice.categories.forEach(function (category) {&lt;br /&gt;
    if (category === &amp;quot;attacker&amp;quot; &amp;amp;&amp;amp; type === &amp;quot;stone&amp;quot;) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
    var selected = battleChoice[category].selected;&lt;br /&gt;
&lt;br /&gt;
    if (selected) {&lt;br /&gt;
      var { type: selectedType, nameOrVnum: selectedNameOrVnum } =&lt;br /&gt;
        parseTypeAndName(selected);&lt;br /&gt;
&lt;br /&gt;
      if (nameOrVnum === selectedNameOrVnum &amp;amp;&amp;amp; type === selectedType) {&lt;br /&gt;
        resetBattleChoiceButton(battleChoice, category);&lt;br /&gt;
        battleChoice[category].selected = null;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    removeBattleElement(battleChoice, nameOrVnum, category, type);&lt;br /&gt;
    updateBattleChoiceText(battleChoice, category, type);&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addBattleElement(&lt;br /&gt;
  battleChoice,&lt;br /&gt;
  pseudoOrVnum,&lt;br /&gt;
  characterOrMonster,&lt;br /&gt;
  category,&lt;br /&gt;
  isMonster&lt;br /&gt;
) {&lt;br /&gt;
  var { template, raceToImage, translateMonsters } = battleChoice;&lt;br /&gt;
  var battleChoiceCategory = battleChoice[category];&lt;br /&gt;
  var templateClone = template.cloneNode(true);&lt;br /&gt;
  var label = templateClone.firstElementChild;&lt;br /&gt;
  var [input, image, span] = label.children;&lt;br /&gt;
  var imageSrc;&lt;br /&gt;
  var name;&lt;br /&gt;
  var type;&lt;br /&gt;
&lt;br /&gt;
  if (isMonster) {&lt;br /&gt;
    type = characterOrMonster.category;&lt;br /&gt;
&lt;br /&gt;
    if (type === &amp;quot;stone&amp;quot; &amp;amp;&amp;amp; category === &amp;quot;attacker&amp;quot;) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
    imageSrc = characterOrMonster.image;&lt;br /&gt;
    name = translateMonsters&lt;br /&gt;
      ? getTranslatedMonsterName(pseudoOrVnum)&lt;br /&gt;
      : getMonsterName(pseudoOrVnum);&lt;br /&gt;
  } else {&lt;br /&gt;
    type = &amp;quot;character&amp;quot;;&lt;br /&gt;
    imageSrc = raceToImage[characterOrMonster.race];&lt;br /&gt;
    name = pseudoOrVnum;&lt;br /&gt;
    label.classList.add(&amp;quot;notranslate&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var value = type + &amp;quot;-&amp;quot; + pseudoOrVnum;&lt;br /&gt;
  var id = category + &amp;quot;-&amp;quot; + value;&lt;br /&gt;
  var currentBattleChoice = battleChoiceCategory[type];&lt;br /&gt;
&lt;br /&gt;
  label.setAttribute(&amp;quot;for&amp;quot;, id);&lt;br /&gt;
  input.value = value;&lt;br /&gt;
  input.id = id;&lt;br /&gt;
  input.name = category;&lt;br /&gt;
  span.textContent = name;&lt;br /&gt;
&lt;br /&gt;
  handleImageFromWiki(image, imageSrc);&lt;br /&gt;
&lt;br /&gt;
  currentBattleChoice.container.appendChild(templateClone);&lt;br /&gt;
  currentBattleChoice.count++;&lt;br /&gt;
  currentBattleChoice.elements[pseudoOrVnum] = {&lt;br /&gt;
    container: templateClone,&lt;br /&gt;
    image: image,&lt;br /&gt;
    name: name,&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  updateBattleChoiceText(battleChoice, category, type);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addBattleChoice(&lt;br /&gt;
  battleChoice,&lt;br /&gt;
  pseudoOrVnum,&lt;br /&gt;
  characterOrMonster,&lt;br /&gt;
  isMonster = false&lt;br /&gt;
) {&lt;br /&gt;
  addBattleElement(&lt;br /&gt;
    battleChoice,&lt;br /&gt;
    pseudoOrVnum,&lt;br /&gt;
    characterOrMonster,&lt;br /&gt;
    &amp;quot;attacker&amp;quot;,&lt;br /&gt;
    isMonster&lt;br /&gt;
  );&lt;br /&gt;
  addBattleElement(&lt;br /&gt;
    battleChoice,&lt;br /&gt;
    pseudoOrVnum,&lt;br /&gt;
    characterOrMonster,&lt;br /&gt;
    &amp;quot;victim&amp;quot;,&lt;br /&gt;
    isMonster&lt;br /&gt;
  );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateBattleChoiceImage(battleChoice, characterName, newRace) {&lt;br /&gt;
  var imageSrc = battleChoice.raceToImage[newRace];&lt;br /&gt;
&lt;br /&gt;
  battleChoice.categories.forEach(function (category) {&lt;br /&gt;
    handleImageFromWiki(&lt;br /&gt;
      battleChoice[category].character.elements[characterName].image,&lt;br /&gt;
      imageSrc&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    var selected = battleChoice[category].selected;&lt;br /&gt;
&lt;br /&gt;
    if (isCharacterSelected(characterName, selected)) {&lt;br /&gt;
      updateBattleChoiceButton(battleChoice, category, selected);&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateBattleChoiceText(battleChoice, category, type) {&lt;br /&gt;
  var { count, container } = battleChoice[category][type];&lt;br /&gt;
  var parentContainer = container.parentElement;&lt;br /&gt;
&lt;br /&gt;
  if (count === 0) {&lt;br /&gt;
    hideElement(parentContainer);&lt;br /&gt;
    showElement(parentContainer.nextElementSibling);&lt;br /&gt;
  } else if (count === 1) {&lt;br /&gt;
    showElement(parentContainer);&lt;br /&gt;
    hideElement(parentContainer.nextElementSibling);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateBattleChoice(characters, battleChoice) {&lt;br /&gt;
  var templateImage = battleChoice.template.querySelector(&amp;quot;img&amp;quot;);&lt;br /&gt;
  var attackerImage = battleChoice.attacker.buttonContent.querySelector(&amp;quot;img&amp;quot;);&lt;br /&gt;
  var victimImage = battleChoice.victim.buttonContent.querySelector(&amp;quot;img&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  resetImageFromWiki(templateImage);&lt;br /&gt;
  resetImageFromWiki(attackerImage);&lt;br /&gt;
  resetImageFromWiki(victimImage);&lt;br /&gt;
&lt;br /&gt;
  for (var [pseudo, character] of Object.entries(characters.savedCharacters)) {&lt;br /&gt;
    addBattleChoice(battleChoice, pseudo, character);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (var [vnum, monster] of Object.entries(characters.savedMonsters)) {&lt;br /&gt;
    addBattleChoice(battleChoice, vnum, monster, true);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateBattleChoiceButton(battleChoice, category, data) {&lt;br /&gt;
  var battleChoiceCategory = battleChoice[category];&lt;br /&gt;
  var { defaultButtonContent, buttonContent } = battleChoiceCategory;&lt;br /&gt;
  var [buttonImage, buttonSpan] = buttonContent.firstElementChild.children;&lt;br /&gt;
  var { type, nameOrVnum } = parseTypeAndName(data);&lt;br /&gt;
  var { name, image } = battleChoiceCategory[type].elements[nameOrVnum];&lt;br /&gt;
&lt;br /&gt;
  hideElement(defaultButtonContent);&lt;br /&gt;
  showElement(buttonContent);&lt;br /&gt;
&lt;br /&gt;
  buttonSpan.textContent = name;&lt;br /&gt;
  buttonImage.src = image.src;&lt;br /&gt;
  battleChoiceCategory.selected = data;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function resetBattleChoiceButton(battleChoice, category) {&lt;br /&gt;
  var { defaultButtonContent, buttonContent } = battleChoice[category];&lt;br /&gt;
&lt;br /&gt;
  showElement(defaultButtonContent);&lt;br /&gt;
  hideElement(buttonContent);&lt;br /&gt;
&lt;br /&gt;
  if (category === &amp;quot;attacker&amp;quot;) {&lt;br /&gt;
    filterAttackTypeSelectionMonster(battleChoice.attackType);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isPC(character) {&lt;br /&gt;
  if (character.race === 0 || character.race === 1) {&lt;br /&gt;
    return false;&lt;br /&gt;
  }&lt;br /&gt;
  return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isBoss(character) {&lt;br /&gt;
  return character.race === 0 &amp;amp;&amp;amp; character.rank &amp;gt;= 5;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isStone(character) {&lt;br /&gt;
  return character.race === 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isMeleeAttacker(monster) {&lt;br /&gt;
  return monster.attack == 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isRangeAttacker(monster) {&lt;br /&gt;
  return monster.attack == 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isMagicAttacker(monster) {&lt;br /&gt;
  return monster.attack == 2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isMagicClass(character) {&lt;br /&gt;
  return character.race === &amp;quot;shaman&amp;quot; || character.class === &amp;quot;black_magic&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isDispell(character, skillId) {&lt;br /&gt;
  return character.class === &amp;quot;weaponary&amp;quot; &amp;amp;&amp;amp; skillId === 6;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isPolymorph(character) {&lt;br /&gt;
  return isChecked(character.isPolymorph);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isRiding(character) {&lt;br /&gt;
  return isChecked(character.isRiding);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isBow(weaponType) {&lt;br /&gt;
  return weaponType === 2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcAttackFactor(attacker, victim) {&lt;br /&gt;
  function calcCoeffK(dex, level) {&lt;br /&gt;
    return Math.min(90, Math.floor((2 * dex + level) / 3));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var K1 = calcCoeffK(attacker.polymorphDex, attacker.level);&lt;br /&gt;
  var K2 = calcCoeffK(victim.polymorphDex, attacker.level);&lt;br /&gt;
&lt;br /&gt;
  var AR = (K1 + 210) / 300;&lt;br /&gt;
  var ER = (((2 * K2 + 5) / (K2 + 95)) * 3) / 10;&lt;br /&gt;
&lt;br /&gt;
  return truncateNumber(AR - ER, 8);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcMainAttackValue(attacker) {&lt;br /&gt;
  var leadership = 0;&lt;br /&gt;
  var weaponGrowth = 0;&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker)) {&lt;br /&gt;
    weaponGrowth = attacker.weapon.growth;&lt;br /&gt;
    leadership = attacker.leadership;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return 2 * (attacker.level + weaponGrowth) + leadership;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcStatAttackValue(character) {&lt;br /&gt;
  switch (character.race) {&lt;br /&gt;
    case &amp;quot;warrior&amp;quot;:&lt;br /&gt;
    case &amp;quot;sura&amp;quot;:&lt;br /&gt;
      return 2 * character.str;&lt;br /&gt;
    case &amp;quot;ninja&amp;quot;:&lt;br /&gt;
      return Math.floor((1 / 4) * (character.str + 7 * character.dex));&lt;br /&gt;
    case &amp;quot;shaman&amp;quot;:&lt;br /&gt;
      return Math.floor((1 / 3) * (5 * character.int + character.dex));&lt;br /&gt;
    case &amp;quot;lycan&amp;quot;:&lt;br /&gt;
      return character.vit + 2 * character.dex;&lt;br /&gt;
    default:&lt;br /&gt;
      return 2 * character.str;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcPvpCriticalAttackRange(minAttackValue, maxAttackValue, growth) {&lt;br /&gt;
  return Array.from(&lt;br /&gt;
    { length: maxAttackValue - minAttackValue + 1 },&lt;br /&gt;
    (_, index) =&amp;gt; (minAttackValue + growth + index) * 2&lt;br /&gt;
  );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcSecondaryAttackValue(attacker, isPlayerVsPlayer) {&lt;br /&gt;
  let attackValueOther = 0;&lt;br /&gt;
&lt;br /&gt;
  let minAttackValue = 0;&lt;br /&gt;
  let maxAttackValue = 0;&lt;br /&gt;
&lt;br /&gt;
  let minAttackValueSlash = 0;&lt;br /&gt;
  let maxAttackValueSlash = 0;&lt;br /&gt;
&lt;br /&gt;
  let type, isSerpent, growth;&lt;br /&gt;
&lt;br /&gt;
  let criticalAttackRange;&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker)) {&lt;br /&gt;
    ({ type, isSerpent, minAttackValue, maxAttackValue, growth } =&lt;br /&gt;
      attacker.weapon);&lt;br /&gt;
&lt;br /&gt;
    if (isSerpent) {&lt;br /&gt;
      minAttackValue = Math.max(0, attacker.minAttackValueRandom - growth);&lt;br /&gt;
      maxAttackValue = Math.max(&lt;br /&gt;
        minAttackValue,&lt;br /&gt;
        attacker.maxAttackValueRandom - growth&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    minAttackValueSlash = Math.min(&lt;br /&gt;
      attacker.minAttackValueSlash,&lt;br /&gt;
      attacker.maxAttackValueSlash&lt;br /&gt;
    );&lt;br /&gt;
    maxAttackValueSlash = Math.max(&lt;br /&gt;
      attacker.minAttackValueSlash,&lt;br /&gt;
      attacker.maxAttackValueSlash&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    attackValueOther += attacker.attackValue;&lt;br /&gt;
&lt;br /&gt;
    if (isBow(type) &amp;amp;&amp;amp; !isPolymorph(attacker)) {&lt;br /&gt;
      attackValueOther += 25;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isPlayerVsPlayer) {&lt;br /&gt;
      criticalAttackRange = calcPvpCriticalAttackRange(&lt;br /&gt;
        minAttackValue,&lt;br /&gt;
        maxAttackValue,&lt;br /&gt;
        growth&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    minAttackValue = attacker.minAttackValue;&lt;br /&gt;
    maxAttackValue = attacker.maxAttackValue;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  minAttackValue += attacker.minAttackValuePolymorph;&lt;br /&gt;
  maxAttackValue += attacker.maxAttackValuePolymorph;&lt;br /&gt;
&lt;br /&gt;
  attackValueOther += attacker.statAttackValue;&lt;br /&gt;
  attackValueOther += attacker.horseAttackValue;&lt;br /&gt;
&lt;br /&gt;
  const weaponInterval = maxAttackValue - minAttackValue + 1;&lt;br /&gt;
  const slashInterval = maxAttackValueSlash - minAttackValueSlash + 1;&lt;br /&gt;
&lt;br /&gt;
  const totalCardinal = weaponInterval * slashInterval * 1_000_000;&lt;br /&gt;
  const minInterval = Math.min(weaponInterval, slashInterval);&lt;br /&gt;
&lt;br /&gt;
  minAttackValue += minAttackValueSlash;&lt;br /&gt;
  maxAttackValue += maxAttackValueSlash;&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    minAttackValue: minAttackValue,&lt;br /&gt;
    maxAttackValue: maxAttackValue,&lt;br /&gt;
    attackValueOther: attackValueOther,&lt;br /&gt;
    totalCardinal: totalCardinal,&lt;br /&gt;
    weights: calcWeights(minAttackValue, maxAttackValue, minInterval),&lt;br /&gt;
    possibleDamageCount: maxAttackValue - minAttackValue + 1,&lt;br /&gt;
    criticalAttackRange: criticalAttackRange,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcMagicAttackValue(attacker, isPlayerVsPlayer) {&lt;br /&gt;
  let minMagicAttackValueSlash = 0;&lt;br /&gt;
  let maxMagicAttackValueSlash = 0;&lt;br /&gt;
&lt;br /&gt;
  let criticalAttackRange;&lt;br /&gt;
&lt;br /&gt;
  let {&lt;br /&gt;
    isSerpent,&lt;br /&gt;
    minMagicAttackValue,&lt;br /&gt;
    maxMagicAttackValue,&lt;br /&gt;
    minAttackValue,&lt;br /&gt;
    maxAttackValue,&lt;br /&gt;
    growth,&lt;br /&gt;
  } = attacker.weapon;&lt;br /&gt;
&lt;br /&gt;
  if (isSerpent) {&lt;br /&gt;
    minMagicAttackValue = Math.max(0, attacker.minMagicAttackValueRandom);&lt;br /&gt;
    maxMagicAttackValue = Math.max(&lt;br /&gt;
      minMagicAttackValue,&lt;br /&gt;
      attacker.maxMagicAttackValueRandom&lt;br /&gt;
    );&lt;br /&gt;
    minAttackValue = Math.max(0, attacker.minAttackValueRandom - growth);&lt;br /&gt;
    maxAttackValue = Math.max(&lt;br /&gt;
      minAttackValue,&lt;br /&gt;
      attacker.maxAttackValueRandom - growth&lt;br /&gt;
    );&lt;br /&gt;
  } else {&lt;br /&gt;
    minMagicAttackValue += growth;&lt;br /&gt;
    maxMagicAttackValue += growth;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (isPlayerVsPlayer) {&lt;br /&gt;
    criticalAttackRange = calcPvpCriticalAttackRange(&lt;br /&gt;
      minAttackValue,&lt;br /&gt;
      maxAttackValue,&lt;br /&gt;
      growth&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  minMagicAttackValueSlash = Math.min(&lt;br /&gt;
    attacker.minMagicAttackValueSlash,&lt;br /&gt;
    attacker.maxMagicAttackValueSlash&lt;br /&gt;
  );&lt;br /&gt;
  maxMagicAttackValueSlash = Math.max(&lt;br /&gt;
    attacker.minMagicAttackValueSlash,&lt;br /&gt;
    attacker.maxMagicAttackValueSlash&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  const weaponInterval = maxMagicAttackValue - minMagicAttackValue + 1;&lt;br /&gt;
  const slashInterval = maxMagicAttackValueSlash - minMagicAttackValueSlash + 1;&lt;br /&gt;
&lt;br /&gt;
  const totalCardinal = weaponInterval * slashInterval * 1_000_000;&lt;br /&gt;
  const minInterval = Math.min(weaponInterval, slashInterval);&lt;br /&gt;
&lt;br /&gt;
  minMagicAttackValue += minMagicAttackValueSlash;&lt;br /&gt;
  maxMagicAttackValue += maxMagicAttackValueSlash;&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    minMagicAttackValue: minMagicAttackValue,&lt;br /&gt;
    maxMagicAttackValue: maxMagicAttackValue,&lt;br /&gt;
    magicAttackValueAugmentation: getMagicAttackValueAugmentation(&lt;br /&gt;
      minMagicAttackValue,&lt;br /&gt;
      maxMagicAttackValue,&lt;br /&gt;
      attacker.magicAttackValue&lt;br /&gt;
    ),&lt;br /&gt;
    totalCardinal: totalCardinal,&lt;br /&gt;
    weights: calcWeights(minMagicAttackValue, maxMagicAttackValue, minInterval),&lt;br /&gt;
    possibleDamageCount: maxMagicAttackValue - minMagicAttackValue + 1,&lt;br /&gt;
    criticalAttackRange: criticalAttackRange,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getPolymorphPower(polymorphPoint, polymorphPowerTable) {&lt;br /&gt;
  return polymorphPowerTable[polymorphPoint];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSkillPower(skillPoint, skillPowerTable) {&lt;br /&gt;
  return skillPowerTable[skillPoint];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getMarriageBonusValue(character, marriageTable, itemName) {&lt;br /&gt;
  let index;&lt;br /&gt;
  const lovePoint = character.lovePoint;&lt;br /&gt;
&lt;br /&gt;
  if (lovePoint &amp;lt; 65) {&lt;br /&gt;
    index = 0;&lt;br /&gt;
  } else if (lovePoint &amp;lt; 80) {&lt;br /&gt;
    index = 1;&lt;br /&gt;
  } else if (lovePoint &amp;lt; 100) {&lt;br /&gt;
    index = 2;&lt;br /&gt;
  } else {&lt;br /&gt;
    index = 3;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return marriageTable[itemName][index];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcDamageWithPrimaryBonuses(damage, bonusValues) {&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.attackValueCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  damage += bonusValues.attackValueMarriage;&lt;br /&gt;
&lt;br /&gt;
  damage = Math.floor(&lt;br /&gt;
    (damage * bonusValues.monsterResistanceMarriageCoeff) / 100&lt;br /&gt;
  );&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.monsterResistanceCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  damage += Math.floor((damage * bonusValues.typeBonusCoeff) / 100);&lt;br /&gt;
  damage +=&lt;br /&gt;
    Math.floor((damage * bonusValues.raceBonusCoeff) / 100) -&lt;br /&gt;
    Math.floor((damage * bonusValues.raceResistanceCoeff) / 100);&lt;br /&gt;
  damage += Math.floor((damage * bonusValues.stoneBonusCoeff) / 100);&lt;br /&gt;
  damage += Math.floor((damage * bonusValues.monsterBonusCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  const elementBonusCoeff = bonusValues.elementBonusCoeff;&lt;br /&gt;
&lt;br /&gt;
  damage +=&lt;br /&gt;
    Math.trunc((damage * elementBonusCoeff[0]) / 10000) +&lt;br /&gt;
    Math.trunc((damage * elementBonusCoeff[1]) / 10000) +&lt;br /&gt;
    Math.trunc((damage * elementBonusCoeff[2]) / 10000) +&lt;br /&gt;
    Math.trunc((damage * elementBonusCoeff[3]) / 10000) +&lt;br /&gt;
    Math.trunc((damage * elementBonusCoeff[4]) / 10000) +&lt;br /&gt;
    Math.trunc((damage * elementBonusCoeff[5]) / 10000);&lt;br /&gt;
&lt;br /&gt;
  damage = Math.floor(damage * bonusValues.damageMultiplier);&lt;br /&gt;
&lt;br /&gt;
  return Math.max(0, damage);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcFinalDamage(&lt;br /&gt;
  finalDamage,&lt;br /&gt;
  damageWithPrimaryBonuses,&lt;br /&gt;
  bonusValues,&lt;br /&gt;
  criticalAttackRange,&lt;br /&gt;
  damageByType&lt;br /&gt;
) {&lt;br /&gt;
  for (let criticalIndex = 0; criticalIndex &amp;lt; 2; criticalIndex++) {&lt;br /&gt;
    if (bonusValues.skipCriticalStep[criticalIndex]) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
    let beforeCriticalDamage = finalDamage;&lt;br /&gt;
    let damageValues = criticalIndex&lt;br /&gt;
      ? criticalAttackRange || [finalDamage]&lt;br /&gt;
      : [0];&lt;br /&gt;
&lt;br /&gt;
    for (let index = 0, len = damageValues.length; index &amp;lt; len; index++) {&lt;br /&gt;
      let afterCriticalDamage = beforeCriticalDamage + damageValues[index];&lt;br /&gt;
&lt;br /&gt;
      for (let piercingIndex = 0; piercingIndex &amp;lt; 2; piercingIndex++) {&lt;br /&gt;
        if (bonusValues.skipPiercingStep[piercingIndex]) {&lt;br /&gt;
          continue;&lt;br /&gt;
        }&lt;br /&gt;
        let damage = afterCriticalDamage;&lt;br /&gt;
&lt;br /&gt;
        if (piercingIndex) {&lt;br /&gt;
          damage += Math.min(&lt;br /&gt;
            bonusValues.defenseBoost,&lt;br /&gt;
            damageWithPrimaryBonuses&lt;br /&gt;
          );&lt;br /&gt;
          damage += Math.floor(&lt;br /&gt;
            (damageWithPrimaryBonuses * bonusValues.extraPiercingHitCoeff) /&lt;br /&gt;
              1000&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        damage = Math.floor((damage * bonusValues.averageDamageCoeff) / 100);&lt;br /&gt;
        damage = Math.floor(&lt;br /&gt;
          (damage * bonusValues.averageDamageResistanceCoeff) / 100&lt;br /&gt;
        );&lt;br /&gt;
        damage = Math.floor((damage * bonusValues.skillDamageCoeff) / 100);&lt;br /&gt;
        damage = Math.floor(&lt;br /&gt;
          (damage * bonusValues.skillDamageResistanceCoeff) / 100&lt;br /&gt;
        );&lt;br /&gt;
        damage = Math.floor((damage * bonusValues.rankBonusCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
        if (bonusValues.useDarkProtection) {&lt;br /&gt;
          const { darkProtectionPoint, darkProtectionSp } = bonusValues;&lt;br /&gt;
&lt;br /&gt;
          const damageReduction = Math.floor(damage / 3);&lt;br /&gt;
          const spAbsorption = Math.floor(&lt;br /&gt;
            (damageReduction * darkProtectionPoint) / 100&lt;br /&gt;
          );&lt;br /&gt;
&lt;br /&gt;
          if (spAbsorption &amp;lt;= darkProtectionSp) {&lt;br /&gt;
            damage -= damageReduction;&lt;br /&gt;
          } else {&lt;br /&gt;
            damage -= Math.floor(&lt;br /&gt;
              (darkProtectionSp * 100) / darkProtectionPoint&lt;br /&gt;
            );&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        damage -= Math.floor(&lt;br /&gt;
          (damage * bonusValues.resistance90PercentHp) / 100&lt;br /&gt;
        );&lt;br /&gt;
        damage = Math.max(0, damage + bonusValues.defensePercent);&lt;br /&gt;
        damage += Math.min(&lt;br /&gt;
          300,&lt;br /&gt;
          Math.floor((damage * bonusValues.damageBonusCoeff) / 100)&lt;br /&gt;
        );&lt;br /&gt;
        damage = Math.floor((damage * bonusValues.empireMalusCoeff) / 10);&lt;br /&gt;
        damage = Math.floor((damage * bonusValues.sungMaStrBonusCoeff) / 10000);&lt;br /&gt;
        damage -= Math.floor(damage * bonusValues.sungmaStrMalusCoeff);&lt;br /&gt;
        damage = Math.floor(&lt;br /&gt;
          (damage * bonusValues.whiteDragonElixirCoeff) / 100&lt;br /&gt;
        );&lt;br /&gt;
        damage = Math.floor(&lt;br /&gt;
          (damage * bonusValues.steelDragonElixirCoeff) / 100&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        damageByType[criticalIndex + 2 * piercingIndex].push(damage);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveFinalDamage(&lt;br /&gt;
  damage,&lt;br /&gt;
  damageWithPrimaryBonuses,&lt;br /&gt;
  bonusValues,&lt;br /&gt;
  criticalAttackRange,&lt;br /&gt;
  damageByType&lt;br /&gt;
) {&lt;br /&gt;
  damage = Math.floor(damage * bonusValues.magicResistanceCoeff);&lt;br /&gt;
  damage = Math.trunc((damage * bonusValues.weaponDefenseCoeff) / 100);&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.tigerStrengthCoeff) / 100);&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.berserkBonusCoeff) / 100);&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.fearBonusCoeff) / 100);&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.blessingBonusCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  calcFinalDamage(&lt;br /&gt;
    damage,&lt;br /&gt;
    damageWithPrimaryBonuses,&lt;br /&gt;
    bonusValues,&lt;br /&gt;
    criticalAttackRange,&lt;br /&gt;
    damageByType&lt;br /&gt;
  );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveFinalSkillDamage(&lt;br /&gt;
  damage,&lt;br /&gt;
  bonusValues,&lt;br /&gt;
  criticalAttackRange,&lt;br /&gt;
  damageByType&lt;br /&gt;
) {&lt;br /&gt;
  damage = Math.floor(damage * bonusValues.magicResistanceCoeff);&lt;br /&gt;
  damage = Math.trunc((damage * bonusValues.weaponDefenseCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  damage -= bonusValues.defense;&lt;br /&gt;
&lt;br /&gt;
  const damageValues =&lt;br /&gt;
    damage &amp;lt;= 2 &amp;amp;&amp;amp; bonusValues.isPhysicalSkill ? [1, 2, 3, 4, 5] : [damage];&lt;br /&gt;
&lt;br /&gt;
  for (const minDamage of damageValues) {&lt;br /&gt;
    damage = floorMultiplication(minDamage, bonusValues.skillWardCoeff);&lt;br /&gt;
    damage = floorMultiplication(damage, bonusValues.skillBonusCoeff);&lt;br /&gt;
&lt;br /&gt;
    const tempDamage = Math.floor(&lt;br /&gt;
      (damage * bonusValues.skillBonusByBonusCoeff) / 100&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    damage = Math.floor(&lt;br /&gt;
      (tempDamage * bonusValues.magicAttackValueCoeff) / 100 + 0.5&lt;br /&gt;
    );&lt;br /&gt;
    damage = Math.floor((damage * bonusValues.tigerStrengthCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
    calcFinalDamage(&lt;br /&gt;
      damage,&lt;br /&gt;
      tempDamage,&lt;br /&gt;
      bonusValues,&lt;br /&gt;
      criticalAttackRange,&lt;br /&gt;
      damageByType&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function computePolymorphPoint(attacker, victim, polymorphPowerTable) {&lt;br /&gt;
  attacker.polymorphDex = attacker.dex;&lt;br /&gt;
  victim.polymorphDex = victim.dex;&lt;br /&gt;
&lt;br /&gt;
  attacker.minAttackValuePolymorph = 0;&lt;br /&gt;
  attacker.maxAttackValuePolymorph = 0;&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker) &amp;amp;&amp;amp; isPolymorph(attacker)) {&lt;br /&gt;
    var polymorphPowerPct =&lt;br /&gt;
      getPolymorphPower(attacker.polymorphPoint, polymorphPowerTable) / 100;&lt;br /&gt;
    var polymorphMonster = createMonster(&lt;br /&gt;
      attacker.polymorphMonster,&lt;br /&gt;
      null,&lt;br /&gt;
      null,&lt;br /&gt;
      true&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    var polymorphStr = floorMultiplication(&lt;br /&gt;
      polymorphPowerPct,&lt;br /&gt;
      polymorphMonster.str&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    attacker.polymorphDex += floorMultiplication(&lt;br /&gt;
      polymorphPowerPct,&lt;br /&gt;
      polymorphMonster.dex&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    attacker.minAttackValuePolymorph = floorMultiplication(&lt;br /&gt;
      polymorphPowerPct,&lt;br /&gt;
      polymorphMonster.minAttackValue&lt;br /&gt;
    );&lt;br /&gt;
    attacker.maxAttackValuePolymorph = floorMultiplication(&lt;br /&gt;
      polymorphPowerPct,&lt;br /&gt;
      polymorphMonster.maxAttackValue&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    if (!attacker.weapon) {&lt;br /&gt;
      attacker.maxAttackValuePolymorph += 1;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    attacker.attackValue = 0;&lt;br /&gt;
&lt;br /&gt;
    if (isMagicClass(attacker)) {&lt;br /&gt;
      attacker.statAttackValue = 2 * (polymorphStr + attacker.int);&lt;br /&gt;
    } else {&lt;br /&gt;
      attacker.statAttackValue = 2 * (polymorphStr + attacker.str);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function computeHorse(attacker) {&lt;br /&gt;
  attacker.horseAttackValue = 0;&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker) &amp;amp;&amp;amp; isRiding(attacker) &amp;amp;&amp;amp; !isPolymorph(attacker)) {&lt;br /&gt;
    var horseConstant = 30;&lt;br /&gt;
&lt;br /&gt;
    if (attacker.class === &amp;quot;weaponary&amp;quot;) {&lt;br /&gt;
      horseConstant = 60;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    attacker.horseAttackValue = floorMultiplication(&lt;br /&gt;
      2 * attacker.level + attacker.statAttackValue,&lt;br /&gt;
      attacker.horsePoint / horseConstant&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getRankBonus(attacker) {&lt;br /&gt;
  if (!isChecked(attacker.lowRank)) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  switch (attacker.rank) {&lt;br /&gt;
    case &amp;quot;aggressive&amp;quot;:&lt;br /&gt;
      return 1;&lt;br /&gt;
    case &amp;quot;fraudulent&amp;quot;:&lt;br /&gt;
      return 2;&lt;br /&gt;
    case &amp;quot;malicious&amp;quot;:&lt;br /&gt;
      return 3;&lt;br /&gt;
    case &amp;quot;cruel&amp;quot;:&lt;br /&gt;
      return 5;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcElementCoeffPvP(elementBonus, mapping, attacker, victim) {&lt;br /&gt;
  var minElementMalus = 0;&lt;br /&gt;
  var maxDifference = 0;&lt;br /&gt;
  var savedElementDifferences = [];&lt;br /&gt;
  var elementBonusIndex = 0;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; elementBonus.length; index++) {&lt;br /&gt;
    if (!attacker[mapping.elementBonus[index]]) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var elementDifference =&lt;br /&gt;
      attacker[mapping.elementBonus[index]] -&lt;br /&gt;
      victim[mapping.elementResistance[index]];&lt;br /&gt;
&lt;br /&gt;
    if (elementDifference &amp;gt;= 0) {&lt;br /&gt;
      elementBonus[elementBonusIndex] = 10 * elementDifference;&lt;br /&gt;
      minElementMalus -= elementDifference;&lt;br /&gt;
      maxDifference = Math.max(maxDifference, elementDifference);&lt;br /&gt;
      elementBonusIndex++;&lt;br /&gt;
    } else {&lt;br /&gt;
      savedElementDifferences.push(elementDifference);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (!savedElementDifferences.length) {&lt;br /&gt;
    return;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  minElementMalus += maxDifference;&lt;br /&gt;
  savedElementDifferences.sort(compareNumbers);&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; savedElementDifferences.length; index++) {&lt;br /&gt;
    var elementDifference = savedElementDifferences[index];&lt;br /&gt;
&lt;br /&gt;
    elementBonus[elementBonusIndex + index] =&lt;br /&gt;
      10 * Math.max(minElementMalus, elementDifference);&lt;br /&gt;
&lt;br /&gt;
    minElementMalus = Math.min(&lt;br /&gt;
      0,&lt;br /&gt;
      Math.max(minElementMalus, minElementMalus - elementDifference)&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcCriticalHitChance(criticalHitPercentage) {&lt;br /&gt;
  if (criticalHitPercentage &amp;lt;= 9) {&lt;br /&gt;
    return Math.floor((criticalHitPercentage + 5) / 5);&lt;br /&gt;
  }&lt;br /&gt;
  return Math.floor((criticalHitPercentage + 5) / 6);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcCriticalSkillChance(criticalHitPercentage) {&lt;br /&gt;
  if (criticalHitPercentage === 0) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  } else if (criticalHitPercentage &amp;lt;= 9) {&lt;br /&gt;
    return Math.floor((criticalHitPercentage + 7) / 3);&lt;br /&gt;
  }&lt;br /&gt;
  return Math.floor((criticalHitPercentage + 5) / 3);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcPiercingSkillChance(piercingHitPercentage) {&lt;br /&gt;
  if (piercingHitPercentage &amp;lt;= 9) {&lt;br /&gt;
    return Math.floor(piercingHitPercentage / 2);&lt;br /&gt;
  }&lt;br /&gt;
  return 5 + Math.floor((piercingHitPercentage - 10) / 4);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function magicResistanceToCoeff(magicResistance) {&lt;br /&gt;
  if (magicResistance) {&lt;br /&gt;
    return 2000 / (6 * magicResistance + 1000) - 1;&lt;br /&gt;
  }&lt;br /&gt;
  return 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createBattleValues(attacker, victim, battle, skillType) {&lt;br /&gt;
  var {&lt;br /&gt;
    mapping,&lt;br /&gt;
    constants: { polymorphPowerTable, skillPowerTable, marriageTable },&lt;br /&gt;
  } = battle;&lt;br /&gt;
  var calcAttackValues;&lt;br /&gt;
&lt;br /&gt;
  var missPercentage = 0;&lt;br /&gt;
  var attackValueMeleeMagic = 0;&lt;br /&gt;
  var attackValueMarriage = 0;&lt;br /&gt;
  var monsterResistanceMarriage = 0;&lt;br /&gt;
  var monsterResistance = 0;&lt;br /&gt;
  var typeBonus = 0;&lt;br /&gt;
  var raceBonus = 0;&lt;br /&gt;
  var raceResistance = 0;&lt;br /&gt;
  var stoneBonus = 0;&lt;br /&gt;
  var monsterBonus = 0;&lt;br /&gt;
  var elementBonus = [0, 0, 0, 0, 0, 0]; // fire, ice, lightning, earth, darkness, wind, order doesn't matter&lt;br /&gt;
  var defenseMarriage = 0;&lt;br /&gt;
  var damageMultiplier = 1;&lt;br /&gt;
  var useDamage = 1;&lt;br /&gt;
  var defense = victim.defense;&lt;br /&gt;
  var defenseBoost = defense;&lt;br /&gt;
  var magicResistance = 0;&lt;br /&gt;
  var magicPenetration = 0;&lt;br /&gt;
  var weaponDefense = 0;&lt;br /&gt;
  var tigerStrength = 0;&lt;br /&gt;
  var berserkBonus = 0;&lt;br /&gt;
  var blessingBonus = 0;&lt;br /&gt;
  var fearBonus = 0;&lt;br /&gt;
  var magicAttackValueMeleeMagic = 0;&lt;br /&gt;
  var criticalHitPercentage = attacker.criticalHit;&lt;br /&gt;
  var isPlayerVsPlayer = false;&lt;br /&gt;
  var piercingHitPercentage = attacker.piercingHit;&lt;br /&gt;
  var extraPiercingHitPercentage = Math.max(0, piercingHitPercentage - 100);&lt;br /&gt;
  var averageDamage = 0;&lt;br /&gt;
  var averageDamageResistance = 0;&lt;br /&gt;
  var skillDamage = 0;&lt;br /&gt;
  var skillDamageResistance = 0;&lt;br /&gt;
  var rankBonus = 0;&lt;br /&gt;
  var useDarkProtection = false;&lt;br /&gt;
  var darkProtectionPoint = 0;&lt;br /&gt;
  var resistance90PercentHp = 0;&lt;br /&gt;
  var defensePercent = 0;&lt;br /&gt;
  var damageBonus = 0;&lt;br /&gt;
  var empireMalus = 0;&lt;br /&gt;
  var sungMaStrBonus = 0;&lt;br /&gt;
  var sungmaStrMalus = 0;&lt;br /&gt;
  var whiteDragonElixir = 0;&lt;br /&gt;
  var steelDragonElixir = 0;&lt;br /&gt;
&lt;br /&gt;
  attacker.statAttackValue = calcStatAttackValue(attacker);&lt;br /&gt;
&lt;br /&gt;
  computePolymorphPoint(attacker, victim, polymorphPowerTable);&lt;br /&gt;
  computeHorse(attacker);&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker)) {&lt;br /&gt;
    if (weaponData.hasOwnProperty(attacker.weapon)) {&lt;br /&gt;
      attacker.weapon = createWeapon(attacker.weapon);&lt;br /&gt;
    } else {&lt;br /&gt;
      attacker.weapon = createWeapon(0);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    attacker.weapon.getValues(attacker.weaponUpgrade);&lt;br /&gt;
&lt;br /&gt;
    attackValueMeleeMagic =&lt;br /&gt;
      attacker.attackValuePercent + Math.min(100, attacker.attackMeleeMagic);&lt;br /&gt;
&lt;br /&gt;
    var weaponType = attacker.weapon.type;&lt;br /&gt;
&lt;br /&gt;
    if (skillType &amp;amp;&amp;amp; attacker.class === &amp;quot;archery&amp;quot;) {&lt;br /&gt;
      if (weaponType !== 2) {&lt;br /&gt;
        useDamage = 0;&lt;br /&gt;
        weaponType = 2;&lt;br /&gt;
      }&lt;br /&gt;
      defense = 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var weaponDefenseName = mapping.defenseWeapon[weaponType];&lt;br /&gt;
    var weaponDefenseBreakName = mapping.breakWeapon[weaponType];&lt;br /&gt;
&lt;br /&gt;
    if (victim.hasOwnProperty(weaponDefenseName)) {&lt;br /&gt;
      weaponDefense = victim[weaponDefenseName];&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isChecked(attacker.whiteDragonElixir)) {&lt;br /&gt;
      whiteDragonElixir = 10;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    magicPenetration = attacker.magicPenetration;&lt;br /&gt;
&lt;br /&gt;
    if (isPC(victim)) {&lt;br /&gt;
      isPlayerVsPlayer = true;&lt;br /&gt;
&lt;br /&gt;
      if (!skillType) {&lt;br /&gt;
        if (weaponType === 2 &amp;amp;&amp;amp; !isPolymorph(attacker)) {&lt;br /&gt;
          missPercentage = victim.arrowBlock;&lt;br /&gt;
        } else {&lt;br /&gt;
          missPercentage = victim.meleeBlock;&lt;br /&gt;
        }&lt;br /&gt;
        missPercentage +=&lt;br /&gt;
          victim.meleeArrowBlock -&lt;br /&gt;
          (missPercentage * victim.meleeArrowBlock) / 100;&lt;br /&gt;
&lt;br /&gt;
        criticalHitPercentage = calcCriticalHitChance(criticalHitPercentage);&lt;br /&gt;
        berserkBonus = calcBerserkBonus(skillPowerTable, victim);&lt;br /&gt;
        blessingBonus = calcBlessingBonus(skillPowerTable, victim);&lt;br /&gt;
        fearBonus = calcFearBonus(skillPowerTable, victim);&lt;br /&gt;
        averageDamageResistance = victim.averageDamageResistance;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      typeBonus = Math.max(1, attacker.humanBonus - victim.humanResistance);&lt;br /&gt;
      raceBonus = attacker[mapping.raceBonus[victim.race]];&lt;br /&gt;
      raceResistance = victim[mapping.raceResistance[attacker.race]];&lt;br /&gt;
&lt;br /&gt;
      calcElementCoeffPvP(elementBonus, mapping, attacker, victim);&lt;br /&gt;
&lt;br /&gt;
      if (weaponType !== 2 &amp;amp;&amp;amp; attacker.hasOwnProperty(weaponDefenseBreakName)) {&lt;br /&gt;
        weaponDefense -= attacker[weaponDefenseBreakName];&lt;br /&gt;
      }&lt;br /&gt;
    } else {&lt;br /&gt;
      if (isChecked(attacker.isMarried)) {&lt;br /&gt;
        if (isChecked(attacker.loveNecklace)) {&lt;br /&gt;
          attackValueMarriage = getMarriageBonusValue(&lt;br /&gt;
            attacker,&lt;br /&gt;
            marriageTable,&lt;br /&gt;
            &amp;quot;loveNecklace&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isChecked(attacker.loveEarrings)) {&lt;br /&gt;
          criticalHitPercentage += getMarriageBonusValue(&lt;br /&gt;
            attacker,&lt;br /&gt;
            marriageTable,&lt;br /&gt;
            &amp;quot;loveEarrings&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isChecked(attacker.harmonyEarrings)) {&lt;br /&gt;
          piercingHitPercentage += getMarriageBonusValue(&lt;br /&gt;
            attacker,&lt;br /&gt;
            marriageTable,&lt;br /&gt;
            &amp;quot;harmonyEarrings&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (isChecked(attacker.tigerStrength)) {&lt;br /&gt;
        tigerStrength = 40;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      for (var index = 0; index &amp;lt; elementBonus.length; index++) {&lt;br /&gt;
        var elementBonusName = mapping.elementBonus[index];&lt;br /&gt;
        var elementResistanceName = mapping.elementResistance[index];&lt;br /&gt;
&lt;br /&gt;
        if (attacker[elementBonusName] &amp;amp;&amp;amp; victim[elementBonusName]) {&lt;br /&gt;
          elementBonus[index] =&lt;br /&gt;
            50 * (attacker[elementBonusName] - victim[elementResistanceName]);&lt;br /&gt;
        } else {&lt;br /&gt;
          elementBonus[index] = 5 * attacker[elementBonusName];&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      var victimType = victim.type;&lt;br /&gt;
&lt;br /&gt;
      if (victimType !== -1) {&lt;br /&gt;
        typeBonus = attacker[mapping.typeFlag[victimType]];&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      monsterBonus = attacker.monsterBonus;&lt;br /&gt;
&lt;br /&gt;
      if (isStone(victim)) {&lt;br /&gt;
        stoneBonus = attacker.stoneBonus;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (isBoss(victim)) {&lt;br /&gt;
        if (skillType) {&lt;br /&gt;
          skillDamage += attacker.skillBossDamage;&lt;br /&gt;
        } else {&lt;br /&gt;
          averageDamage += attacker.bossDamage;&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (isChecked(attacker.onYohara)) {&lt;br /&gt;
        var sungmaStrDifference = attacker.sungmaStr - attacker.sungmaStrMalus;&lt;br /&gt;
&lt;br /&gt;
        if (sungmaStrDifference &amp;gt;= 0) {&lt;br /&gt;
          sungMaStrBonus = sungmaStrDifference;&lt;br /&gt;
        } else {&lt;br /&gt;
          sungmaStrMalus = 0.5;&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (skillType) {&lt;br /&gt;
      skillDamage += attacker.skillDamage;&lt;br /&gt;
    } else {&lt;br /&gt;
      averageDamage += attacker.averageDamage;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    rankBonus = getRankBonus(attacker);&lt;br /&gt;
    damageBonus = attacker.damageBonus;&lt;br /&gt;
&lt;br /&gt;
    if (isChecked(attacker.empireMalus)) {&lt;br /&gt;
      empireMalus = 1;&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    if (isPC(victim)) {&lt;br /&gt;
      if (isChecked(victim.isMarried)) {&lt;br /&gt;
        if (isChecked(victim.harmonyBracelet)) {&lt;br /&gt;
          monsterResistanceMarriage = getMarriageBonusValue(&lt;br /&gt;
            victim,&lt;br /&gt;
            marriageTable,&lt;br /&gt;
            &amp;quot;harmonyBracelet&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isChecked(victim.harmonyNecklace) &amp;amp;&amp;amp; !skillType) {&lt;br /&gt;
          defenseMarriage = getMarriageBonusValue(&lt;br /&gt;
            victim,&lt;br /&gt;
            marriageTable,&lt;br /&gt;
            &amp;quot;harmonyNecklace&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      monsterResistance = victim.monsterResistance;&lt;br /&gt;
&lt;br /&gt;
      for (var index = 0; index &amp;lt; elementBonus.length; index++) {&lt;br /&gt;
        var elementBonusName = mapping.elementBonus[index];&lt;br /&gt;
        var elementResistanceName = mapping.elementResistance[index];&lt;br /&gt;
&lt;br /&gt;
        if (attacker[elementBonusName]) {&lt;br /&gt;
          elementBonus[index] =&lt;br /&gt;
            80 * (attacker[elementBonusName] - victim[elementResistanceName]);&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (!skillType) {&lt;br /&gt;
        if (isMeleeAttacker(attacker)) {&lt;br /&gt;
          missPercentage = victim.meleeBlock;&lt;br /&gt;
          averageDamageResistance = victim.averageDamageResistance;&lt;br /&gt;
          berserkBonus = calcBerserkBonus(skillPowerTable, victim);&lt;br /&gt;
          blessingBonus = calcBlessingBonus(skillPowerTable, victim);&lt;br /&gt;
          fearBonus = calcFearBonus(skillPowerTable, victim);&lt;br /&gt;
        } else if (isRangeAttacker(attacker)) {&lt;br /&gt;
          missPercentage = victim.arrowBlock;&lt;br /&gt;
          weaponDefense = victim.arrowDefense;&lt;br /&gt;
          averageDamageResistance = victim.averageDamageResistance;&lt;br /&gt;
          berserkBonus = calcBerserkBonus(skillPowerTable, victim);&lt;br /&gt;
          blessingBonus = calcBlessingBonus(skillPowerTable, victim);&lt;br /&gt;
          fearBonus = calcFearBonus(skillPowerTable, victim);&lt;br /&gt;
        } else if (isMagicAttacker(attacker)) {&lt;br /&gt;
          missPercentage = victim.arrowBlock;&lt;br /&gt;
          skillDamageResistance = victim.skillDamageResistance;&lt;br /&gt;
          magicResistance = victim.magicResistance;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        missPercentage +=&lt;br /&gt;
          victim.meleeArrowBlock -&lt;br /&gt;
          (missPercentage * victim.meleeArrowBlock) / 100;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    typeBonus = 1;&lt;br /&gt;
    damageMultiplier = attacker.damageMultiplier;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillType) {&lt;br /&gt;
    criticalHitPercentage = calcCriticalSkillChance(criticalHitPercentage);&lt;br /&gt;
    piercingHitPercentage = calcPiercingSkillChance(piercingHitPercentage);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (isPC(victim)) {&lt;br /&gt;
    if (!skillType &amp;amp;&amp;amp; isChecked(victim.biologist70)) {&lt;br /&gt;
      defenseBoost = Math.floor((defenseBoost * 110) / 100);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    criticalHitPercentage = Math.max(&lt;br /&gt;
      0,&lt;br /&gt;
      criticalHitPercentage - victim.criticalHitResistance&lt;br /&gt;
    );&lt;br /&gt;
    piercingHitPercentage = Math.max(&lt;br /&gt;
      0,&lt;br /&gt;
      piercingHitPercentage - victim.piercingHitResistance&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    if (skillType) {&lt;br /&gt;
      skillDamageResistance = victim.skillDamageResistance;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      victim.useDarkProtection &amp;amp;&amp;amp;&lt;br /&gt;
      victim.class === &amp;quot;black_magic&amp;quot; &amp;amp;&amp;amp;&lt;br /&gt;
      victim.skillDarkProtection&lt;br /&gt;
    ) {&lt;br /&gt;
      useDarkProtection = true;&lt;br /&gt;
      darkProtectionPoint = calcDarkProtectionPoint(skillPowerTable, victim);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    resistance90PercentHp = victim.resistance90PercentHp || 0;&lt;br /&gt;
&lt;br /&gt;
    if (isMagicClass(victim)) {&lt;br /&gt;
      defensePercent = (-2 * victim.magicDefense * victim.defensePercent) / 100;&lt;br /&gt;
    } else {&lt;br /&gt;
      defensePercent = (-2 * defenseBoost * victim.defensePercent) / 100;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isChecked(victim.steelDragonElixir)) {&lt;br /&gt;
      steelDragonElixir = 10;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillType === &amp;quot;magic&amp;quot;) {&lt;br /&gt;
    attackValueMeleeMagic = 0;&lt;br /&gt;
    magicAttackValueMeleeMagic =&lt;br /&gt;
      attacker.attackMagic + Math.min(100, attacker.attackMeleeMagic);&lt;br /&gt;
    attackValueMarriage = 0;&lt;br /&gt;
    defense = 0;&lt;br /&gt;
    magicResistance = victim.magicResistance;&lt;br /&gt;
&lt;br /&gt;
    if (magicResistance &amp;gt; 0 &amp;amp;&amp;amp; magicPenetration) {&lt;br /&gt;
      magicResistance = Math.floor(&lt;br /&gt;
        magicResistance * (1 - magicPenetration / 120) + 0.5&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    weaponDefense = 0;&lt;br /&gt;
    calcAttackValues = calcMagicAttackValue;&lt;br /&gt;
&lt;br /&gt;
    if (isDispell(attacker, 6)) {&lt;br /&gt;
      typeBonus = 0;&lt;br /&gt;
      raceBonus = 0;&lt;br /&gt;
      raceResistance = 0;&lt;br /&gt;
      stoneBonus = 0;&lt;br /&gt;
      monsterBonus = 0;&lt;br /&gt;
      for (var index = 0; index &amp;lt; elementBonus.length; index++) {&lt;br /&gt;
        elementBonus[index] = 0;&lt;br /&gt;
      }&lt;br /&gt;
      magicResistance = 0;&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    calcAttackValues = calcSecondaryAttackValue;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  missPercentage = Math.min(100, missPercentage);&lt;br /&gt;
  criticalHitPercentage = Math.min(criticalHitPercentage, 100);&lt;br /&gt;
  piercingHitPercentage = Math.min(piercingHitPercentage, 100);&lt;br /&gt;
&lt;br /&gt;
  const bonusValues = {&lt;br /&gt;
    missPercentage: missPercentage,&lt;br /&gt;
    skipCriticalStep: [&lt;br /&gt;
      !Boolean(100 - criticalHitPercentage),&lt;br /&gt;
      !Boolean(criticalHitPercentage),&lt;br /&gt;
    ],&lt;br /&gt;
    skipPiercingStep: [&lt;br /&gt;
      !Boolean(100 - piercingHitPercentage),&lt;br /&gt;
      !Boolean(piercingHitPercentage),&lt;br /&gt;
    ],&lt;br /&gt;
    isPhysicalSkill: skillType === &amp;quot;physical&amp;quot; &amp;amp;&amp;amp; attacker.class !== &amp;quot;archery&amp;quot;,&lt;br /&gt;
    weaponBonusCoeff: 1,&lt;br /&gt;
    attackValueCoeff: 100 + attackValueMeleeMagic,&lt;br /&gt;
    attackValueMarriage: attackValueMarriage,&lt;br /&gt;
    monsterResistanceMarriageCoeff: 100 - monsterResistanceMarriage,&lt;br /&gt;
    monsterResistanceCoeff: 100 - monsterResistance,&lt;br /&gt;
    typeBonusCoeff: typeBonus,&lt;br /&gt;
    raceBonusCoeff: raceBonus,&lt;br /&gt;
    raceResistanceCoeff: raceResistance,&lt;br /&gt;
    stoneBonusCoeff: stoneBonus,&lt;br /&gt;
    monsterBonusCoeff: monsterBonus,&lt;br /&gt;
    elementBonusCoeff: elementBonus,&lt;br /&gt;
    damageMultiplier: damageMultiplier,&lt;br /&gt;
    useDamage: useDamage,&lt;br /&gt;
    defense: defense,&lt;br /&gt;
    defenseBoost: defenseBoost,&lt;br /&gt;
    defenseMarriage: defenseMarriage,&lt;br /&gt;
    tigerStrengthCoeff: 100 + tigerStrength,&lt;br /&gt;
    magicResistanceCoeff: magicResistanceToCoeff(magicResistance),&lt;br /&gt;
    weaponDefenseCoeff: 100 - weaponDefense,&lt;br /&gt;
    berserkBonusCoeff: 100 + berserkBonus,&lt;br /&gt;
    blessingBonusCoeff: 100 - blessingBonus,&lt;br /&gt;
    fearBonusCoeff: 100 - fearBonus,&lt;br /&gt;
    magicAttackValueCoeff: 100 + magicAttackValueMeleeMagic,&lt;br /&gt;
    extraPiercingHitCoeff: 5 * extraPiercingHitPercentage,&lt;br /&gt;
    averageDamageCoeff: 100 + averageDamage,&lt;br /&gt;
    averageDamageResistanceCoeff: 100 - Math.min(99, averageDamageResistance),&lt;br /&gt;
    skillDamageCoeff: 100 + skillDamage,&lt;br /&gt;
    skillDamageResistanceCoeff: 100 - Math.min(99, skillDamageResistance),&lt;br /&gt;
    useDarkProtection: useDarkProtection,&lt;br /&gt;
    darkProtectionPoint: darkProtectionPoint,&lt;br /&gt;
    darkProtectionSp: victim.darkProtectionSp,&lt;br /&gt;
    rankBonusCoeff: 100 + rankBonus,&lt;br /&gt;
    resistance90PercentHp: resistance90PercentHp,&lt;br /&gt;
    defensePercent: Math.floor(defensePercent),&lt;br /&gt;
    damageBonusCoeff: Math.min(20, damageBonus),&lt;br /&gt;
    empireMalusCoeff: 10 - empireMalus,&lt;br /&gt;
    sungMaStrBonusCoeff: 10000 + sungMaStrBonus,&lt;br /&gt;
    sungmaStrMalusCoeff: sungmaStrMalus,&lt;br /&gt;
    whiteDragonElixirCoeff: 100 + whiteDragonElixir,&lt;br /&gt;
    steelDragonElixirCoeff: 100 - steelDragonElixir,&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  const damageTypeWeights = [&lt;br /&gt;
    (100 - criticalHitPercentage) *&lt;br /&gt;
      (100 - piercingHitPercentage) *&lt;br /&gt;
      (100 - missPercentage),&lt;br /&gt;
    criticalHitPercentage *&lt;br /&gt;
      (100 - piercingHitPercentage) *&lt;br /&gt;
      (100 - missPercentage),&lt;br /&gt;
    (100 - criticalHitPercentage) *&lt;br /&gt;
      piercingHitPercentage *&lt;br /&gt;
      (100 - missPercentage),&lt;br /&gt;
    criticalHitPercentage * piercingHitPercentage * (100 - missPercentage),&lt;br /&gt;
  ];&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    attacker: attacker,&lt;br /&gt;
    victim: victim,&lt;br /&gt;
    attackFactor: calcAttackFactor(attacker, victim),&lt;br /&gt;
    mainAttackValue: calcMainAttackValue(attacker),&lt;br /&gt;
    attackValues: calcAttackValues(attacker, isPlayerVsPlayer),&lt;br /&gt;
    bonusValues: bonusValues,&lt;br /&gt;
    damageTypeWeights: damageTypeWeights,&lt;br /&gt;
    attackTypeMapping: mapping.attackType,&lt;br /&gt;
    damageWeightedByType: {&lt;br /&gt;
      normalHit: {},&lt;br /&gt;
      criticalHit: {},&lt;br /&gt;
      piercingHit: {},&lt;br /&gt;
      criticalPiercingHit: {},&lt;br /&gt;
    },&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateBattleValues(battleValues, skillFormula, skillInfo) {&lt;br /&gt;
  var weaponBonus = skillInfo.adjust || 0;&lt;br /&gt;
  var skillWard = 0;&lt;br /&gt;
  var skillBonus = 0;&lt;br /&gt;
  var skillBonusByBonus = 0;&lt;br /&gt;
  var { attacker: attacker, bonusValues: bonusValues } = battleValues;&lt;br /&gt;
  var {&lt;br /&gt;
    range: [minVariation, maxVariation],&lt;br /&gt;
  } = skillInfo;&lt;br /&gt;
  var variationLength = maxVariation - minVariation + 1;&lt;br /&gt;
&lt;br /&gt;
  if (skillInfo.hasOwnProperty(&amp;quot;weaponBonus&amp;quot;)) {&lt;br /&gt;
    var [weaponType, weaponBonusValue] = skillInfo.weaponBonus;&lt;br /&gt;
&lt;br /&gt;
    if (weaponType === attacker.weapon.type) {&lt;br /&gt;
      weaponBonus += weaponBonusValue;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillInfo.skillBonus) {&lt;br /&gt;
    skillBonus = skillInfo.skillBonus;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillInfo.skillWard) {&lt;br /&gt;
    skillWard = skillInfo.skillWard;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillInfo.skillBonusByBonus) {&lt;br /&gt;
    skillBonusByBonus = skillInfo.skillBonusByBonus;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillInfo.removeWeaponReduction) {&lt;br /&gt;
    bonusValues.weaponDefenseCoeff = 100;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  bonusValues.weaponBonusCoeff = 100 + weaponBonus;&lt;br /&gt;
  bonusValues.skillWardCoeff = 1 - skillWard / 100;&lt;br /&gt;
  bonusValues.skillBonusCoeff = 1 + skillBonus / 100;&lt;br /&gt;
  bonusValues.skillBonusByBonusCoeff = 100 + skillBonusByBonus;&lt;br /&gt;
&lt;br /&gt;
  battleValues.skillFormula = skillFormula;&lt;br /&gt;
  battleValues.skillRange = skillInfo.range;&lt;br /&gt;
  battleValues.attackValues.totalCardinal *= variationLength;&lt;br /&gt;
  battleValues.attackValues.possibleDamageCount *= variationLength;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcWeights(minValue, maxValue, minInterval) {&lt;br /&gt;
  var firstWeightLimit = minValue + minInterval - 1;&lt;br /&gt;
  var lastWeightsLimit = maxValue - minInterval + 1;&lt;br /&gt;
  var weights = [];&lt;br /&gt;
&lt;br /&gt;
  for (var value = minValue; value &amp;lt; firstWeightLimit; value++) {&lt;br /&gt;
    weights.push(value - minValue + 1);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (var value = firstWeightLimit; value &amp;lt;= lastWeightsLimit; value++) {&lt;br /&gt;
    weights.push(minInterval);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (var value = lastWeightsLimit + 1; value &amp;lt;= maxValue; value++) {&lt;br /&gt;
    weights.push(maxValue - value + 1);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return weights;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcBerserkBonus(skillPowerTable, victim) {&lt;br /&gt;
  if (!isChecked(victim.useBerserk) || victim.class !== &amp;quot;body&amp;quot;) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  const skillPower = getSkillPower(victim.skillBerserk, skillPowerTable);&lt;br /&gt;
&lt;br /&gt;
  if (!skillPower) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  const berserkBonus = Math.floor(skillPower * 25);&lt;br /&gt;
&lt;br /&gt;
  return berserkBonus;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcBlessingBonus(skillPowerTable, victim) {&lt;br /&gt;
  if (!isChecked(victim.isBlessed)) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  const int = victim.intBlessing;&lt;br /&gt;
  const dex = victim.dexBlessing;&lt;br /&gt;
  const skillPower = getSkillPower(victim.skillBlessing, skillPowerTable);&lt;br /&gt;
&lt;br /&gt;
  if (!skillPower) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  let blessingBonus = floorMultiplication(&lt;br /&gt;
    ((int * 0.3 + 5) * (2 * skillPower + 0.5) + 0.3 * dex) / (skillPower + 2.3),&lt;br /&gt;
    1&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  if (victim.class === &amp;quot;dragon&amp;quot; &amp;amp;&amp;amp; isChecked(victim.blessingOnself)) {&lt;br /&gt;
    blessingBonus = floorMultiplication(blessingBonus, 1.1);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return blessingBonus;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcFearBonus(skillPowerTable, victim) {&lt;br /&gt;
  if (!isChecked(victim.useFear) || victim.class !== &amp;quot;weaponary&amp;quot;) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  const skillPower = getSkillPower(victim.skillFear, skillPowerTable);&lt;br /&gt;
&lt;br /&gt;
  if (!skillPower) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  const fearBonus = 5 + Math.floor(skillPower * 20);&lt;br /&gt;
&lt;br /&gt;
  return fearBonus;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcDarkProtectionPoint(skillPowerTable, victim) {&lt;br /&gt;
  const skillPower = getSkillPower(victim.skillDarkProtection, skillPowerTable);&lt;br /&gt;
&lt;br /&gt;
  return floorMultiplication(100 - victim.int * 0.84 * skillPower, 1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcStealthBonus(skillPowerTable, attacker) {&lt;br /&gt;
  if (!isChecked(attacker.useStealth)) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  const skillPower = getSkillPower(attacker.skillStealth, skillPowerTable);&lt;br /&gt;
&lt;br /&gt;
  if (!skillPower) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  const stealthBonus = skillPower * 50;&lt;br /&gt;
&lt;br /&gt;
  return stealthBonus;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSkillFormula(battle, skillId, battleValues, removeSkillVariation) {&lt;br /&gt;
  var { attacker, victim, attackFactor } = battleValues;&lt;br /&gt;
  var skillPowerTable = battle.constants.skillPowerTable;&lt;br /&gt;
&lt;br /&gt;
  var skillFormula;&lt;br /&gt;
  var skillInfo = { range: [0, 0] };&lt;br /&gt;
&lt;br /&gt;
  var { class: attackerClass, level: lv, vit, str, int, dex } = attacker;&lt;br /&gt;
&lt;br /&gt;
  if (skillId &amp;lt;= 9) {&lt;br /&gt;
    var skillPower = getSkillPower(&lt;br /&gt;
      attacker[&amp;quot;attackSkill&amp;quot; + skillId],&lt;br /&gt;
      skillPowerTable&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    var improvedBySkillBonus = false;&lt;br /&gt;
    var improvedByBonus = false;&lt;br /&gt;
&lt;br /&gt;
    if (attackerClass === &amp;quot;body&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Triple lacération&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.1 * atk + (0.5 * atk + 1.5 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Moulinet à l'épée&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              3 * atk + (0.8 * atk + 5 * str + 3 * dex + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Accélération&lt;br /&gt;
        case 5:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * atk + (atk + dex * 3 + str * 7 + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Volonté de vivre&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              (3 * atk + (atk + 1.5 * str) * skillPower) * 1.07,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          break;&lt;br /&gt;
        // Tremblement de terre&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              3 * atk +&lt;br /&gt;
                (0.9 * atk + variation + 5 * str + 3 * dex + lv) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;mental&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Attaque de l'esprit&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2.3 * atk + (4 * atk + 4 * str + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Attaque de la paume&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2.3 * atk + (3 * atk + 4 * str + 3 * vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Charge&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * atk + (2 * atk + 2 * dex + 2 * vit + 4 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          break;&lt;br /&gt;
        // Coup d'épée&lt;br /&gt;
        case 5:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * atk + (atk + 3 * dex + 5 * str + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Orbe de l'épée&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              (2 * atk + (2 * atk + 2 * dex + 2 * vit + 4 * str) * skillPower) *&lt;br /&gt;
                1.1,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          break;&lt;br /&gt;
        // Tremblement de terre&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              3 * atk +&lt;br /&gt;
                (0.9 * atk + variation + 5 * str + 3 * dex + lv) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;blade_fight&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Embuscade&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk + (1.2 * atk + variation + 4 * dex + 4 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [1, 50];&lt;br /&gt;
          skillInfo.range = [500, 700];&lt;br /&gt;
          skillInfo.adjust = calcStealthBonus(skillPowerTable, attacker);&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Attaque rapide&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk + (1.6 * atk + variation + 7 * dex + 7 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [1, 35];&lt;br /&gt;
          skillInfo.range = [200, 300];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Dague filante&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * atk + (0.5 * atk + 9 * dex + 7 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Brume empoisonnée&lt;br /&gt;
        case 5:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * lv + (atk + 3 * str + 18 * dex) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Poison insidieux&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              (2 * lv + (atk + 3 * str + 18 * dex) * skillPower) * 1.1,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          break;&lt;br /&gt;
        // Étoiles brillantes&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk + (1.7 * atk + variation + 6 * dex + 5 * lv) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;archery&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Tir à répétition&lt;br /&gt;
        // case 1:&lt;br /&gt;
        //   skillFormula = function (atk) {&lt;br /&gt;
        //     return floorMultiplication(&lt;br /&gt;
        //       atk + 0.2 * atk * Math.floor(2 + 6 * skillPower) + (0.8 * atk + 8 * dex * attackFactor + 2 * int) * skillPower,&lt;br /&gt;
        //       1&lt;br /&gt;
        //     );&lt;br /&gt;
        //   };&lt;br /&gt;
        //   improvedByBonus = true;&lt;br /&gt;
        //   break;&lt;br /&gt;
        // Pluie de flèches&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk + (1.7 * atk + 5 * dex + str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Flèche de feu&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.5 * atk + (2.6 * atk + 0.9 * int + variation) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [100, 300];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Foulée de plume&lt;br /&gt;
        case 4:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              (3 * dex + 200 + 2 * str + 2 * int) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.removeWeaponReduction = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Flèche empoisonnée&lt;br /&gt;
        case 5:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk +&lt;br /&gt;
                (1.4 * atk + variation + 7 * dex + 4 * str + 4 * int) *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [100, 200];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Coup étincelant&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              (atk +&lt;br /&gt;
                (1.2 * atk + variation + 6 * dex + 3 * str + 3 * int) *&lt;br /&gt;
                  skillPower) *&lt;br /&gt;
                1.2,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [100, 200];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Tir tempête&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.9 * atk + (2.6 * atk + variation) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;weaponary&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Toucher brûlant&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk +&lt;br /&gt;
                2 * lv +&lt;br /&gt;
                2 * int +&lt;br /&gt;
                (2 * atk + 4 * str + 14 * int) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Tourbillon du dragon&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.1 * atk +&lt;br /&gt;
                2 * lv +&lt;br /&gt;
                2 * int +&lt;br /&gt;
                (1.5 * atk + str + 12 * int) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Contre-sort&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              40 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                2 * int +&lt;br /&gt;
                (10 * int + 7 * mav + variation) * attackFactor * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [50, 100];&lt;br /&gt;
          break;&lt;br /&gt;
        // Coup démoniaque&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.9 * atk + (2.6 * atk + variation) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;black_magic&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Attaque des ténèbres&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              40 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                2 * int +&lt;br /&gt;
                (13 * int + 6 * mav + variation) * attackFactor * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [50, 100];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Attaque de flammes&lt;br /&gt;
        // case 2:&lt;br /&gt;
        //   skillFormula = function (mav, variation) {&lt;br /&gt;
        //     return floorMultiplication(&lt;br /&gt;
        //       5 * lv + 2 * int + (7 * int + 8 * mav + 4 * str + 2 * vit + variation) * skillPower,&lt;br /&gt;
        //       1&lt;br /&gt;
        //     );&lt;br /&gt;
        //   };&lt;br /&gt;
        //   skillInfo.range = [180, 100];&lt;br /&gt;
        //   improvedByBonus = true;&lt;br /&gt;
        //   break;&lt;br /&gt;
        // Esprit de flammes&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              30 +&lt;br /&gt;
                2 * lv +&lt;br /&gt;
                2 * int +&lt;br /&gt;
                (7 * int + 6 * mav + variation) * attackFactor * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [200, 500];&lt;br /&gt;
          break;&lt;br /&gt;
        // Frappe de l'esprit&lt;br /&gt;
        // case 5:&lt;br /&gt;
        //   skillFormula = function (mav, variation) {&lt;br /&gt;
        //     return floorMultiplication(&lt;br /&gt;
        //       40 + 2 * lv + 2 * int + (2 * vit + 2 * dex + 13 * int + 6 * mav + variation) * attackFactor * skillPower,&lt;br /&gt;
        //       1&lt;br /&gt;
        //     );&lt;br /&gt;
        //   };&lt;br /&gt;
        //   skillInfo.range = [180, 200];&lt;br /&gt;
        //   break;&lt;br /&gt;
        // Orbe des ténèbres&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (mav) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              120 +&lt;br /&gt;
                6 * lv +&lt;br /&gt;
                (5 * vit + 5 * dex + 29 * int + 9 * mav) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Vague mortelle&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              120 +&lt;br /&gt;
                6 * lv +&lt;br /&gt;
                (5 * vit + 5 * dex + 30 * int + variation + 9 * mav) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;dragon&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Talisman volant&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (mav) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              70 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                (18 * int + 7 * str + 5 * mav + 50) * attackFactor * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [4, 10];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Dragon chassant&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (mav) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              60 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                (16 * int + 6 * dex + 6 * mav + 120) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [4, 10];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Rugissement du dragon&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (mav) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              70 +&lt;br /&gt;
                3 * lv +&lt;br /&gt;
                (20 * int + 3 * str + 10 * mav + 100) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [4, 10];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Météore&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              120 +&lt;br /&gt;
                6 * lv +&lt;br /&gt;
                (5 * vit + 5 * dex + 30 * int + variation + 9 * mav) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;heal&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Jet de foudre&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              60 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                (8 * int + 2 * dex + 8 * mav + variation) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [6, 10];&lt;br /&gt;
          skillInfo.range = [5 * int, 15 * int];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Invocation de foudre&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              40 +&lt;br /&gt;
                4 * lv +&lt;br /&gt;
                (13 * int + 2 * str + 10 * mav + variation) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [6, 10];&lt;br /&gt;
          skillInfo.range = [5 * int, 16 * int];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Griffe de foudre&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              50 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                (8 * int + 2 * str + 8 * mav + variation) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 800];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;lycan&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Déchiqueter&lt;br /&gt;
        // case 1:&lt;br /&gt;
        //   skillFormula = function (atk) {&lt;br /&gt;
        //     return floorMultiplication(&lt;br /&gt;
        //       1.1 * atk + (0.3 * atk + 1.5 * str) * skillPower,&lt;br /&gt;
        //       1&lt;br /&gt;
        //     );&lt;br /&gt;
        //   };&lt;br /&gt;
        //   skillInfo.weaponBonus = [5, 54];&lt;br /&gt;
        //   improvedByBonus = true;&lt;br /&gt;
        //   break;&lt;br /&gt;
        // Souffle de loup&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * atk + (atk + 3 * dex + 5 * str + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [5, 35];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Bond de loup&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk + (1.6 * atk + 200 + 7 * dex + 7 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [5, 35];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Griffe de loup&lt;br /&gt;
        case 4:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              3 * atk + (0.8 * atk + 6 * str + 2 * dex + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Tempête cinglante&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.8 * atk +&lt;br /&gt;
                (atk + 6 * dex + variation + 3 * str + lv) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
    if (improvedBySkillBonus) {&lt;br /&gt;
      skillInfo.skillBonus =&lt;br /&gt;
        16 * getSkillPower(attacker.skillBonus, skillPowerTable);&lt;br /&gt;
&lt;br /&gt;
      var skillWardChoice = victim.skillWardChoice;&lt;br /&gt;
&lt;br /&gt;
      if (skillWardChoice &amp;amp;&amp;amp; skillWardChoice === attackerClass) {&lt;br /&gt;
        skillInfo.skillWard =&lt;br /&gt;
          24 * getSkillPower(victim.skillWard, skillPowerTable);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (improvedByBonus) {&lt;br /&gt;
      skillInfo.skillBonusByBonus = attacker[&amp;quot;skillBonus&amp;quot; + skillId];&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (removeSkillVariation) {&lt;br /&gt;
      var averageVariation = (skillInfo.range[0] + skillInfo.range[0]) / 2;&lt;br /&gt;
      skillInfo.range = [averageVariation, averageVariation];&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    var skillPower = getSkillPower(&lt;br /&gt;
      attacker[&amp;quot;horseSkill&amp;quot; + skillId],&lt;br /&gt;
      skillPowerTable&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    switch (skillId) {&lt;br /&gt;
      // Combat équestre&lt;br /&gt;
      case 137:&lt;br /&gt;
        skillFormula = function (atk) {&lt;br /&gt;
          return floorMultiplication(atk + 2 * atk * skillPower, 1);&lt;br /&gt;
        };&lt;br /&gt;
        break;&lt;br /&gt;
      // Charge à cheval&lt;br /&gt;
      case 138:&lt;br /&gt;
        skillFormula = function (atk) {&lt;br /&gt;
          return floorMultiplication(&lt;br /&gt;
            2.4 * (200 + 1.5 * lv) + 600 * skillPower,&lt;br /&gt;
            1&lt;br /&gt;
          );&lt;br /&gt;
        };&lt;br /&gt;
        break;&lt;br /&gt;
      // Vague de Pouvoir&lt;br /&gt;
      case 139:&lt;br /&gt;
        skillFormula = function (atk) {&lt;br /&gt;
          return floorMultiplication(&lt;br /&gt;
            2 * (200 + 1.5 * lv) + 600 * skillPower,&lt;br /&gt;
            1&lt;br /&gt;
          );&lt;br /&gt;
        };&lt;br /&gt;
        break;&lt;br /&gt;
      // Grêle de flèches&lt;br /&gt;
      case 140:&lt;br /&gt;
        skillFormula = function (atk) {&lt;br /&gt;
          return floorMultiplication(atk + 2 * atk * skillPower, 1);&lt;br /&gt;
        };&lt;br /&gt;
        break;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  updateBattleValues(battleValues, skillFormula, skillInfo);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcMagicAttackValueAugmentation(&lt;br /&gt;
  magicAttackValueWeapon,&lt;br /&gt;
  magicAttackValueBonus&lt;br /&gt;
) {&lt;br /&gt;
  if (magicAttackValueBonus) {&lt;br /&gt;
    return Math.max(&lt;br /&gt;
      1,&lt;br /&gt;
      0.0025056 *&lt;br /&gt;
        magicAttackValueBonus ** 0.602338 *&lt;br /&gt;
        magicAttackValueWeapon ** 1.20476&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
  return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getMagicAttackValueAugmentation(&lt;br /&gt;
  minMagicAttackValue,&lt;br /&gt;
  maxMagicAttackValue,&lt;br /&gt;
  magicAttackValueBonus&lt;br /&gt;
) {&lt;br /&gt;
  var magicAttackValueAugmentation = [];&lt;br /&gt;
&lt;br /&gt;
  for (&lt;br /&gt;
    var magicAttackValue = minMagicAttackValue;&lt;br /&gt;
    magicAttackValue &amp;lt;= maxMagicAttackValue;&lt;br /&gt;
    magicAttackValue++&lt;br /&gt;
  ) {&lt;br /&gt;
    magicAttackValueAugmentation.push(&lt;br /&gt;
      calcMagicAttackValueAugmentation(magicAttackValue, magicAttackValueBonus)&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return magicAttackValueAugmentation;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcPhysicalDamage(battleValues) {&lt;br /&gt;
  const {&lt;br /&gt;
    attackFactor,&lt;br /&gt;
    mainAttackValue,&lt;br /&gt;
    attackValues: {&lt;br /&gt;
      minAttackValue,&lt;br /&gt;
      maxAttackValue,&lt;br /&gt;
      attackValueOther,&lt;br /&gt;
      weights,&lt;br /&gt;
      criticalAttackRange,&lt;br /&gt;
    },&lt;br /&gt;
    bonusValues,&lt;br /&gt;
    damageWeightedByType,&lt;br /&gt;
  } = battleValues;&lt;br /&gt;
&lt;br /&gt;
  const savedDamage = {};&lt;br /&gt;
&lt;br /&gt;
  if (bonusValues.missPercentage) {&lt;br /&gt;
    damageWeightedByType.miss = bonusValues.missPercentage / 100;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (&lt;br /&gt;
    let attackValue = minAttackValue;&lt;br /&gt;
    attackValue &amp;lt;= maxAttackValue;&lt;br /&gt;
    attackValue++&lt;br /&gt;
  ) {&lt;br /&gt;
    const weight = weights[attackValue - minAttackValue];&lt;br /&gt;
    const damageByType = [[], [], [], []];&lt;br /&gt;
    const currentDamageInfo = [weight, damageByType];&lt;br /&gt;
&lt;br /&gt;
    const secondaryAttackValue = 2 * attackValue + attackValueOther;&lt;br /&gt;
    const rawDamage =&lt;br /&gt;
      mainAttackValue + floorMultiplication(attackFactor, secondaryAttackValue);&lt;br /&gt;
&lt;br /&gt;
    const damageWithPrimaryBonuses = calcDamageWithPrimaryBonuses(&lt;br /&gt;
      rawDamage,&lt;br /&gt;
      bonusValues&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    const damageAfterDefense =&lt;br /&gt;
      damageWithPrimaryBonuses -&lt;br /&gt;
      bonusValues.defenseBoost -&lt;br /&gt;
      bonusValues.defenseMarriage;&lt;br /&gt;
&lt;br /&gt;
    const damageValues =&lt;br /&gt;
      damageAfterDefense &amp;lt;= 2 ? [1, 2, 3, 4, 5] : [damageAfterDefense];&lt;br /&gt;
&lt;br /&gt;
    for (const damage of damageValues) {&lt;br /&gt;
      saveFinalDamage(&lt;br /&gt;
        damage,&lt;br /&gt;
        damageWithPrimaryBonuses,&lt;br /&gt;
        bonusValues,&lt;br /&gt;
        criticalAttackRange,&lt;br /&gt;
        damageByType&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    savedDamage[attackValue] = currentDamageInfo;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  processSavedDamage(savedDamage, damageWeightedByType, battleValues);&lt;br /&gt;
&lt;br /&gt;
  return damageWeightedByType;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcPhysicalSkillDamage(battleValues) {&lt;br /&gt;
  const {&lt;br /&gt;
    attackFactor,&lt;br /&gt;
    mainAttackValue,&lt;br /&gt;
    attackValues: {&lt;br /&gt;
      minAttackValue,&lt;br /&gt;
      maxAttackValue,&lt;br /&gt;
      attackValueOther,&lt;br /&gt;
      weights,&lt;br /&gt;
      criticalAttackRange,&lt;br /&gt;
    },&lt;br /&gt;
    bonusValues,&lt;br /&gt;
    damageWeightedByType,&lt;br /&gt;
    skillFormula,&lt;br /&gt;
    skillRange: [minVariation, maxVariation],&lt;br /&gt;
  } = battleValues;&lt;br /&gt;
&lt;br /&gt;
  const savedDamage = {};&lt;br /&gt;
&lt;br /&gt;
  for (&lt;br /&gt;
    let attackValue = minAttackValue;&lt;br /&gt;
    attackValue &amp;lt;= maxAttackValue;&lt;br /&gt;
    attackValue++&lt;br /&gt;
  ) {&lt;br /&gt;
    const weight = weights[attackValue - minAttackValue];&lt;br /&gt;
&lt;br /&gt;
    const secondaryAttackValue = 2 * attackValue + attackValueOther;&lt;br /&gt;
    const rawDamage =&lt;br /&gt;
      mainAttackValue + floorMultiplication(attackFactor, secondaryAttackValue);&lt;br /&gt;
&lt;br /&gt;
    const damageWithPrimaryBonuses = calcDamageWithPrimaryBonuses(&lt;br /&gt;
      rawDamage,&lt;br /&gt;
      bonusValues&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    const damageValues =&lt;br /&gt;
      damageWithPrimaryBonuses &amp;lt;= 2&lt;br /&gt;
        ? [1, 2, 3, 4, 5]&lt;br /&gt;
        : [damageWithPrimaryBonuses];&lt;br /&gt;
    const weightByDamage = weight / damageValues.length;&lt;br /&gt;
&lt;br /&gt;
    for (let variation = minVariation; variation &amp;lt;= maxVariation; variation++) {&lt;br /&gt;
      for (const damage of damageValues) {&lt;br /&gt;
        const damageWithFormula = skillFormula(&lt;br /&gt;
          damage * bonusValues.useDamage,&lt;br /&gt;
          variation&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        let damageKey = damageWithFormula;&lt;br /&gt;
&lt;br /&gt;
        if (damageWithPrimaryBonuses &amp;lt; bonusValues.defenseBoost) {&lt;br /&gt;
          damageKey = `${damageWithFormula}_${damageWithPrimaryBonuses}`;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        const entry = savedDamage[damageKey];&lt;br /&gt;
&lt;br /&gt;
        if (entry) {&lt;br /&gt;
          entry[0] += weightByDamage;&lt;br /&gt;
          continue;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        const damageByType = [[], [], [], []];&lt;br /&gt;
        const currentDamageInfo = [weightByDamage, damageByType];&lt;br /&gt;
&lt;br /&gt;
        const finalDamage = Math.floor(&lt;br /&gt;
          (damageWithFormula * bonusValues.weaponBonusCoeff) / 100&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        saveFinalSkillDamage(&lt;br /&gt;
          finalDamage,&lt;br /&gt;
          bonusValues,&lt;br /&gt;
          criticalAttackRange,&lt;br /&gt;
          damageByType&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        savedDamage[damageKey] = currentDamageInfo;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  processSavedDamage(savedDamage, damageWeightedByType, battleValues);&lt;br /&gt;
&lt;br /&gt;
  return damageWeightedByType;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcMagicSkillDamage(battleValues) {&lt;br /&gt;
  const {&lt;br /&gt;
    attackValues: {&lt;br /&gt;
      minMagicAttackValue,&lt;br /&gt;
      maxMagicAttackValue,&lt;br /&gt;
      magicAttackValueAugmentation,&lt;br /&gt;
      weights,&lt;br /&gt;
      criticalAttackRange,&lt;br /&gt;
    },&lt;br /&gt;
    bonusValues,&lt;br /&gt;
    damageWeightedByType,&lt;br /&gt;
    skillFormula,&lt;br /&gt;
    skillRange: [minVariation, maxVariation],&lt;br /&gt;
  } = battleValues;&lt;br /&gt;
&lt;br /&gt;
  const savedDamage = {};&lt;br /&gt;
&lt;br /&gt;
  for (&lt;br /&gt;
    let magicAttackValue = minMagicAttackValue;&lt;br /&gt;
    magicAttackValue &amp;lt;= maxMagicAttackValue;&lt;br /&gt;
    magicAttackValue++&lt;br /&gt;
  ) {&lt;br /&gt;
    const index = magicAttackValue - minMagicAttackValue;&lt;br /&gt;
    const weight = weights[index];&lt;br /&gt;
&lt;br /&gt;
    for (let variation = minVariation; variation &amp;lt;= maxVariation; variation++) {&lt;br /&gt;
      const rawDamage = skillFormula(&lt;br /&gt;
        magicAttackValue + magicAttackValueAugmentation[index],&lt;br /&gt;
        variation&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      const entry = savedDamage[rawDamage];&lt;br /&gt;
&lt;br /&gt;
      if (entry) {&lt;br /&gt;
        entry[0] += weight;&lt;br /&gt;
        continue;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      const damageByType = [[], [], [], []];&lt;br /&gt;
      const currentDamageInfo = [weight, damageByType];&lt;br /&gt;
&lt;br /&gt;
      let damageWithPrimaryBonuses = Math.floor(&lt;br /&gt;
        (rawDamage * bonusValues.weaponBonusCoeff) / 100&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      damageWithPrimaryBonuses = calcDamageWithPrimaryBonuses(&lt;br /&gt;
        damageWithPrimaryBonuses,&lt;br /&gt;
        bonusValues&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      const damageValues =&lt;br /&gt;
        damageWithPrimaryBonuses &amp;lt;= 2&lt;br /&gt;
          ? [1, 2, 3, 4, 5]&lt;br /&gt;
          : [damageWithPrimaryBonuses];&lt;br /&gt;
&lt;br /&gt;
      for (const damage of damageValues) {&lt;br /&gt;
        saveFinalSkillDamage(&lt;br /&gt;
          damage,&lt;br /&gt;
          bonusValues,&lt;br /&gt;
          criticalAttackRange,&lt;br /&gt;
          damageByType&lt;br /&gt;
        );&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      savedDamage[rawDamage] = currentDamageInfo;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  processSavedDamage(savedDamage, damageWeightedByType, battleValues);&lt;br /&gt;
&lt;br /&gt;
  return damageWeightedByType;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcDamage(&lt;br /&gt;
  attacker,&lt;br /&gt;
  victim,&lt;br /&gt;
  attackType,&lt;br /&gt;
  battle,&lt;br /&gt;
  removeSkillVariation&lt;br /&gt;
) {&lt;br /&gt;
  var damageCalculator, skillId, skillType;&lt;br /&gt;
&lt;br /&gt;
  if (attackType === &amp;quot;physical&amp;quot;) {&lt;br /&gt;
    damageCalculator = calcPhysicalDamage;&lt;br /&gt;
  } else if (attackType.startsWith(&amp;quot;attackSkill&amp;quot;)) {&lt;br /&gt;
    skillId = Number(attackType.split(&amp;quot;attackSkill&amp;quot;)[1]);&lt;br /&gt;
&lt;br /&gt;
    if (isMagicClass(attacker) || isDispell(attacker, skillId)) {&lt;br /&gt;
      skillType = &amp;quot;magic&amp;quot;;&lt;br /&gt;
      damageCalculator = calcMagicSkillDamage;&lt;br /&gt;
    } else {&lt;br /&gt;
      skillType = &amp;quot;physical&amp;quot;;&lt;br /&gt;
      damageCalculator = calcPhysicalSkillDamage;&lt;br /&gt;
    }&lt;br /&gt;
  } else if (attackType.startsWith(&amp;quot;horseSkill&amp;quot;)) {&lt;br /&gt;
    skillType = &amp;quot;physical&amp;quot;;&lt;br /&gt;
    skillId = Number(attackType.split(&amp;quot;horseSkill&amp;quot;)[1]);&lt;br /&gt;
    damageCalculator = calcPhysicalSkillDamage;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var battleValues = createBattleValues(attacker, victim, battle, skillType);&lt;br /&gt;
&lt;br /&gt;
  if (skillId) {&lt;br /&gt;
    getSkillFormula(battle, skillId, battleValues, removeSkillVariation);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    damageWeightedByType: damageCalculator(battleValues),&lt;br /&gt;
    attackValues: battleValues.attackValues,&lt;br /&gt;
    skillType: skillType,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function damageWithoutVariation(&lt;br /&gt;
  attacker,&lt;br /&gt;
  victim,&lt;br /&gt;
  attackType,&lt;br /&gt;
  battle,&lt;br /&gt;
  characters&lt;br /&gt;
) {&lt;br /&gt;
  var startDamageTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
  var { damageWeightedByType, attackValues, skillType } = calcDamage(&lt;br /&gt;
    attacker,&lt;br /&gt;
    victim,&lt;br /&gt;
    attackType,&lt;br /&gt;
    battle&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  var endDamageTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
  displayResults(&lt;br /&gt;
    attackValues,&lt;br /&gt;
    damageWeightedByType,&lt;br /&gt;
    battle,&lt;br /&gt;
    attacker.name,&lt;br /&gt;
    victim.name&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  var endDisplayTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
  displayFightInfo(&lt;br /&gt;
    attackValues.possibleDamageCount,&lt;br /&gt;
    endDamageTime - startDamageTime,&lt;br /&gt;
    endDisplayTime - endDamageTime,&lt;br /&gt;
    battle&lt;br /&gt;
  );&lt;br /&gt;
  addPotentialErrorInformation(&lt;br /&gt;
    battle.errorInformation,&lt;br /&gt;
    attacker,&lt;br /&gt;
    victim,&lt;br /&gt;
    skillType,&lt;br /&gt;
    characters&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  hideElement(battle.bonusVariationResultContainer);&lt;br /&gt;
  showElement(battle.fightResultTitle);&lt;br /&gt;
  showElement(battle.fightResultContainer);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function damageWithVariation(&lt;br /&gt;
  attacker,&lt;br /&gt;
  victim,&lt;br /&gt;
  attackType,&lt;br /&gt;
  battle,&lt;br /&gt;
  entity,&lt;br /&gt;
  entityVariation&lt;br /&gt;
) {&lt;br /&gt;
  var startTime = performance.now();&lt;br /&gt;
  var damageByBonus = [];&lt;br /&gt;
  var augmentationByBonus = [];&lt;br /&gt;
  var {&lt;br /&gt;
    bonusVariationMinValue: minVariation,&lt;br /&gt;
    bonusVariationMaxValue: maxVariation,&lt;br /&gt;
  } = entity;&lt;br /&gt;
  var step = Math.ceil((maxVariation - minVariation + 1) / 500);&lt;br /&gt;
  var simulationCount = 0;&lt;br /&gt;
  var simulationTime;&lt;br /&gt;
  var firstDamage = 1;&lt;br /&gt;
&lt;br /&gt;
  for (&lt;br /&gt;
    var bonusValue = minVariation;&lt;br /&gt;
    bonusValue &amp;lt;= maxVariation;&lt;br /&gt;
    bonusValue += step&lt;br /&gt;
  ) {&lt;br /&gt;
    entity[entityVariation] = bonusValue;&lt;br /&gt;
&lt;br /&gt;
    var {&lt;br /&gt;
      damageWeightedByType,&lt;br /&gt;
      attackValues: { totalCardinal },&lt;br /&gt;
    } = calcDamage(&lt;br /&gt;
      copyObject(attacker),&lt;br /&gt;
      copyObject(victim),&lt;br /&gt;
      attackType,&lt;br /&gt;
      battle,&lt;br /&gt;
      true&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    var meanDamage = calcMeanDamage(damageWeightedByType, totalCardinal);&lt;br /&gt;
&lt;br /&gt;
    if (bonusValue === minVariation) {&lt;br /&gt;
      firstDamage = Math.max(meanDamage, 1e-3);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    damageByBonus.push({ x: bonusValue, y: meanDamage });&lt;br /&gt;
    augmentationByBonus.push({&lt;br /&gt;
      x: bonusValue,&lt;br /&gt;
      y: meanDamage / firstDamage - 1,&lt;br /&gt;
    });&lt;br /&gt;
    simulationCount++;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var endTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
  battle.damageByBonus = damageByBonus.concat(entityVariation);&lt;br /&gt;
&lt;br /&gt;
  addToBonusVariationChart(&lt;br /&gt;
    damageByBonus,&lt;br /&gt;
    augmentationByBonus,&lt;br /&gt;
    entity.bonusVariationName,&lt;br /&gt;
    battle.bonusVariationChart&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  simulationCount = battle.numberFormats.default.format(simulationCount);&lt;br /&gt;
  simulationTime = battle.numberFormats.second.format(&lt;br /&gt;
    (endTime - startTime) / 1000&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  battle.simulationCounter.textContent = simulationCount;&lt;br /&gt;
  battle.simulationTime.textContent = simulationTime;&lt;br /&gt;
&lt;br /&gt;
  hideElement(battle.fightResultContainer);&lt;br /&gt;
  showElement(battle.fightResultTitle);&lt;br /&gt;
  showElement(battle.bonusVariationResultContainer);&lt;br /&gt;
&lt;br /&gt;
  if (&lt;br /&gt;
    isChecked(attacker.useBonusVariation) &amp;amp;&amp;amp;&lt;br /&gt;
    isChecked(victim.useBonusVariation)&lt;br /&gt;
  ) {&lt;br /&gt;
    showElement(battle.errorInformation[&amp;quot;attacker-victim-variation&amp;quot;]);&lt;br /&gt;
  } else {&lt;br /&gt;
    hideElement(battle.errorInformation[&amp;quot;attacker-victim-variation&amp;quot;]);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function changeMonsterValues(monster, instance, attacker) {&lt;br /&gt;
  switch (instance) {&lt;br /&gt;
    case &amp;quot;SungMahiTower&amp;quot;:&lt;br /&gt;
      var sungMahiFloor = 1;&lt;br /&gt;
      var sungMahiStep = 1;&lt;br /&gt;
      var rawDefense = 120;&lt;br /&gt;
&lt;br /&gt;
      if (isPC(attacker)) {&lt;br /&gt;
        sungMahiFloor = attacker.sungMahiFloor;&lt;br /&gt;
        sungMahiStep = attacker.sungMahiStep;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (monster.rank === 5) {&lt;br /&gt;
        monster.level = 121;&lt;br /&gt;
        monster.dex = 75;&lt;br /&gt;
        rawDefense += 1;&lt;br /&gt;
      } else if (monster.rank === 6) {&lt;br /&gt;
        monster.level = 123;&lt;br /&gt;
        monster.dex = 75;&lt;br /&gt;
        rawDefense += 1;&lt;br /&gt;
      } else {&lt;br /&gt;
        monster.level = 120;&lt;br /&gt;
        monster.dex = 68;&lt;br /&gt;
      }&lt;br /&gt;
      monster.vit = 100;&lt;br /&gt;
      monster.rawDefense = rawDefense + (sungMahiStep - 1) * 6;&lt;br /&gt;
      monster.fistDefense = 0;&lt;br /&gt;
      monster.swordDefense = 0;&lt;br /&gt;
      monster.twoHandedSwordDefense = 0;&lt;br /&gt;
      monster.daggerDefense = 0;&lt;br /&gt;
      monster.bellDefense = 0;&lt;br /&gt;
      monster.fanDefense = 0;&lt;br /&gt;
      monster.arrowDefense = 0;&lt;br /&gt;
      monster.clawDefense = 0;&lt;br /&gt;
      monster.magicResistance = 0;&lt;br /&gt;
      monster.fireResistance = -20;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  switch (monster.vnum) {&lt;br /&gt;
    // Alastor&lt;br /&gt;
    case 6790:&lt;br /&gt;
      monster.iceResistance = 0;&lt;br /&gt;
      monster.iceBonus = 0;&lt;br /&gt;
      monster.lightningResistance = -10;&lt;br /&gt;
      monster.lightningBonus = 65;&lt;br /&gt;
      break;&lt;br /&gt;
&lt;br /&gt;
    // Zodiac boss&lt;br /&gt;
    case 2852:&lt;br /&gt;
    case 2862:&lt;br /&gt;
    case 2872:&lt;br /&gt;
    case 2882:&lt;br /&gt;
    case 2892:&lt;br /&gt;
    case 2902:&lt;br /&gt;
    case 2912:&lt;br /&gt;
    case 2922:&lt;br /&gt;
    case 2932:&lt;br /&gt;
    case 2942:&lt;br /&gt;
    case 2952:&lt;br /&gt;
    case 2962:&lt;br /&gt;
      monster.level = 136;&lt;br /&gt;
      monster.vit = 200;&lt;br /&gt;
      monster.rawDefense = 5000;&lt;br /&gt;
      break;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createWeapon(vnum) {&lt;br /&gt;
  var weapon = copyObject(weaponData[vnum]);&lt;br /&gt;
  var serpentVnums = [360, 380, 1210, 2230, 3250, 5200, 6150, 7330];&lt;br /&gt;
  var weaponValues = weapon[1];&lt;br /&gt;
  var isSerpent = isValueInArray(Number(vnum), serpentVnums);&lt;br /&gt;
  var isSpecial = Array.isArray(weaponValues[0]);&lt;br /&gt;
  var isMagic;&lt;br /&gt;
&lt;br /&gt;
  if (isSpecial) {&lt;br /&gt;
    isMagic = weaponValues[0][1] &amp;gt; 0;&lt;br /&gt;
  } else {&lt;br /&gt;
    isMagic = weaponValues[1] &amp;gt; 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    type: weapon[0],&lt;br /&gt;
    maxUpgrade: weapon[2].length - 1,&lt;br /&gt;
    isSerpent: isSerpent,&lt;br /&gt;
    isMagic: isMagic,&lt;br /&gt;
    getValues: function (upgrade) {&lt;br /&gt;
      var currentWeaponValues = weaponValues;&lt;br /&gt;
&lt;br /&gt;
      if (upgrade === undefined) {&lt;br /&gt;
        // rare bug when weaponUpgrade is deleted&lt;br /&gt;
        console.warn(&amp;quot;WeaponUpgrade is missing.&amp;quot;);&lt;br /&gt;
        upgrade = this.maxUpgrade;&lt;br /&gt;
      }&lt;br /&gt;
      upgrade = Math.min(upgrade, this.maxUpgrade);&lt;br /&gt;
&lt;br /&gt;
      if (isSpecial) {&lt;br /&gt;
        currentWeaponValues = weaponValues[upgrade];&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      this.minAttackValue = currentWeaponValues[2];&lt;br /&gt;
      this.maxAttackValue = currentWeaponValues[3];&lt;br /&gt;
      this.minMagicAttackValue = currentWeaponValues[0];&lt;br /&gt;
      this.maxMagicAttackValue = currentWeaponValues[1];&lt;br /&gt;
      this.growth = weapon[2][upgrade];&lt;br /&gt;
    },&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createMonster(&lt;br /&gt;
  monsterVnum,&lt;br /&gt;
  translateMonster,&lt;br /&gt;
  attacker,&lt;br /&gt;
  polymorphMonster&lt;br /&gt;
) {&lt;br /&gt;
  var monsterAttributes = monsterData[monsterVnum];&lt;br /&gt;
&lt;br /&gt;
  var monster = {&lt;br /&gt;
    vnum: Number(monsterVnum),&lt;br /&gt;
    name: translateMonster&lt;br /&gt;
      ? getTranslatedMonsterName(monsterVnum)&lt;br /&gt;
      : monsterAttributes[36],&lt;br /&gt;
    rank: monsterAttributes[0],&lt;br /&gt;
    race: monsterAttributes[1],&lt;br /&gt;
    attack: monsterAttributes[2],&lt;br /&gt;
    level: monsterAttributes[3],&lt;br /&gt;
    type: monsterAttributes[4],&lt;br /&gt;
    str: monsterAttributes[5],&lt;br /&gt;
    dex: monsterAttributes[6],&lt;br /&gt;
    vit: monsterAttributes[7],&lt;br /&gt;
    int: monsterAttributes[8],&lt;br /&gt;
    minAttackValue: monsterAttributes[9],&lt;br /&gt;
    maxAttackValue: monsterAttributes[10],&lt;br /&gt;
    rawDefense: monsterAttributes[11],&lt;br /&gt;
    criticalHit: monsterAttributes[12],&lt;br /&gt;
    piercingHit: monsterAttributes[13],&lt;br /&gt;
    fistDefense: monsterAttributes[14],&lt;br /&gt;
    swordDefense: monsterAttributes[15],&lt;br /&gt;
    twoHandedSwordDefense: monsterAttributes[16],&lt;br /&gt;
    daggerDefense: monsterAttributes[17],&lt;br /&gt;
    bellDefense: monsterAttributes[18],&lt;br /&gt;
    fanDefense: monsterAttributes[19],&lt;br /&gt;
    arrowDefense: monsterAttributes[20],&lt;br /&gt;
    clawDefense: monsterAttributes[21],&lt;br /&gt;
    fireResistance: monsterAttributes[22],&lt;br /&gt;
    lightningResistance: monsterAttributes[23],&lt;br /&gt;
    magicResistance: monsterAttributes[24],&lt;br /&gt;
    windResistance: monsterAttributes[25],&lt;br /&gt;
    lightningBonus: monsterAttributes[26],&lt;br /&gt;
    fireBonus: monsterAttributes[27],&lt;br /&gt;
    iceBonus: monsterAttributes[28],&lt;br /&gt;
    windBonus: monsterAttributes[29],&lt;br /&gt;
    earthBonus: monsterAttributes[30],&lt;br /&gt;
    darknessBonus: monsterAttributes[31],&lt;br /&gt;
    darknessResistance: monsterAttributes[32],&lt;br /&gt;
    iceResistance: monsterAttributes[33],&lt;br /&gt;
    earthResistance: monsterAttributes[34],&lt;br /&gt;
    damageMultiplier: monsterAttributes[35],&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  // monster.instance = 0;&lt;br /&gt;
&lt;br /&gt;
  // if (attacker &amp;amp;&amp;amp; monster.instance === 0) {&lt;br /&gt;
  //   changeMonsterValues(monster, &amp;quot;SungMahiTower&amp;quot;, attacker);&lt;br /&gt;
  // }&lt;br /&gt;
  if (!polymorphMonster) {&lt;br /&gt;
    changeMonsterValues(monster);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  monster.defense = monster.rawDefense + monster.level + monster.vit;&lt;br /&gt;
&lt;br /&gt;
  return monster;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addPotentialErrorInformation(&lt;br /&gt;
  errorInformation,&lt;br /&gt;
  attacker,&lt;br /&gt;
  victim,&lt;br /&gt;
  skillType,&lt;br /&gt;
  characters&lt;br /&gt;
) {&lt;br /&gt;
  for (var error of Object.values(errorInformation)) {&lt;br /&gt;
    hideElement(error);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker)) {&lt;br /&gt;
    if (isRiding(attacker)) {&lt;br /&gt;
      if (attacker.horsePoint === 0) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;horse-level&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
      showElement(errorInformation[&amp;quot;horse-stat&amp;quot;]);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isPolymorph(attacker)) {&lt;br /&gt;
      if (attacker.polymorphPoint === 0) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;polymorph-level&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (&lt;br /&gt;
        (attacker.polymorphPoint &amp;lt;= 39 &amp;amp;&amp;amp; attacker.attackValuePercent &amp;lt;= 199) ||&lt;br /&gt;
        (attacker.polymorphPoint === 40 &amp;amp;&amp;amp; attacker.attackValuePercent &amp;lt;= 299)&lt;br /&gt;
      ) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;polymorph-bonus&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
    if (skillType === &amp;quot;magic&amp;quot; &amp;amp;&amp;amp; !isDispell(attacker, 6)) {&lt;br /&gt;
      if (attacker.magicAttackValue) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;magic-attack-value-bonus&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
      if (victim.magicResistance) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;magic-resistance&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
      if (victim.magicResistance &amp;gt; 0 &amp;amp;&amp;amp; attacker.magicPenetration) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;magic-penetration&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    showElement(errorInformation[&amp;quot;monster-attacker&amp;quot;]);&lt;br /&gt;
    if (isMagicAttacker(attacker) &amp;amp;&amp;amp; victim.magicResistance) {&lt;br /&gt;
      showElement(errorInformation[&amp;quot;magic-resistance&amp;quot;]);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (isPC(victim)) {&lt;br /&gt;
    if (isRiding(victim)) {&lt;br /&gt;
      showElement(errorInformation[&amp;quot;horse-stat&amp;quot;]);&lt;br /&gt;
    }&lt;br /&gt;
    if (isPolymorph(victim)) {&lt;br /&gt;
      if (attacker.polymorphPoint === 0) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;polymorph-level&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
      showElement(errorInformation[&amp;quot;polymorph-defense&amp;quot;]);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (characters.unsavedChanges) {&lt;br /&gt;
    showElement(errorInformation[&amp;quot;save&amp;quot;]);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function reduceChartPointsListener(battle) {&lt;br /&gt;
  var {&lt;br /&gt;
    reduceChartPointsContainer,&lt;br /&gt;
    reduceChartPoints,&lt;br /&gt;
    numberFormats: { second: numberFormat },&lt;br /&gt;
    displayTime,&lt;br /&gt;
  } = battle;&lt;br /&gt;
&lt;br /&gt;
  reduceChartPoints.addEventListener(&amp;quot;change&amp;quot;, function () {&lt;br /&gt;
    reduceChartPoints.disabled = true;&lt;br /&gt;
&lt;br /&gt;
    var startDisplayTime = performance.now();&lt;br /&gt;
    var scatterDataByType = battle.scatterDataByType;&lt;br /&gt;
    var {&lt;br /&gt;
      chart,&lt;br /&gt;
      maxPoints,&lt;br /&gt;
      chart: {&lt;br /&gt;
        data: { datasets },&lt;br /&gt;
      },&lt;br /&gt;
    } = battle.damageChart;&lt;br /&gt;
    var addAnimations = false;&lt;br /&gt;
&lt;br /&gt;
    for (var index = 0; index &amp;lt; datasets.length; index++) {&lt;br /&gt;
      var dataset = datasets[index];&lt;br /&gt;
      var scatterData = scatterDataByType[dataset.name];&lt;br /&gt;
&lt;br /&gt;
      if (dataset.canBeReduced &amp;amp;&amp;amp; reduceChartPoints.checked) {&lt;br /&gt;
        dataset.data = aggregateDamage(scatterData, maxPoints);&lt;br /&gt;
        addAnimations = true;&lt;br /&gt;
      } else {&lt;br /&gt;
        dataset.data = scatterData;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    handleChartAnimations(chart, addAnimations);&lt;br /&gt;
    chart.update();&lt;br /&gt;
&lt;br /&gt;
    displayTime.textContent = numberFormat.format(&lt;br /&gt;
      (performance.now() - startDisplayTime) / 1000&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    setTimeout(function () {&lt;br /&gt;
      reduceChartPoints.disabled = false;&lt;br /&gt;
    }, 1000);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  reduceChartPointsContainer.addEventListener(&amp;quot;pointerup&amp;quot;, function (event) {&lt;br /&gt;
    if (event.pointerType === &amp;quot;mouse&amp;quot;) {&lt;br /&gt;
      if (event.target.closest(&amp;quot;label&amp;quot;)) {&lt;br /&gt;
        return;&lt;br /&gt;
      }&lt;br /&gt;
      reduceChartPoints.click();&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function downloadRawDataListener(battle) {&lt;br /&gt;
  var { downLoadRawData, downLoadRawDataVariation } = battle;&lt;br /&gt;
  var fileType = &amp;quot;text/csv;charset=utf-8;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  downLoadRawData.addEventListener(&amp;quot;click&amp;quot;, function () {&lt;br /&gt;
    var damageWeightedByType = battle.damageWeightedByType;&lt;br /&gt;
    var filename = &amp;quot;raw_damage.csv&amp;quot;;&lt;br /&gt;
    var csvContent = &amp;quot;damage,probabilities,damageType\n&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    for (var damageType in damageWeightedByType) {&lt;br /&gt;
      var damageWeighted = damageWeightedByType[damageType];&lt;br /&gt;
&lt;br /&gt;
      for (var damage in damageWeighted) {&lt;br /&gt;
        csvContent +=&lt;br /&gt;
          damage + &amp;quot;,&amp;quot; + damageWeighted[damage] + &amp;quot;,&amp;quot; + damageType + &amp;quot;\n&amp;quot;;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    downloadData(csvContent, fileType, filename);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  downLoadRawDataVariation.addEventListener(&amp;quot;click&amp;quot;, function () {&lt;br /&gt;
    var damageByBonus = battle.damageByBonus;&lt;br /&gt;
    var damageByBonusLength = damageByBonus.length;&lt;br /&gt;
    var filename = &amp;quot;damage_variation.csv&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    if (!damageByBonusLength) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var csvContent =&lt;br /&gt;
      damageByBonus[damageByBonusLength - 1] + &amp;quot;,averageDamage\n&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    for (var index = 0; index &amp;lt; damageByBonusLength - 1; index++) {&lt;br /&gt;
      var row = damageByBonus[index];&lt;br /&gt;
&lt;br /&gt;
      csvContent += row.x + &amp;quot;,&amp;quot; + row.y + &amp;quot;\n&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    downloadData(csvContent, fileType, filename);&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function displayResults(&lt;br /&gt;
  attackValues,&lt;br /&gt;
  damageWeightedByType,&lt;br /&gt;
  battle,&lt;br /&gt;
  attackerName,&lt;br /&gt;
  victimName&lt;br /&gt;
) {&lt;br /&gt;
  var [meanDamage, minDamage, maxDamage, scatterDataByType, uniqueDamageCount] =&lt;br /&gt;
    prepareDamageData(damageWeightedByType, attackValues);&lt;br /&gt;
&lt;br /&gt;
  addToDamageChart(battle, scatterDataByType);&lt;br /&gt;
  updateDamageChartDescription(battle, uniqueDamageCount);&lt;br /&gt;
  displayFightResults(&lt;br /&gt;
    battle,&lt;br /&gt;
    attackerName,&lt;br /&gt;
    victimName,&lt;br /&gt;
    meanDamage,&lt;br /&gt;
    minDamage,&lt;br /&gt;
    maxDamage&lt;br /&gt;
  );&lt;br /&gt;
  battle.damageWeightedByType = damageWeightedByType;&lt;br /&gt;
  battle.scatterDataByType = scatterDataByType;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function displayFightResults(&lt;br /&gt;
  battle,&lt;br /&gt;
  attackerName,&lt;br /&gt;
  victimName,&lt;br /&gt;
  meanDamage,&lt;br /&gt;
  minDamage,&lt;br /&gt;
  maxDamage&lt;br /&gt;
) {&lt;br /&gt;
  var {&lt;br /&gt;
    tableResultFight,&lt;br /&gt;
    tableResultHistory,&lt;br /&gt;
    savedFights,&lt;br /&gt;
    numberFormats: { default: numberFormat },&lt;br /&gt;
    deleteFightTemplate,&lt;br /&gt;
  } = battle;&lt;br /&gt;
&lt;br /&gt;
  hideElement(tableResultHistory.rows[1]);&lt;br /&gt;
&lt;br /&gt;
  var valuesToDisplay = [&lt;br /&gt;
    attackerName,&lt;br /&gt;
    victimName,&lt;br /&gt;
    battle.battleChoice.attackType.selectedText,&lt;br /&gt;
    meanDamage,&lt;br /&gt;
    minDamage,&lt;br /&gt;
    maxDamage,&lt;br /&gt;
  ];&lt;br /&gt;
&lt;br /&gt;
  savedFights.push(valuesToDisplay);&lt;br /&gt;
  updateSavedFights(savedFights);&lt;br /&gt;
&lt;br /&gt;
  editTableResultRow(tableResultFight.rows[1], valuesToDisplay, numberFormat);&lt;br /&gt;
  addRowToTableResultHistory(&lt;br /&gt;
    tableResultHistory,&lt;br /&gt;
    valuesToDisplay,&lt;br /&gt;
    deleteFightTemplate,&lt;br /&gt;
    numberFormat&lt;br /&gt;
  );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function displayFightInfo(&lt;br /&gt;
  possibleDamageCount,&lt;br /&gt;
  damageTimeDuration,&lt;br /&gt;
  displayTimeDuration,&lt;br /&gt;
  battle&lt;br /&gt;
) {&lt;br /&gt;
  const {&lt;br /&gt;
    damageInfoContainer,&lt;br /&gt;
    numberFormats: { default: defaultFormat, second: secondFormat },&lt;br /&gt;
    possibleDamageCounter,&lt;br /&gt;
    damageTime,&lt;br /&gt;
    displayTime,&lt;br /&gt;
  } = battle;&lt;br /&gt;
&lt;br /&gt;
  if (possibleDamageCount &amp;lt;= 1) {&lt;br /&gt;
    hideElement(damageInfoContainer);&lt;br /&gt;
    return;&lt;br /&gt;
  } else {&lt;br /&gt;
    showElement(damageInfoContainer);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  possibleDamageCount = defaultFormat.format(possibleDamageCount);&lt;br /&gt;
  damageTimeDuration = secondFormat.format(damageTimeDuration / 1000);&lt;br /&gt;
  displayTimeDuration = secondFormat.format(displayTimeDuration / 1000);&lt;br /&gt;
&lt;br /&gt;
  possibleDamageCounter.textContent = possibleDamageCount;&lt;br /&gt;
  damageTime.textContent = damageTimeDuration;&lt;br /&gt;
  displayTime.textContent = displayTimeDuration;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function parseTypeAndName(data) {&lt;br /&gt;
  var [type, nameOrVnum] = splitFirst(data, &amp;quot;-&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    type: type,&lt;br /&gt;
    nameOrVnum: nameOrVnum,&lt;br /&gt;
    isCharacter: type === &amp;quot;character&amp;quot;,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isCharacterSelected(characterName, selected) {&lt;br /&gt;
  if (!selected) {&lt;br /&gt;
    return false;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var { nameOrVnum, isCharacter } = parseTypeAndName(selected);&lt;br /&gt;
&lt;br /&gt;
  return nameOrVnum === characterName &amp;amp;&amp;amp; isCharacter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function useBonusVariationMode(character, variation) {&lt;br /&gt;
  return (&lt;br /&gt;
    isChecked(character.useBonusVariation) &amp;amp;&amp;amp;&lt;br /&gt;
    character.hasOwnProperty(variation) &amp;amp;&amp;amp;&lt;br /&gt;
    character.bonusVariationMinValue &amp;lt; character.bonusVariationMaxValue&lt;br /&gt;
  );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createBattle(characters, battle) {&lt;br /&gt;
  var battleChoice = battle.battleChoice;&lt;br /&gt;
  var battleForm = battleChoice.form;&lt;br /&gt;
  var lastInvalidTime = 0;&lt;br /&gt;
&lt;br /&gt;
  battleForm.addEventListener(&amp;quot;change&amp;quot;, handleBattleFormChange);&lt;br /&gt;
  battleForm.addEventListener(&amp;quot;invalid&amp;quot;, handleBattleFormInvalid, true);&lt;br /&gt;
  battleForm.addEventListener(&amp;quot;submit&amp;quot;, handleBattleFormSubmit);&lt;br /&gt;
&lt;br /&gt;
  function handleBattleFormChange(event) {&lt;br /&gt;
    var target = event.target;&lt;br /&gt;
    var { name: targetName, value: targetValue, type: targetType } = target;&lt;br /&gt;
&lt;br /&gt;
    if (targetType !== &amp;quot;radio&amp;quot;) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (targetName === &amp;quot;attackType&amp;quot;) {&lt;br /&gt;
      battleChoice.attackType.selectedText =&lt;br /&gt;
        target.previousElementSibling.textContent;&lt;br /&gt;
    } else {&lt;br /&gt;
      updateBattleChoiceButton(battleChoice, targetName, targetValue);&lt;br /&gt;
&lt;br /&gt;
      if (targetName === &amp;quot;attacker&amp;quot;) {&lt;br /&gt;
        filterAttackTypeSelection(characters, battleChoice, targetValue);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function handleBattleFormInvalid(event) {&lt;br /&gt;
    var currentTime = Date.now();&lt;br /&gt;
&lt;br /&gt;
    if (currentTime - lastInvalidTime &amp;lt; 100) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    lastInvalidTime = currentTime;&lt;br /&gt;
&lt;br /&gt;
    var target = event.target;&lt;br /&gt;
    var modal = target.closest(&amp;quot;.modal&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (!modal) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var dataModal = modal.dataset.modal;&lt;br /&gt;
&lt;br /&gt;
    if (!dataModal) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var category = dataModal.split(&amp;quot;-&amp;quot;)[0];&lt;br /&gt;
&lt;br /&gt;
    if (isValueInArray(category, battleChoice.categories)) {&lt;br /&gt;
      battleChoice[category].button.click();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function handleBattleFormSubmit(event) {&lt;br /&gt;
    event.preventDefault();&lt;br /&gt;
&lt;br /&gt;
    // auto save&lt;br /&gt;
    if (characters.unsavedChanges) {&lt;br /&gt;
      characters.saveButton.click();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var battleInfo = new FormData(event.target);&lt;br /&gt;
    var attackerData = battleInfo.get(&amp;quot;attacker&amp;quot;);&lt;br /&gt;
    var attackType = battleInfo.get(&amp;quot;attackType&amp;quot;);&lt;br /&gt;
    var victimData = battleInfo.get(&amp;quot;victim&amp;quot;);&lt;br /&gt;
    var attackerVariation;&lt;br /&gt;
    var victimVariation;&lt;br /&gt;
&lt;br /&gt;
    if (!attackerData &amp;amp;&amp;amp; !attackType &amp;amp;&amp;amp; !victimData) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var { nameOrVnum: attackerNameOrVnum, isCharacter: attackerIsPlayer } =&lt;br /&gt;
      parseTypeAndName(attackerData);&lt;br /&gt;
    var { nameOrVnum: victimNameOrVnum, isCharacter: victimIsPlayer } =&lt;br /&gt;
      parseTypeAndName(victimData);&lt;br /&gt;
&lt;br /&gt;
    if (attackerIsPlayer) {&lt;br /&gt;
      var attacker = copyObject(characters.savedCharacters[attackerNameOrVnum]);&lt;br /&gt;
      attackerVariation = attacker.bonusVariation;&lt;br /&gt;
    } else {&lt;br /&gt;
      var attacker = createMonster(&lt;br /&gt;
        attackerNameOrVnum,&lt;br /&gt;
        characters.translateMonsters&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (victimIsPlayer) {&lt;br /&gt;
      var victim = copyObject(characters.savedCharacters[victimNameOrVnum]);&lt;br /&gt;
      victimVariation = victim.bonusVariation;&lt;br /&gt;
    } else {&lt;br /&gt;
      var victim = createMonster(&lt;br /&gt;
        victimNameOrVnum,&lt;br /&gt;
        characters.translateMonsters,&lt;br /&gt;
        attacker&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (useBonusVariationMode(attacker, attackerVariation)) {&lt;br /&gt;
      damageWithVariation(&lt;br /&gt;
        attacker,&lt;br /&gt;
        victim,&lt;br /&gt;
        attackType,&lt;br /&gt;
        battle,&lt;br /&gt;
        attacker,&lt;br /&gt;
        attackerVariation&lt;br /&gt;
      );&lt;br /&gt;
    } else if (useBonusVariationMode(victim, victimVariation)) {&lt;br /&gt;
      damageWithVariation(&lt;br /&gt;
        attacker,&lt;br /&gt;
        victim,&lt;br /&gt;
        attackType,&lt;br /&gt;
        battle,&lt;br /&gt;
        victim,&lt;br /&gt;
        victimVariation&lt;br /&gt;
      );&lt;br /&gt;
    } else {&lt;br /&gt;
      damageWithoutVariation(attacker, victim, attackType, battle, characters);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createMapping() {&lt;br /&gt;
  return {&lt;br /&gt;
    typeFlag: [&lt;br /&gt;
      &amp;quot;animalBonus&amp;quot;, // 0&lt;br /&gt;
      &amp;quot;humanBonus&amp;quot;, // 1&lt;br /&gt;
      &amp;quot;orcBonus&amp;quot;, // 2&lt;br /&gt;
      &amp;quot;mysticBonus&amp;quot;, // 3&lt;br /&gt;
      &amp;quot;undeadBonus&amp;quot;, // 4&lt;br /&gt;
      &amp;quot;insectBonus&amp;quot;, // 5&lt;br /&gt;
      &amp;quot;desertBonus&amp;quot;, // 6&lt;br /&gt;
      &amp;quot;devilBonus&amp;quot;, // 7&lt;br /&gt;
      &amp;quot;zodiacBonus&amp;quot;, // 8&lt;br /&gt;
    ],&lt;br /&gt;
    raceBonus: {&lt;br /&gt;
      warrior: &amp;quot;warriorBonus&amp;quot;,&lt;br /&gt;
      sura: &amp;quot;suraBonus&amp;quot;,&lt;br /&gt;
      ninja: &amp;quot;ninjaBonus&amp;quot;,&lt;br /&gt;
      shaman: &amp;quot;shamanBonus&amp;quot;,&lt;br /&gt;
      lycan: &amp;quot;lycanBonus&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    raceResistance: {&lt;br /&gt;
      warrior: &amp;quot;warriorResistance&amp;quot;,&lt;br /&gt;
      sura: &amp;quot;suraResistance&amp;quot;,&lt;br /&gt;
      ninja: &amp;quot;ninjaResistance&amp;quot;,&lt;br /&gt;
      shaman: &amp;quot;shamanResistance&amp;quot;,&lt;br /&gt;
      lycan: &amp;quot;lycanResistance&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    defenseWeapon: [&lt;br /&gt;
      &amp;quot;swordDefense&amp;quot;, // 0&lt;br /&gt;
      &amp;quot;daggerDefense&amp;quot;, // 1&lt;br /&gt;
      &amp;quot;arrowDefense&amp;quot;, // 2&lt;br /&gt;
      &amp;quot;twoHandedSwordDefense&amp;quot;, // 3&lt;br /&gt;
      &amp;quot;bellDefense&amp;quot;, // 4&lt;br /&gt;
      &amp;quot;clawDefense&amp;quot;, // 5&lt;br /&gt;
      &amp;quot;fanDefense&amp;quot;, // 6&lt;br /&gt;
      &amp;quot;swordDefense&amp;quot;, // 7&lt;br /&gt;
      &amp;quot;fistDefense&amp;quot;, // 8&lt;br /&gt;
    ],&lt;br /&gt;
    breakWeapon: [&lt;br /&gt;
      &amp;quot;breakSwordDefense&amp;quot;, // 0&lt;br /&gt;
      &amp;quot;breakDaggerDefense&amp;quot;, // 1&lt;br /&gt;
      &amp;quot;breakArrowDefense&amp;quot;, // 2&lt;br /&gt;
      &amp;quot;breakTwoHandedSwordDefense&amp;quot;, // 3&lt;br /&gt;
      &amp;quot;breakBellDefense&amp;quot;, // 4&lt;br /&gt;
      &amp;quot;breakClawDefense&amp;quot;, // 5&lt;br /&gt;
      &amp;quot;breakFanDefense&amp;quot;, // 6&lt;br /&gt;
      &amp;quot;breakSwordDefense&amp;quot;, // 7&lt;br /&gt;
    ],&lt;br /&gt;
    elementBonus: [&lt;br /&gt;
      &amp;quot;fireBonus&amp;quot;, // 0&lt;br /&gt;
      &amp;quot;iceBonus&amp;quot;, // 1&lt;br /&gt;
      &amp;quot;windBonus&amp;quot;, // 2&lt;br /&gt;
      &amp;quot;lightningBonus&amp;quot;, // 3&lt;br /&gt;
      &amp;quot;earthBonus&amp;quot;, // 4&lt;br /&gt;
      &amp;quot;darknessBonus&amp;quot;, // 5&lt;br /&gt;
    ],&lt;br /&gt;
    elementResistance: [&lt;br /&gt;
      &amp;quot;fireResistance&amp;quot;, // 0&lt;br /&gt;
      &amp;quot;iceResistance&amp;quot;, // 1&lt;br /&gt;
      &amp;quot;windResistance&amp;quot;, // 2&lt;br /&gt;
      &amp;quot;lightningResistance&amp;quot;, // 3&lt;br /&gt;
      &amp;quot;earthResistance&amp;quot;, // 4&lt;br /&gt;
      &amp;quot;darknessResistance&amp;quot;, // 5&lt;br /&gt;
    ],&lt;br /&gt;
    attackType: [&lt;br /&gt;
      &amp;quot;normalHit&amp;quot;,&lt;br /&gt;
      &amp;quot;criticalHit&amp;quot;,&lt;br /&gt;
      &amp;quot;piercingHit&amp;quot;,&lt;br /&gt;
      &amp;quot;criticalPiercingHit&amp;quot;,&lt;br /&gt;
    ],&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createConstants() {&lt;br /&gt;
  var constants = {&lt;br /&gt;
    polymorphPowerTable: [&lt;br /&gt;
      10, 11, 11, 12, 13, 13, 14, 15, 16, 17, 18, 19, 20, 22, 23, 24, 26, 27,&lt;br /&gt;
      29, 31, 33, 35, 37, 39, 41, 44, 46, 49, 52, 55, 59, 62, 66, 70, 74, 79,&lt;br /&gt;
      84, 89, 94, 100, 0,&lt;br /&gt;
    ],&lt;br /&gt;
    skillPowerTable: [&lt;br /&gt;
      0, 0.05, 0.06, 0.08, 0.1, 0.12, 0.14, 0.16, 0.18, 0.2, 0.22, 0.24, 0.26,&lt;br /&gt;
      0.28, 0.3, 0.32, 0.34, 0.36, 0.38, 0.4, 0.5, 0.52, 0.54, 0.56, 0.58, 0.6,&lt;br /&gt;
      0.63, 0.66, 0.69, 0.72, 0.82, 0.85, 0.88, 0.91, 0.94, 0.98, 1.02, 1.06,&lt;br /&gt;
      1.1, 1.15, 1.25,&lt;br /&gt;
    ],&lt;br /&gt;
    marriageTable: {&lt;br /&gt;
      harmonyEarrings: [4, 5, 6, 8],&lt;br /&gt;
      loveEarrings: [4, 5, 6, 8],&lt;br /&gt;
      harmonyBracelet: [4, 5, 6, 8],&lt;br /&gt;
      loveNecklace: [20, 25, 30, 40],&lt;br /&gt;
      harmonyNecklace: [12, 16, 20, 30],&lt;br /&gt;
    },&lt;br /&gt;
    allowedWeaponsPerRace: {&lt;br /&gt;
      warrior: [0, 3, 8],&lt;br /&gt;
      ninja: [0, 1, 2, 8],&lt;br /&gt;
      sura: [0, 7, 8],&lt;br /&gt;
      shaman: [4, 6, 8],&lt;br /&gt;
      lycan: [5, 8],&lt;br /&gt;
    },&lt;br /&gt;
  };&lt;br /&gt;
  return constants;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initResultTableHistory(battle) {&lt;br /&gt;
  var {&lt;br /&gt;
    tableResultHistory,&lt;br /&gt;
    savedFights,&lt;br /&gt;
    deleteFightTemplate,&lt;br /&gt;
    numberFormats: { default: numberFormat },&lt;br /&gt;
  } = battle;&lt;br /&gt;
  var startIndex = 3;&lt;br /&gt;
&lt;br /&gt;
  if (savedFights.length) {&lt;br /&gt;
    hideElement(tableResultHistory.rows[1]);&lt;br /&gt;
&lt;br /&gt;
    for (var savedFight of savedFights) {&lt;br /&gt;
      addRowToTableResultHistory(&lt;br /&gt;
        tableResultHistory,&lt;br /&gt;
        savedFight,&lt;br /&gt;
        deleteFightTemplate,&lt;br /&gt;
        numberFormat&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  tableResultHistory.addEventListener(&amp;quot;click&amp;quot;, function (event) {&lt;br /&gt;
    var deleteButton = event.target.closest(&amp;quot;.svg-icon-delete&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (deleteButton) {&lt;br /&gt;
      var row = deleteButton.closest(&amp;quot;tr&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
      if (row) {&lt;br /&gt;
        savedFights.splice(row.rowIndex - startIndex, 1);&lt;br /&gt;
        updateSavedFights(savedFights);&lt;br /&gt;
&lt;br /&gt;
        row.remove();&lt;br /&gt;
&lt;br /&gt;
        if (tableResultHistory.rows.length === startIndex) {&lt;br /&gt;
          showElement(tableResultHistory.rows[1]);&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initDamageChart(battle, currentLanguage, defaultText) {&lt;br /&gt;
  const { reduceChartPointsContainer, reduceChartPoints } = battle;&lt;br /&gt;
  const { default: defaultFormat, percent: percentFormat } =&lt;br /&gt;
    battle.numberFormats;&lt;br /&gt;
  const customPlugins = {&lt;br /&gt;
    id: &amp;quot;customPlugins&amp;quot;,&lt;br /&gt;
    afterDraw(chart) {&lt;br /&gt;
      const missPercentage = chart.data.missPercentage;&lt;br /&gt;
&lt;br /&gt;
      if (!missPercentage) {&lt;br /&gt;
        return;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      const {&lt;br /&gt;
        ctx,&lt;br /&gt;
        chartArea: { top, right },&lt;br /&gt;
      } = chart;&lt;br /&gt;
      ctx.save();&lt;br /&gt;
      const text =&lt;br /&gt;
        defaultText.miss + &amp;quot; : &amp;quot; + percentFormat.format(missPercentage);&lt;br /&gt;
      const padding = 4;&lt;br /&gt;
      const fontSize = 14;&lt;br /&gt;
&lt;br /&gt;
      ctx.font = fontSize + &amp;quot;px Helvetica Neue&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
      const textWidth = ctx.measureText(text).width;&lt;br /&gt;
      const xPosition = right - textWidth - 5;&lt;br /&gt;
      const yPosition = top + 5;&lt;br /&gt;
&lt;br /&gt;
      ctx.fillStyle = &amp;quot;rgba(255, 0, 0, 0.2)&amp;quot;;&lt;br /&gt;
      ctx.fillRect(&lt;br /&gt;
        xPosition - padding,&lt;br /&gt;
        yPosition - padding,&lt;br /&gt;
        textWidth + 2 * padding,&lt;br /&gt;
        fontSize + 2 * padding&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      ctx.strokeStyle = &amp;quot;red&amp;quot;;&lt;br /&gt;
      ctx.strokeRect(&lt;br /&gt;
        xPosition - padding,&lt;br /&gt;
        yPosition - padding,&lt;br /&gt;
        textWidth + 2 * padding,&lt;br /&gt;
        fontSize + 2 * padding&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      ctx.fillStyle = &amp;quot;#666&amp;quot;;&lt;br /&gt;
      ctx.textBaseline = &amp;quot;top&amp;quot;;&lt;br /&gt;
      ctx.fillText(text, xPosition, yPosition + 1);&lt;br /&gt;
&lt;br /&gt;
      ctx.restore();&lt;br /&gt;
    },&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  Chart.register(customPlugins);&lt;br /&gt;
&lt;br /&gt;
  const ctx = battle.plotDamage.getContext(&amp;quot;2d&amp;quot;);&lt;br /&gt;
  const maxLabelsInTooltip = 10;&lt;br /&gt;
  const nullLabelText = &amp;quot; ...&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  const chart = new Chart(ctx, {&lt;br /&gt;
    type: &amp;quot;scatter&amp;quot;,&lt;br /&gt;
    data: {&lt;br /&gt;
      missPercentage: 0,&lt;br /&gt;
      datasets: [],&lt;br /&gt;
    },&lt;br /&gt;
    options: {&lt;br /&gt;
      locale: currentLanguage,&lt;br /&gt;
      responsive: true,&lt;br /&gt;
      maintainAspectRatio: false,&lt;br /&gt;
      plugins: {&lt;br /&gt;
        legend: {&lt;br /&gt;
          display: true,&lt;br /&gt;
          onHover: function (e) {&lt;br /&gt;
            e.native.target.style.cursor = &amp;quot;pointer&amp;quot;;&lt;br /&gt;
          },&lt;br /&gt;
          onLeave: function (e) {&lt;br /&gt;
            e.native.target.style.cursor = &amp;quot;default&amp;quot;;&lt;br /&gt;
          },&lt;br /&gt;
          onClick: function (e, legendItem, legend) {&lt;br /&gt;
            const currentIndex = legendItem.datasetIndex;&lt;br /&gt;
            const ci = legend.chart;&lt;br /&gt;
            const isCurrentDatasetVisible = ci.isDatasetVisible(currentIndex);&lt;br /&gt;
            const datasets = ci.data.datasets;&lt;br /&gt;
            const isReducePointsChecked = reduceChartPoints.checked;&lt;br /&gt;
            let hideReducePoints = true;&lt;br /&gt;
&lt;br /&gt;
            datasets[currentIndex].hidden = isCurrentDatasetVisible;&lt;br /&gt;
            legendItem.hidden = isCurrentDatasetVisible;&lt;br /&gt;
&lt;br /&gt;
            for (const index in datasets) {&lt;br /&gt;
              if (ci.isDatasetVisible(index) &amp;amp;&amp;amp; datasets[index].canBeReduced) {&lt;br /&gt;
                showElement(reduceChartPointsContainer);&lt;br /&gt;
                hideReducePoints = false;&lt;br /&gt;
                break;&lt;br /&gt;
              }&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            if (hideReducePoints) {&lt;br /&gt;
              hideElement(reduceChartPointsContainer);&lt;br /&gt;
              handleChartAnimations(ci, true);&lt;br /&gt;
            } else {&lt;br /&gt;
              handleChartAnimations(ci, isReducePointsChecked);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            ci.update();&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        title: {&lt;br /&gt;
          display: true,&lt;br /&gt;
          text: defaultText.damageRepartition,&lt;br /&gt;
          font: {&lt;br /&gt;
            size: 20,&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        tooltip: {&lt;br /&gt;
          callbacks: {&lt;br /&gt;
            label: function (context) {&lt;br /&gt;
              if (context.label === null) {&lt;br /&gt;
                return nullLabelText;&lt;br /&gt;
              }&lt;br /&gt;
&lt;br /&gt;
              const xValue = defaultFormat.format(context.parsed.x);&lt;br /&gt;
              const yValue = percentFormat.format(context.parsed.y);&lt;br /&gt;
              const label =&lt;br /&gt;
                &amp;quot; &amp;quot; +&lt;br /&gt;
                context.dataset.label +&lt;br /&gt;
                &amp;quot; : (&amp;quot; +&lt;br /&gt;
                xValue +&lt;br /&gt;
                &amp;quot;, &amp;quot; +&lt;br /&gt;
                yValue +&lt;br /&gt;
                &amp;quot;)&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
              return label;&lt;br /&gt;
            },&lt;br /&gt;
            beforeBody: function (tooltipItems) {&lt;br /&gt;
              if (tooltipItems.length &amp;gt; maxLabelsInTooltip + 1) {&lt;br /&gt;
                tooltipItems.splice(maxLabelsInTooltip + 1);&lt;br /&gt;
                tooltipItems[maxLabelsInTooltip].label = null;&lt;br /&gt;
              }&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          caretPadding: 10,&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
      scales: {&lt;br /&gt;
        x: {&lt;br /&gt;
          type: &amp;quot;linear&amp;quot;,&lt;br /&gt;
          position: &amp;quot;bottom&amp;quot;,&lt;br /&gt;
          title: {&lt;br /&gt;
            display: true,&lt;br /&gt;
            text: defaultText.damage,&lt;br /&gt;
            font: {&lt;br /&gt;
              size: 16,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          ticks: {&lt;br /&gt;
            callback: function (value) {&lt;br /&gt;
              return Number.isInteger(value) ? value : &amp;quot;&amp;quot;;&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        y: {&lt;br /&gt;
          title: {&lt;br /&gt;
            display: true,&lt;br /&gt;
            text: defaultText.percentage,&lt;br /&gt;
            font: {&lt;br /&gt;
              size: 16,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          ticks: {&lt;br /&gt;
            format: {&lt;br /&gt;
              style: &amp;quot;percent&amp;quot;,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
      elements: {&lt;br /&gt;
        point: {&lt;br /&gt;
          borderWidth: 1,&lt;br /&gt;
          radius: 3,&lt;br /&gt;
          hitRadius: 3,&lt;br /&gt;
          hoverRadius: 6,&lt;br /&gt;
          hoverBorderWidth: 2,&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
    },&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  const datasetsStyle = [&lt;br /&gt;
    {&lt;br /&gt;
      name: &amp;quot;normalHit&amp;quot;,&lt;br /&gt;
      canBeReduced: false,&lt;br /&gt;
      label: defaultText.normalHit,&lt;br /&gt;
      backgroundColor: &amp;quot;rgba(75, 192, 192, 0.2)&amp;quot;,&lt;br /&gt;
      borderColor: &amp;quot;rgba(75, 192, 192, 1)&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      name: &amp;quot;piercingHit&amp;quot;,&lt;br /&gt;
      canBeReduced: false,&lt;br /&gt;
      label: defaultText.piercingHit,&lt;br /&gt;
      backgroundColor: &amp;quot;rgba(192, 192, 75, 0.2)&amp;quot;,&lt;br /&gt;
      borderColor: &amp;quot;rgba(192, 192, 75, 1)&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      name: &amp;quot;criticalHit&amp;quot;,&lt;br /&gt;
      canBeReduced: false,&lt;br /&gt;
      label: defaultText.criticalHit,&lt;br /&gt;
      backgroundColor: &amp;quot;rgba(192, 75, 192, 0.2)&amp;quot;,&lt;br /&gt;
      borderColor: &amp;quot;rgba(192, 75, 192, 1)&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      name: &amp;quot;criticalPiercingHit&amp;quot;,&lt;br /&gt;
      canBeReduced: false,&lt;br /&gt;
      label: defaultText.criticalPiercingHit,&lt;br /&gt;
      backgroundColor: &amp;quot;rgba(75, 75, 192, 0.2)&amp;quot;,&lt;br /&gt;
      borderColor: &amp;quot;rgba(75, 75, 192, 1)&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
  ];&lt;br /&gt;
  battle.damageChart = {&lt;br /&gt;
    chart: chart,&lt;br /&gt;
    datasetsStyle: datasetsStyle,&lt;br /&gt;
    maxPoints: 500,&lt;br /&gt;
    reduceChartPointsContainer: reduceChartPointsContainer,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initBonusVariationChart(battle, currentLanguage, defaultText) {&lt;br /&gt;
  const { plotBonusVariation } = battle;&lt;br /&gt;
&lt;br /&gt;
  const ctx = plotBonusVariation.getContext(&amp;quot;2d&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  const chart = new Chart(ctx, {&lt;br /&gt;
    type: &amp;quot;line&amp;quot;,&lt;br /&gt;
    data: {&lt;br /&gt;
      datasets: [&lt;br /&gt;
        {&lt;br /&gt;
          label: defaultText.averageDamage,&lt;br /&gt;
          backgroundColor: &amp;quot;rgba(75, 192, 192, 0.2)&amp;quot;,&lt;br /&gt;
          borderColor: &amp;quot;rgba(75, 192, 192, 1)&amp;quot;,&lt;br /&gt;
          fill: true,&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          label: defaultText.damageAugmentation,&lt;br /&gt;
          backgroundColor: &amp;quot;rgba(192, 192, 75, 0.2)&amp;quot;,&lt;br /&gt;
          borderColor: &amp;quot;rgba(192, 192, 75, 1)&amp;quot;,&lt;br /&gt;
          hidden: true,&lt;br /&gt;
          yTicksFormat: { style: &amp;quot;percent&amp;quot; },&lt;br /&gt;
          fill: true,&lt;br /&gt;
        },&lt;br /&gt;
      ],&lt;br /&gt;
    },&lt;br /&gt;
    options: {&lt;br /&gt;
      locale: currentLanguage,&lt;br /&gt;
      responsive: true,&lt;br /&gt;
      maintainAspectRatio: false,&lt;br /&gt;
      plugins: {&lt;br /&gt;
        legend: {&lt;br /&gt;
          display: true,&lt;br /&gt;
          onHover: function (e) {&lt;br /&gt;
            e.native.target.style.cursor = &amp;quot;pointer&amp;quot;;&lt;br /&gt;
          },&lt;br /&gt;
          onLeave: function (e) {&lt;br /&gt;
            e.native.target.style.cursor = &amp;quot;default&amp;quot;;&lt;br /&gt;
          },&lt;br /&gt;
          onClick: function (e, legendItem, legend) {&lt;br /&gt;
            var currentIndex = legendItem.datasetIndex;&lt;br /&gt;
            var ci = legend.chart;&lt;br /&gt;
            var datasets = ci.data.datasets;&lt;br /&gt;
            var isCurrentDatasetVisible = ci.isDatasetVisible(currentIndex);&lt;br /&gt;
            var yAxis = ci.options.scales.y;&lt;br /&gt;
&lt;br /&gt;
            var otherIndex = currentIndex === 0 ? 1 : 0;&lt;br /&gt;
            var visibleDataset = isCurrentDatasetVisible&lt;br /&gt;
              ? datasets[otherIndex]&lt;br /&gt;
              : datasets[currentIndex];&lt;br /&gt;
&lt;br /&gt;
            datasets[currentIndex].hidden = isCurrentDatasetVisible;&lt;br /&gt;
            datasets[otherIndex].hidden = !isCurrentDatasetVisible;&lt;br /&gt;
&lt;br /&gt;
            yAxis.title.text = visibleDataset.label;&lt;br /&gt;
            yAxis.ticks.format = visibleDataset.yTicksFormat;&lt;br /&gt;
&lt;br /&gt;
            ci.update();&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        title: {&lt;br /&gt;
          display: true,&lt;br /&gt;
          text: defaultText.bonusVariationTitle.split(&amp;quot;[[]]&amp;quot;),&lt;br /&gt;
          font: {&lt;br /&gt;
            size: 18,&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        tooltip: {&lt;br /&gt;
          caretPadding: 10,&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
      scales: {&lt;br /&gt;
        x: {&lt;br /&gt;
          type: &amp;quot;linear&amp;quot;,&lt;br /&gt;
          position: &amp;quot;bottom&amp;quot;,&lt;br /&gt;
          title: {&lt;br /&gt;
            display: true,&lt;br /&gt;
            text: &amp;quot;Bonus&amp;quot;,&lt;br /&gt;
            font: {&lt;br /&gt;
              size: 16,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          ticks: {&lt;br /&gt;
            callback: function (value) {&lt;br /&gt;
              if (Number.isInteger(value)) {&lt;br /&gt;
                return Number(value);&lt;br /&gt;
              }&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        y: {&lt;br /&gt;
          title: {&lt;br /&gt;
            display: true,&lt;br /&gt;
            text: defaultText.averageDamage,&lt;br /&gt;
            font: {&lt;br /&gt;
              size: 16,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
      elements: {&lt;br /&gt;
        point: {&lt;br /&gt;
          borderWidth: 1,&lt;br /&gt;
          radius: 3,&lt;br /&gt;
          hitRadius: 3,&lt;br /&gt;
          hoverRadius: 6,&lt;br /&gt;
          hoverBorderWidth: 2,&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
    },&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  battle.bonusVariationChart = chart;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterAttackTypeSelection(characters, battleChoice, targetValue) {&lt;br /&gt;
  var { nameOrVnum: attackerNameOrVnum, isCharacter: isAttackerPlayer } =&lt;br /&gt;
    parseTypeAndName(targetValue);&lt;br /&gt;
&lt;br /&gt;
  if (isAttackerPlayer) {&lt;br /&gt;
    var attacker = characters.savedCharacters[attackerNameOrVnum];&lt;br /&gt;
    filterAttackTypeSelectionCharacter(attacker, battleChoice.attackType);&lt;br /&gt;
  } else {&lt;br /&gt;
    filterAttackTypeSelectionMonster(battleChoice.attackType);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addBattleData(battle) {&lt;br /&gt;
  var errorElements = document.querySelectorAll(&amp;quot;[data-error]&amp;quot;);&lt;br /&gt;
  var { elements: attackTypeElements, container: attackTypeContainer } =&lt;br /&gt;
    battle.battleChoice.attackType;&lt;br /&gt;
  var attackTypeChilds = attackTypeContainer.children;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; errorElements.length; index++) {&lt;br /&gt;
    var errorElement = errorElements[index];&lt;br /&gt;
    battle.errorInformation[errorElement.dataset.error] = errorElement;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (var index = 1; index &amp;lt; attackTypeChilds.length - 1; index++) {&lt;br /&gt;
    var attackTypeChild = attackTypeChilds[index];&lt;br /&gt;
    var input = attackTypeChild.querySelector(&amp;quot;input&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    attackTypeElements.push({&lt;br /&gt;
      container: attackTypeChild,&lt;br /&gt;
      input: input,&lt;br /&gt;
      inputClass: input.dataset.class,&lt;br /&gt;
      inputValue: input.value,&lt;br /&gt;
    });&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createDamageCalculatorInformation(&lt;br /&gt;
  defaultLang,&lt;br /&gt;
  currentLanguage,&lt;br /&gt;
  defaultText&lt;br /&gt;
) {&lt;br /&gt;
  const characters = {&lt;br /&gt;
    unsavedChanges: false,&lt;br /&gt;
    savedCharacters: {},&lt;br /&gt;
    currentCharacter: null,&lt;br /&gt;
    savedMonsters: getSavedMonsters(),&lt;br /&gt;
    monsterElements: {},&lt;br /&gt;
    characterCreation: document.getElementById(&amp;quot;character-creation&amp;quot;),&lt;br /&gt;
    addNewCharacterButton: document.getElementById(&amp;quot;add-new-character&amp;quot;),&lt;br /&gt;
    dropZone: document.getElementById(&amp;quot;character-drop-zone&amp;quot;),&lt;br /&gt;
    characterInput: document.getElementById(&amp;quot;character-input&amp;quot;),&lt;br /&gt;
    newCharacterTemplate: document.getElementById(&amp;quot;new-character-template&amp;quot;)&lt;br /&gt;
      .children[0],&lt;br /&gt;
    charactersContainer: document.getElementById(&amp;quot;characters-container&amp;quot;),&lt;br /&gt;
    monsterButtonTemplates: document.getElementById(&amp;quot;monster-button-templates&amp;quot;),&lt;br /&gt;
    monsterTemplate: document.getElementById(&amp;quot;new-monster-template&amp;quot;)&lt;br /&gt;
      .children[0],&lt;br /&gt;
    monstersContainer: document.getElementById(&amp;quot;monsters-container&amp;quot;),&lt;br /&gt;
    monsteriFrame: document.getElementById(&amp;quot;monster-iframe&amp;quot;),&lt;br /&gt;
    stoneiFrame: document.getElementById(&amp;quot;stone-iframe&amp;quot;),&lt;br /&gt;
    saveButton: document.getElementById(&amp;quot;save-character&amp;quot;),&lt;br /&gt;
    weaponCategory: document.getElementById(&amp;quot;weapon-category&amp;quot;),&lt;br /&gt;
    weaponDisplay: document.getElementById(&amp;quot;weapon-display&amp;quot;),&lt;br /&gt;
    randomAttackValue: document.getElementById(&amp;quot;random-attack-value&amp;quot;),&lt;br /&gt;
    randomMagicAttackValue: document.getElementById(&lt;br /&gt;
      &amp;quot;random-magic-attack-value&amp;quot;&lt;br /&gt;
    ),&lt;br /&gt;
    toggleSiblings: {},&lt;br /&gt;
    polymorphDisplay: document.getElementById(&amp;quot;polymorph-display&amp;quot;),&lt;br /&gt;
    bonusVariation: {&lt;br /&gt;
      tabButton: document.getElementById(&amp;quot;Variation&amp;quot;),&lt;br /&gt;
      checkbox: document.getElementById(&amp;quot;use-bonus-variation&amp;quot;),&lt;br /&gt;
      input: document.getElementById(&amp;quot;bonus-variation&amp;quot;),&lt;br /&gt;
      inputName: document.getElementById(&amp;quot;bonus-variation-name&amp;quot;),&lt;br /&gt;
      container: document.getElementById(&amp;quot;bonus-variation-creation&amp;quot;),&lt;br /&gt;
      minValue: document.getElementById(&amp;quot;bonus-variation-min-value&amp;quot;),&lt;br /&gt;
      maxValue: document.getElementById(&amp;quot;bonus-variation-max-value&amp;quot;),&lt;br /&gt;
      disabledText: document.getElementById(&amp;quot;bonus-variation-disabled&amp;quot;),&lt;br /&gt;
      selectedText: document.getElementById(&amp;quot;bonus-variation-selected&amp;quot;),&lt;br /&gt;
      displaySpan: document.getElementById(&amp;quot;bonus-variation-display&amp;quot;),&lt;br /&gt;
    },&lt;br /&gt;
    skillElementsToFilter: document.querySelectorAll(&lt;br /&gt;
      &amp;quot;#skill-container [data-class]&amp;quot;&lt;br /&gt;
    ),&lt;br /&gt;
    currentLanguage: currentLanguage,&lt;br /&gt;
    translateMonsters: defaultLang !== currentLanguage,&lt;br /&gt;
    defaultText: defaultText,&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  for (const [pseudo, character] of Object.entries(getSavedCharacters())) {&lt;br /&gt;
    characters.savedCharacters[pseudo] = character;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  document.querySelectorAll(&amp;quot;.toggle-sibling&amp;quot;).forEach(function (element) {&lt;br /&gt;
    const target = element.dataset.target;&lt;br /&gt;
    const sibling = document.getElementById(target);&lt;br /&gt;
    characters.toggleSiblings[element.name] = sibling;&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  const constants = createConstants();&lt;br /&gt;
&lt;br /&gt;
  const battle = {&lt;br /&gt;
    savedFights: getSavedFights(),&lt;br /&gt;
    battleChoice: {&lt;br /&gt;
      resetAttackType: false,&lt;br /&gt;
      form: document.getElementById(&amp;quot;create-battle&amp;quot;),&lt;br /&gt;
      template: document.getElementById(&amp;quot;battle-selection-template&amp;quot;)&lt;br /&gt;
        .children[0],&lt;br /&gt;
      raceToImage: {&lt;br /&gt;
        warrior: &amp;quot;/images/0/0f/Bandeaurougehomme.png&amp;quot;,&lt;br /&gt;
        ninja: &amp;quot;/images/0/0e/Queuedechevalclair.png&amp;quot;,&lt;br /&gt;
        sura: &amp;quot;/images/3/37/Couperespectablerouge.png&amp;quot;,&lt;br /&gt;
        shaman: &amp;quot;/images/6/6a/Coupeeleganteclairfemme.png&amp;quot;,&lt;br /&gt;
        lycan: &amp;quot;/images/4/4e/Protectionfrontalerouge.png&amp;quot;,&lt;br /&gt;
      },&lt;br /&gt;
      categories: [&amp;quot;attacker&amp;quot;, &amp;quot;victim&amp;quot;],&lt;br /&gt;
      translateMonsters: defaultLang !== currentLanguage,&lt;br /&gt;
      attacker: {&lt;br /&gt;
        character: {&lt;br /&gt;
          count: 0,&lt;br /&gt;
          container: document.getElementById(&amp;quot;attacker-selection-characters&amp;quot;),&lt;br /&gt;
          elements: {},&lt;br /&gt;
        },&lt;br /&gt;
        monster: {&lt;br /&gt;
          count: 0,&lt;br /&gt;
          container: document.getElementById(&amp;quot;attacker-selection-monsters&amp;quot;),&lt;br /&gt;
          elements: {},&lt;br /&gt;
        },&lt;br /&gt;
        button: document.getElementById(&amp;quot;attacker-trigger&amp;quot;),&lt;br /&gt;
        defaultButtonContent: document.getElementById(&lt;br /&gt;
          &amp;quot;attacker-default-button-content&amp;quot;&lt;br /&gt;
        ),&lt;br /&gt;
        buttonContent: document.getElementById(&amp;quot;attacker-button-content&amp;quot;),&lt;br /&gt;
        container: document.getElementById(&amp;quot;attacker-selection&amp;quot;),&lt;br /&gt;
        selected: null,&lt;br /&gt;
      },&lt;br /&gt;
      victim: {&lt;br /&gt;
        character: {&lt;br /&gt;
          count: 0,&lt;br /&gt;
          container: document.getElementById(&amp;quot;victim-selection-characters&amp;quot;),&lt;br /&gt;
          elements: {},&lt;br /&gt;
        },&lt;br /&gt;
        monster: {&lt;br /&gt;
          count: 0,&lt;br /&gt;
          container: document.getElementById(&amp;quot;victim-selection-monsters&amp;quot;),&lt;br /&gt;
          elements: {},&lt;br /&gt;
        },&lt;br /&gt;
        stone: {&lt;br /&gt;
          count: 0,&lt;br /&gt;
          container: document.getElementById(&amp;quot;victim-selection-stones&amp;quot;),&lt;br /&gt;
          elements: {},&lt;br /&gt;
        },&lt;br /&gt;
        button: document.getElementById(&amp;quot;victim-trigger&amp;quot;),&lt;br /&gt;
        defaultButtonContent: document.getElementById(&lt;br /&gt;
          &amp;quot;victim-default-button-content&amp;quot;&lt;br /&gt;
        ),&lt;br /&gt;
        buttonContent: document.getElementById(&amp;quot;victim-button-content&amp;quot;),&lt;br /&gt;
        selected: null,&lt;br /&gt;
      },&lt;br /&gt;
      attackType: {&lt;br /&gt;
        container: document.getElementById(&amp;quot;attack-type-selection&amp;quot;),&lt;br /&gt;
        elements: [],&lt;br /&gt;
        defaultInput: document.getElementById(&amp;quot;physical-attack&amp;quot;),&lt;br /&gt;
        selectedText: &amp;quot;&amp;quot;,&lt;br /&gt;
      },&lt;br /&gt;
    },&lt;br /&gt;
    damageWeightedByType: {},&lt;br /&gt;
    scatterDataByType: {},&lt;br /&gt;
    damageByBonus: [],&lt;br /&gt;
    tableResultFight: document.getElementById(&amp;quot;result-table-fight&amp;quot;),&lt;br /&gt;
    tableResultHistory: document.getElementById(&amp;quot;result-table-history&amp;quot;),&lt;br /&gt;
    deleteFightTemplate: document.getElementById(&amp;quot;delete-fight-template&amp;quot;)&lt;br /&gt;
      .children[0],&lt;br /&gt;
    errorInformation: {},&lt;br /&gt;
    fightResultTitle: document.getElementById(&amp;quot;fight-result-title&amp;quot;),&lt;br /&gt;
    fightResultContainer: document.getElementById(&amp;quot;fight-result-container&amp;quot;),&lt;br /&gt;
    downLoadRawData: document.getElementById(&amp;quot;download-raw-data&amp;quot;),&lt;br /&gt;
    downLoadRawDataVariation: document.getElementById(&lt;br /&gt;
      &amp;quot;download-raw-data-variation&amp;quot;&lt;br /&gt;
    ),&lt;br /&gt;
    bonusVariationResultContainer: document.getElementById(&lt;br /&gt;
      &amp;quot;bonus-variation-result-container&amp;quot;&lt;br /&gt;
    ),&lt;br /&gt;
    reduceChartPointsContainer: document.getElementById(&lt;br /&gt;
      &amp;quot;reduce-chart-points-container&amp;quot;&lt;br /&gt;
    ),&lt;br /&gt;
    reduceChartPoints: document.getElementById(&amp;quot;reduce-chart-points&amp;quot;),&lt;br /&gt;
    plotDamage: document.getElementById(&amp;quot;plot-damage&amp;quot;),&lt;br /&gt;
    plotBonusVariation: document.getElementById(&amp;quot;plot-bonus-variation&amp;quot;),&lt;br /&gt;
    chartDescriptionContainer: document.getElementById(&lt;br /&gt;
      &amp;quot;chart-description-container&amp;quot;&lt;br /&gt;
    ),&lt;br /&gt;
    damageInfoContainer: document.getElementById(&amp;quot;damage-info-container&amp;quot;),&lt;br /&gt;
    uniqueDamageCounters: document.querySelectorAll(&amp;quot;.unique-damage-counter&amp;quot;),&lt;br /&gt;
    possibleDamageCounter: document.getElementById(&amp;quot;possible-damage-counter&amp;quot;),&lt;br /&gt;
    damageTime: document.getElementById(&amp;quot;damage-time&amp;quot;),&lt;br /&gt;
    displayTime: document.getElementById(&amp;quot;display-time&amp;quot;),&lt;br /&gt;
    simulationCounter: document.getElementById(&amp;quot;simulation-counter&amp;quot;),&lt;br /&gt;
    simulationTime: document.getElementById(&amp;quot;simulation-time&amp;quot;),&lt;br /&gt;
    numberFormats: {&lt;br /&gt;
      default: new Intl.NumberFormat(currentLanguage, {&lt;br /&gt;
        minimumFractionDigits: 0,&lt;br /&gt;
        maximumFractionDigits: 1,&lt;br /&gt;
      }),&lt;br /&gt;
      percent: new Intl.NumberFormat(currentLanguage, {&lt;br /&gt;
        style: &amp;quot;percent&amp;quot;,&lt;br /&gt;
        maximumFractionDigits: 3,&lt;br /&gt;
      }),&lt;br /&gt;
      second: new Intl.NumberFormat(currentLanguage, {&lt;br /&gt;
        style: &amp;quot;unit&amp;quot;,&lt;br /&gt;
        unit: &amp;quot;second&amp;quot;,&lt;br /&gt;
        unitDisplay: &amp;quot;long&amp;quot;,&lt;br /&gt;
        maximumFractionDigits: 3,&lt;br /&gt;
      }),&lt;br /&gt;
    },&lt;br /&gt;
    mapping: createMapping(),&lt;br /&gt;
    constants: constants,&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  addBattleData(battle);&lt;br /&gt;
  initResultTableHistory(battle);&lt;br /&gt;
  initDamageChart(battle, currentLanguage, defaultText);&lt;br /&gt;
  initBonusVariationChart(battle, currentLanguage, defaultText);&lt;br /&gt;
  reduceChartPointsListener(battle);&lt;br /&gt;
  downloadRawDataListener(battle);&lt;br /&gt;
&lt;br /&gt;
  return [characters, battle];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function parseText(input) {&lt;br /&gt;
  const regex = /\[\[(.*?)\]\]|([^\[]+)/g;&lt;br /&gt;
  const result = [];&lt;br /&gt;
&lt;br /&gt;
  input.replace(regex, (_, matchA, matchText) =&amp;gt; {&lt;br /&gt;
    if (matchA !== undefined) {&lt;br /&gt;
      result.push({&lt;br /&gt;
        text: matchA,&lt;br /&gt;
        category: matchA === &amp;quot;&amp;quot; ? &amp;quot;NOTRANSLATE&amp;quot; : &amp;quot;A&amp;quot;,&lt;br /&gt;
      });&lt;br /&gt;
    } else if (matchText) {&lt;br /&gt;
      result.push({ text: matchText, category: &amp;quot;#text&amp;quot; });&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  return result;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function translateText(general) {&lt;br /&gt;
  const nodesToTranslate = [&amp;quot;A&amp;quot;, &amp;quot;I&amp;quot;, &amp;quot;B&amp;quot;];&lt;br /&gt;
&lt;br /&gt;
  for (const element of document.querySelectorAll(&amp;quot;[data-t]&amp;quot;)) {&lt;br /&gt;
    const translateText = general[element.dataset.t];&lt;br /&gt;
&lt;br /&gt;
    if (!translateText) continue;&lt;br /&gt;
&lt;br /&gt;
    const childNodes = element.childNodes;&lt;br /&gt;
    const numChildren = childNodes.length;&lt;br /&gt;
&lt;br /&gt;
    if (numChildren === 1) {&lt;br /&gt;
      childNodes[0].textContent = translateText;&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    const parsedText = parseText(translateText);&lt;br /&gt;
    const numParsed = parsedText.length;&lt;br /&gt;
&lt;br /&gt;
    let childIndex = 0;&lt;br /&gt;
    let textIndex = 0;&lt;br /&gt;
&lt;br /&gt;
    while (childIndex &amp;lt; numChildren) {&lt;br /&gt;
      const child = childNodes[childIndex];&lt;br /&gt;
&lt;br /&gt;
      if (textIndex === numParsed) {&lt;br /&gt;
        console.warn(&amp;quot;Bad translation for element&amp;quot;, element);&lt;br /&gt;
        break;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      const parsed = parsedText[textIndex];&lt;br /&gt;
&lt;br /&gt;
      let childName = child.nodeName;&lt;br /&gt;
      const isNodeToTranslate = nodesToTranslate.includes(childName);&lt;br /&gt;
&lt;br /&gt;
      if (&lt;br /&gt;
        (childName === &amp;quot;A&amp;quot; &amp;amp;&amp;amp; child.firstChild?.nodeName === &amp;quot;IMG&amp;quot;) ||&lt;br /&gt;
        !(isNodeToTranslate || childName === &amp;quot;#text&amp;quot;) ||&lt;br /&gt;
        child.dataset?.notranslate&lt;br /&gt;
      ) {&lt;br /&gt;
        childName = &amp;quot;NOTRANSLATE&amp;quot;;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (&lt;br /&gt;
        childName === parsed.category ||&lt;br /&gt;
        (parsed.category === &amp;quot;A&amp;quot; &amp;amp;&amp;amp; isNodeToTranslate)&lt;br /&gt;
      ) {&lt;br /&gt;
        if (childName !== &amp;quot;NOTRANSLATE&amp;quot;) {&lt;br /&gt;
          child.textContent = parsed.text;&lt;br /&gt;
        }&lt;br /&gt;
        childIndex++;&lt;br /&gt;
        textIndex++;&lt;br /&gt;
      } else if (childName === &amp;quot;NOTRANSLATE&amp;quot;) {&lt;br /&gt;
        childIndex++;&lt;br /&gt;
      } else if (isNodeToTranslate) {&lt;br /&gt;
        element.insertBefore(document.createTextNode(parsed.text), child);&lt;br /&gt;
        textIndex++;&lt;br /&gt;
      } else {&lt;br /&gt;
        child.textContent = &amp;quot;&amp;quot;;&lt;br /&gt;
        childIndex++;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (textIndex &amp;lt; parsedText.length) {&lt;br /&gt;
      const textNode = document.createTextNode(parsedText[textIndex].text);&lt;br /&gt;
      element.appendChild(textNode);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function translateWeapons(weapons) {&lt;br /&gt;
  const characterCreation = document.getElementById(&amp;quot;character-creation&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  for (const weaponInput of characterCreation.elements[&amp;quot;weapon&amp;quot;]) {&lt;br /&gt;
    const weaponTranslation = weapons[weaponInput.value];&lt;br /&gt;
&lt;br /&gt;
    if (weaponTranslation) {&lt;br /&gt;
      weaponInput.parentElement.lastElementChild.textContent =&lt;br /&gt;
        weaponTranslation;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleSpecialIndexes(generalTranslations, specialIndexes) {&lt;br /&gt;
  const specialTranslations = {};&lt;br /&gt;
&lt;br /&gt;
  translation.special = specialTranslations;&lt;br /&gt;
&lt;br /&gt;
  for (const [generalIndex, specialKey] of Object.entries(specialIndexes)) {&lt;br /&gt;
    const translatedValue = generalTranslations[generalIndex];&lt;br /&gt;
&lt;br /&gt;
    if (translatedValue) {&lt;br /&gt;
      specialTranslations[specialKey] = translatedValue;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  translation.mapping = {&lt;br /&gt;
    &amp;quot;Demi-humain&amp;quot;: specialTranslations.halfHuman,&lt;br /&gt;
    Mal: specialTranslations.devil,&lt;br /&gt;
    Désert: specialTranslations.desert,&lt;br /&gt;
    Animal: specialTranslations.animal,&lt;br /&gt;
    Orc: specialTranslations.orc,&lt;br /&gt;
    Mystique: specialTranslations.mystic,&lt;br /&gt;
    &amp;quot;Mort-vivant&amp;quot;: specialTranslations.undead,&lt;br /&gt;
    Insecte: specialTranslations.insect,&lt;br /&gt;
    Zodiaque: specialTranslations.zodiac,&lt;br /&gt;
    &amp;quot;Aucun type&amp;quot;: specialTranslations.noType,&lt;br /&gt;
    Mêlée: specialTranslations.melee,&lt;br /&gt;
    Flèche: specialTranslations.arrow,&lt;br /&gt;
    Magique: specialTranslations.magic,&lt;br /&gt;
    DC: specialTranslations.skill,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function translateTitle() {&lt;br /&gt;
  const translatedTitle = translation.special.pageTitle;&lt;br /&gt;
&lt;br /&gt;
  if (translatedTitle) {&lt;br /&gt;
    document.querySelector(&amp;quot;h1&amp;quot;).textContent = translatedTitle;&lt;br /&gt;
    document.querySelector(&amp;quot;ul.subpage&amp;quot;).lastElementChild.textContent =&lt;br /&gt;
      translatedTitle;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function translateSummary(attempts = 5) {&lt;br /&gt;
  const tocContainer = document.getElementById(&amp;quot;toc&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (!tocContainer) {&lt;br /&gt;
    if (attempts &amp;gt; 0) {&lt;br /&gt;
      console.log(`Translating summary... Attempts left: ${attempts}`);&lt;br /&gt;
      setTimeout(() =&amp;gt; translateSummary(attempts - 1), 1000);&lt;br /&gt;
    }&lt;br /&gt;
    return;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  const { toc, hide } = translation.special;&lt;br /&gt;
&lt;br /&gt;
  const heading = tocContainer.querySelector(&amp;quot;h2&amp;quot;);&lt;br /&gt;
  const toggleLink = tocContainer.querySelector(&amp;quot;a.togglelink&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (heading) heading.textContent = toc;&lt;br /&gt;
  if (toggleLink) toggleLink.textContent = hide;&lt;br /&gt;
&lt;br /&gt;
  for (const link of tocContainer.querySelectorAll(&amp;quot;ul a&amp;quot;)) {&lt;br /&gt;
    const hash = link.hash.substring(1);&lt;br /&gt;
    const title = document.getElementById(hash);&lt;br /&gt;
&lt;br /&gt;
    if (title) {&lt;br /&gt;
      const toctext = link.querySelector(&amp;quot;span.toctext&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
      if (toctext?.firstElementChild) {&lt;br /&gt;
        toctext.firstElementChild.textContent = title.textContent;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function translateDefaultText(defaultText) {&lt;br /&gt;
  const specialTranslations = translation.special;&lt;br /&gt;
&lt;br /&gt;
  for (const key of Object.keys(defaultText)) {&lt;br /&gt;
    if (specialTranslations.hasOwnProperty(key)) {&lt;br /&gt;
      defaultText[key] = specialTranslations[key];&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function translatePage(defaultText, currentLanguage) {&lt;br /&gt;
  const mwContent = document.querySelector(&amp;quot;.mw-content-ltr&amp;quot;);&lt;br /&gt;
  const { general, weapons } = translation;&lt;br /&gt;
  const specialIndexes = {&lt;br /&gt;
    471: &amp;quot;placeholder&amp;quot;,&lt;br /&gt;
    473: &amp;quot;boss&amp;quot;,&lt;br /&gt;
    474: &amp;quot;pageTitle&amp;quot;,&lt;br /&gt;
    475: &amp;quot;toc&amp;quot;,&lt;br /&gt;
    476: &amp;quot;hide&amp;quot;,&lt;br /&gt;
    502: &amp;quot;unsavedWarning&amp;quot;,&lt;br /&gt;
    503: &amp;quot;deleteWarning&amp;quot;,&lt;br /&gt;
    504: &amp;quot;pseudo&amp;quot;,&lt;br /&gt;
    481: &amp;quot;damage&amp;quot;,&lt;br /&gt;
    505: &amp;quot;percentage&amp;quot;,&lt;br /&gt;
    506: &amp;quot;miss&amp;quot;,&lt;br /&gt;
    507: &amp;quot;normalHit&amp;quot;,&lt;br /&gt;
    508: &amp;quot;criticalHit&amp;quot;,&lt;br /&gt;
    509: &amp;quot;piercingHit&amp;quot;,&lt;br /&gt;
    510: &amp;quot;criticalPiercingHit&amp;quot;,&lt;br /&gt;
    511: &amp;quot;damageRepartition&amp;quot;,&lt;br /&gt;
    512: &amp;quot;averageDamage&amp;quot;,&lt;br /&gt;
    513: &amp;quot;damageAugmentation&amp;quot;,&lt;br /&gt;
    514: &amp;quot;bonusVariationTitle&amp;quot;,&lt;br /&gt;
    489: &amp;quot;halfHuman&amp;quot;,&lt;br /&gt;
    490: &amp;quot;devil&amp;quot;,&lt;br /&gt;
    491: &amp;quot;desert&amp;quot;,&lt;br /&gt;
    492: &amp;quot;animal&amp;quot;,&lt;br /&gt;
    493: &amp;quot;orc&amp;quot;,&lt;br /&gt;
    494: &amp;quot;mystic&amp;quot;,&lt;br /&gt;
    495: &amp;quot;undead&amp;quot;,&lt;br /&gt;
    496: &amp;quot;insect&amp;quot;,&lt;br /&gt;
    497: &amp;quot;zodiac&amp;quot;,&lt;br /&gt;
    515: &amp;quot;noType&amp;quot;,&lt;br /&gt;
    498: &amp;quot;melee&amp;quot;,&lt;br /&gt;
    499: &amp;quot;arrow&amp;quot;,&lt;br /&gt;
    500: &amp;quot;magic&amp;quot;,&lt;br /&gt;
    516: &amp;quot;skill&amp;quot;,&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  translateText(general);&lt;br /&gt;
  translateWeapons(weapons);&lt;br /&gt;
  handleSpecialIndexes(general, specialIndexes);&lt;br /&gt;
  translateTitle();&lt;br /&gt;
  translateSummary();&lt;br /&gt;
  translateDefaultText(defaultText);&lt;br /&gt;
&lt;br /&gt;
  if (mwContent) {&lt;br /&gt;
    mwContent.setAttribute(&amp;quot;lang&amp;quot;, currentLanguage);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getDefaultText() {&lt;br /&gt;
  return {&lt;br /&gt;
    unsavedWarning:&lt;br /&gt;
      &amp;quot;Voulez-vous continuer ? Les dernières modifications ne seront pas sauvegardées.&amp;quot;,&lt;br /&gt;
    deleteWarning:&lt;br /&gt;
      &amp;quot;Voulez-vous vraiment supprimer définitivement le personnage [[]] ?&amp;quot;,&lt;br /&gt;
    pseudo: &amp;quot;Pseudo&amp;quot;,&lt;br /&gt;
    damage: &amp;quot;Dégâts&amp;quot;,&lt;br /&gt;
    percentage: &amp;quot;Pourcentage&amp;quot;,&lt;br /&gt;
    miss: &amp;quot;Miss&amp;quot;,&lt;br /&gt;
    normalHit: &amp;quot;Coup classique&amp;quot;,&lt;br /&gt;
    criticalHit: &amp;quot;Coup critique&amp;quot;,&lt;br /&gt;
    piercingHit: &amp;quot;Coup perçant&amp;quot;,&lt;br /&gt;
    criticalPiercingHit: &amp;quot;Coup critique perçant&amp;quot;,&lt;br /&gt;
    damageRepartition: &amp;quot;Distribution des dégâts&amp;quot;,&lt;br /&gt;
    averageDamage: &amp;quot;Dégâts moyens&amp;quot;,&lt;br /&gt;
    damageAugmentation: &amp;quot;Augmentation des dégâts&amp;quot;,&lt;br /&gt;
    bonusVariationTitle:&lt;br /&gt;
      &amp;quot;Évolution des dégâts moyens[[]]par rapport à la valeur d'un bonus&amp;quot;,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setLanguage(radios, lang, url, reload = false) {&lt;br /&gt;
  url.searchParams.set(&amp;quot;lang&amp;quot;, lang);&lt;br /&gt;
  updateLastLang(lang);&lt;br /&gt;
&lt;br /&gt;
  if (reload) {&lt;br /&gt;
    window.location.href = url.toString();&lt;br /&gt;
  } else {&lt;br /&gt;
    radios.value = lang;&lt;br /&gt;
    history.replaceState(null, &amp;quot;&amp;quot;, url);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getCurrentLanguage(defaultLang) {&lt;br /&gt;
  const url = new URL(window.location.href);&lt;br /&gt;
  const URLlang = url.searchParams.get(&amp;quot;lang&amp;quot;);&lt;br /&gt;
  const lastLang = getLastLang();&lt;br /&gt;
  const browserLang = navigator.language.split(&amp;quot;-&amp;quot;)[0];&lt;br /&gt;
  const languageSelection = document.getElementById(&amp;quot;language-selection&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (!languageSelection) {&lt;br /&gt;
    return defaultLang;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  const radios = languageSelection.elements[&amp;quot;country&amp;quot;];&lt;br /&gt;
&lt;br /&gt;
  if (!radios) {&lt;br /&gt;
    return defaultLang;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  languageSelection.addEventListener(&amp;quot;change&amp;quot;, changeLanguage);&lt;br /&gt;
&lt;br /&gt;
  function changeLanguage(event) {&lt;br /&gt;
    const newLang = event.target.value;&lt;br /&gt;
    const newUrl = new URL(window.location.href);&lt;br /&gt;
    setLanguage(radios, newLang, newUrl, true);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  const allowedLanguages = Array.from(radios).map((input) =&amp;gt; input.value);&lt;br /&gt;
&lt;br /&gt;
  for (const lang of [URLlang, lastLang, browserLang]) {&lt;br /&gt;
    if (allowedLanguages.includes(lang)) {&lt;br /&gt;
      setLanguage(radios, lang, url);&lt;br /&gt;
      return lang;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return defaultLang;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadStyle(src) {&lt;br /&gt;
  var link = document.createElement(&amp;quot;link&amp;quot;);&lt;br /&gt;
  link.href = src;&lt;br /&gt;
  link.rel = &amp;quot;stylesheet&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  document.head.appendChild(link);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
async function addScript(src) {&lt;br /&gt;
  return new Promise((resolve, reject) =&amp;gt; {&lt;br /&gt;
    const script = document.createElement(&amp;quot;script&amp;quot;);&lt;br /&gt;
    script.src = src;&lt;br /&gt;
    script.async = true;&lt;br /&gt;
&lt;br /&gt;
    script.onload = () =&amp;gt; resolve();&lt;br /&gt;
    script.onerror = () =&amp;gt; reject(new Error(`Failed to load script: ${src}`));&lt;br /&gt;
&lt;br /&gt;
    document.head.appendChild(script);&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
(async function () {&lt;br /&gt;
  const basePath = &amp;quot;/index.php?title=Utilisateur:Ankhseram/&amp;quot;;&lt;br /&gt;
  const dataScript = `${basePath}WeaponsAndMonsters.js&amp;amp;action=raw&amp;amp;ctype=text/javascript`;&lt;br /&gt;
  const simulatorStyle = `${basePath}SimulatorStyle.css&amp;amp;action=raw&amp;amp;ctype=text/css`;&lt;br /&gt;
  const chartLibrary = &amp;quot;https://cdn.jsdelivr.net/npm/chart.js&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  const defaultLang = &amp;quot;fr&amp;quot;;&lt;br /&gt;
  const defaultText = getDefaultText();&lt;br /&gt;
  const currentLanguage = getCurrentLanguage(defaultLang);&lt;br /&gt;
&lt;br /&gt;
  loadStyle(simulatorStyle);&lt;br /&gt;
&lt;br /&gt;
  let translationScript;&lt;br /&gt;
&lt;br /&gt;
  if (currentLanguage !== defaultLang) {&lt;br /&gt;
    translationScript = `${basePath}Calculator/${currentLanguage}.js&amp;amp;action=raw&amp;amp;ctype=text/javascript`;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  const scriptsToLoad = [addScript(chartLibrary), addScript(dataScript)];&lt;br /&gt;
&lt;br /&gt;
  if (translationScript) {&lt;br /&gt;
    scriptsToLoad.push(addScript(translationScript));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  await Promise.all(scriptsToLoad);&lt;br /&gt;
&lt;br /&gt;
  if (translationScript) {&lt;br /&gt;
    translatePage(defaultText, currentLanguage);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  const [characters, battle] = createDamageCalculatorInformation(&lt;br /&gt;
    defaultLang,&lt;br /&gt;
    currentLanguage,&lt;br /&gt;
    defaultText&lt;br /&gt;
  );&lt;br /&gt;
  characterManagement(characters, battle);&lt;br /&gt;
  monsterManagement(characters, battle);&lt;br /&gt;
  updateBattleChoice(characters, battle.battleChoice);&lt;br /&gt;
  createBattle(characters, battle);&lt;br /&gt;
})();&lt;/div&gt;</summary>
		<author><name>Dexter</name></author>
		
	</entry>
	<entry>
		<id>https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Common.js&amp;diff=106869</id>
		<title>MediaWiki:Common.js</title>
		<link rel="alternate" type="text/html" href="https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Common.js&amp;diff=106869"/>
		<updated>2025-03-19T15:41:12Z</updated>

		<summary type="html">&lt;p&gt;Dexter : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;/* Tout le JavaScript ici sera chargé avec chaque page accédée par n’importe quel utilisateur. */&lt;br /&gt;
&lt;br /&gt;
/* =====================================&lt;br /&gt;
DECLARATIONS DES FONCTIONS ET PROCEDURES&lt;br /&gt;
======================================== */&lt;br /&gt;
&lt;br /&gt;
function showElement(element) {&lt;br /&gt;
  element.classList.remove(&amp;quot;tabber-noactive&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function hideElement(element) {&lt;br /&gt;
  element.classList.add(&amp;quot;tabber-noactive&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function toggleElement(element) {&lt;br /&gt;
  element.classList.toggle(&amp;quot;tabber-noactive&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* Favicon */&lt;br /&gt;
function fixInsecureFavicon() {&lt;br /&gt;
  document.querySelector('link[rel=&amp;quot;shortcut icon&amp;quot;]').href =&lt;br /&gt;
    &amp;quot;https://gf1.geo.gfsrv.net/cdn98/191b803adbf82f4b8febe3a2c38c2c.ico&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* Liste des équipements */&lt;br /&gt;
function changeEquipementDisplay(container) {&lt;br /&gt;
  var switchButton = container.querySelector(&amp;quot;.button&amp;quot;);&lt;br /&gt;
  var content = container.nextElementSibling;&lt;br /&gt;
&lt;br /&gt;
  switchButton.addEventListener(&amp;quot;click&amp;quot;, function () {&lt;br /&gt;
    switchButton.classList.toggle(&amp;quot;tabber-active&amp;quot;);&lt;br /&gt;
    toggleElement(content);&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* Enlève l'animation de chargement et affiche le contenu de la page lorsque c'est nécessaire */&lt;br /&gt;
function removeLoadingAnimation() {&lt;br /&gt;
  var loadingAnimation = document.getElementById(&amp;quot;loading-animation&amp;quot;);&lt;br /&gt;
  var showAfterLoading = document.getElementById(&amp;quot;show-after-loading&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (loadingAnimation) {&lt;br /&gt;
    hideElement(loadingAnimation);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (showAfterLoading) {&lt;br /&gt;
    showElement(showAfterLoading);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* BOUTON RETOUR VERS LE HAUT */&lt;br /&gt;
function addButtonTop() {&lt;br /&gt;
  var contentText = document.querySelector(&amp;quot;div#mw-content-text&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (contentText !== null) {&lt;br /&gt;
    var divButtonTop = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
    divButtonTop.classList.add(&amp;quot;top-button&amp;quot;);&lt;br /&gt;
    contentText.appendChild(divButtonTop);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function buttonTop() {&lt;br /&gt;
  var balise = document.querySelector(&amp;quot;div#mw-page-header-links&amp;quot;);&lt;br /&gt;
  var topButton = document.querySelector(&amp;quot;.top-button&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (balise !== null) {&lt;br /&gt;
    var options = {&lt;br /&gt;
      root: null,&lt;br /&gt;
      rootMargin: &amp;quot;0px&amp;quot;,&lt;br /&gt;
      threshold: 0,&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    var observer = new IntersectionObserver(callback, options);&lt;br /&gt;
    observer.observe(balise);&lt;br /&gt;
&lt;br /&gt;
    function callback(entries) {&lt;br /&gt;
      entries.forEach(function (entry) {&lt;br /&gt;
        if (entry.isIntersecting) {&lt;br /&gt;
          topButton.classList.remove(&amp;quot;show-button&amp;quot;);&lt;br /&gt;
        } else {&lt;br /&gt;
          topButton.classList.add(&amp;quot;show-button&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
      });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    topButton.addEventListener(&amp;quot;click&amp;quot;, function () {&lt;br /&gt;
      document.documentElement.scrollTo({&lt;br /&gt;
        top: 0,&lt;br /&gt;
      });&lt;br /&gt;
    });&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* Cookies */&lt;br /&gt;
function cookies() {&lt;br /&gt;
  var req = new XMLHttpRequest();&lt;br /&gt;
  req.addEventListener(&amp;quot;load&amp;quot;, function (ev) {&lt;br /&gt;
    if (this.status &amp;gt;= 200 &amp;amp;&amp;amp; this.status &amp;lt; 300) {&lt;br /&gt;
      var data = JSON.parse(this.responseText);&lt;br /&gt;
      if (data.hasOwnProperty(&amp;quot;version&amp;quot;)) {&lt;br /&gt;
        var gdpr = document.createElement(&amp;quot;script&amp;quot;);&lt;br /&gt;
        gdpr.src =&lt;br /&gt;
          &amp;quot;https://s3-static.geo.gfsrv.net/cookiebanner/&amp;quot; +&lt;br /&gt;
          data.version +&lt;br /&gt;
          &amp;quot;/cookie.min.js&amp;quot;;&lt;br /&gt;
        document.head.appendChild(gdpr);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
  req.open(&amp;quot;GET&amp;quot;, &amp;quot;https://s3-static.geo.gfsrv.net/cookiebanner/version.json&amp;quot;);&lt;br /&gt;
  req.send();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* =======================================&lt;br /&gt;
FONCTION GLOBALE&lt;br /&gt;
Exécutée une fois au chargement de la page&lt;br /&gt;
========================================== */&lt;br /&gt;
&lt;br /&gt;
(function () {&lt;br /&gt;
  fixInsecureFavicon();&lt;br /&gt;
&lt;br /&gt;
  var urlStart = &amp;quot;/index.php?title=MediaWiki:Script/&amp;quot;;&lt;br /&gt;
  var urlEnd = &amp;quot;.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&amp;quot;;&lt;br /&gt;
  var loadScripts = document.querySelectorAll(&amp;quot;div[data-load-javascript]&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  var equipmentContainer = document.querySelectorAll(&lt;br /&gt;
    &amp;quot;div#mw-content-text .list-equip&amp;quot;&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  equipmentContainer.forEach(function (container) {&lt;br /&gt;
    changeEquipementDisplay(container);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  /* Charge des scripts spécifiques au chargement de certaines pages */&lt;br /&gt;
  if (loadScripts.length) {&lt;br /&gt;
    var allowedScripts = {&lt;br /&gt;
      Tabber: true,&lt;br /&gt;
      Skills: true,&lt;br /&gt;
      Modal: true,&lt;br /&gt;
      Switch: true,&lt;br /&gt;
      Loot: true,&lt;br /&gt;
      Map: true,&lt;br /&gt;
      Filter: true,&lt;br /&gt;
      Calculator: true,&lt;br /&gt;
      Element: true,&lt;br /&gt;
      Pets: true,&lt;br /&gt;
      Colorblind: true,&lt;br /&gt;
    };&lt;br /&gt;
    var scriptsToLoad = [];&lt;br /&gt;
&lt;br /&gt;
    loadScripts.forEach(function (scriptElement) {&lt;br /&gt;
      var scriptName = scriptElement.dataset.loadJavascript;&lt;br /&gt;
&lt;br /&gt;
      if (allowedScripts[scriptName]) {&lt;br /&gt;
        allowedScripts[scriptName] = false;&lt;br /&gt;
        scriptsToLoad.push(scriptName);&lt;br /&gt;
      }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    if (scriptsToLoad.length) {&lt;br /&gt;
      var firstScriptName = scriptsToLoad[0];&lt;br /&gt;
&lt;br /&gt;
      if (firstScriptName === &amp;quot;Element&amp;quot;) {&lt;br /&gt;
        scriptsToLoad.shift()&lt;br /&gt;
        $.getScript(urlStart + firstScriptName + urlEnd, function () {&lt;br /&gt;
          injectCustomElements();&lt;br /&gt;
          loadNextScripts();&lt;br /&gt;
        });&lt;br /&gt;
      } else {&lt;br /&gt;
        loadNextScripts();&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function loadNextScripts() {&lt;br /&gt;
      scriptsToLoad.forEach(function (scriptName) {&lt;br /&gt;
        mw.loader.load(urlStart + scriptName + urlEnd);&lt;br /&gt;
      });&lt;br /&gt;
&lt;br /&gt;
      removeLoadingAnimation();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (mw.config.get(&amp;quot;wgUserName&amp;quot;)) {&lt;br /&gt;
    mw.loader.load(urlStart + &amp;quot;Redactor&amp;quot; + urlEnd);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  addButtonTop();&lt;br /&gt;
  buttonTop();&lt;br /&gt;
  cookies();&lt;br /&gt;
})();&lt;/div&gt;</summary>
		<author><name>Dexter</name></author>
		
	</entry>
	<entry>
		<id>https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Script/Calculator.js&amp;diff=106784</id>
		<title>MediaWiki:Script/Calculator.js</title>
		<link rel="alternate" type="text/html" href="https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Script/Calculator.js&amp;diff=106784"/>
		<updated>2025-03-14T05:23:12Z</updated>

		<summary type="html">&lt;p&gt;Dexter : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;function removeAccent(str) {&lt;br /&gt;
  return str.normalize(&amp;quot;NFD&amp;quot;).replace(/[\u0300-\u036f]/g, &amp;quot;&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function pseudoFormat(str) {&lt;br /&gt;
  return removeAccent(str).replace(/[^A-Za-z0-9 \(\)\+_-]+/g, &amp;quot;&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isValueInArray(value, array) {&lt;br /&gt;
  return array.indexOf(value) !== -1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function splitFirst(value, delimiter) {&lt;br /&gt;
  var parts = value.split(delimiter);&lt;br /&gt;
  var first = parts[0];&lt;br /&gt;
  var rest = parts.slice(1).join(delimiter);&lt;br /&gt;
  return [first, rest];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function copyObject(object) {&lt;br /&gt;
  var copy = {};&lt;br /&gt;
  for (var key in object) {&lt;br /&gt;
    copy[key] = object[key];&lt;br /&gt;
  }&lt;br /&gt;
  return copy;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function compareNumbers(a, b) {&lt;br /&gt;
  return b - a;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isChecked(attribute) {&lt;br /&gt;
  return attribute === &amp;quot;on&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function floorMultiplication(firstFactor, secondFactor) {&lt;br /&gt;
  return Math.floor((firstFactor * secondFactor).toFixed(8));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function truncateNumber(number, precision) {&lt;br /&gt;
  return Math.floor(number * 10 ** precision) / 10 ** precision;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function newChangeEvent() {&lt;br /&gt;
  return new Event(&amp;quot;change&amp;quot;, { bubbles: true });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function openTargetTab(target) {&lt;br /&gt;
  var tabberContainer = target.closest(&amp;quot;.tabber-container&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (!tabberContainer) {&lt;br /&gt;
    return;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var [buttonsContainer, tabsContainer] = tabberContainer.children;&lt;br /&gt;
  var buttons = buttonsContainer.children;&lt;br /&gt;
  var tabs = tabsContainer.children;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; tabs.length; index++) {&lt;br /&gt;
    var tab = tabs[index];&lt;br /&gt;
    if (tab.contains(target) &amp;amp;&amp;amp; !tab.checkVisibility()) {&lt;br /&gt;
      buttons[index].click();&lt;br /&gt;
      break;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function openTargetCollapsible(target) {&lt;br /&gt;
  var collapsible = target.closest(&amp;quot;.improved-collapsible&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (!collapsible) {&lt;br /&gt;
    return;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var span = collapsible.firstElementChild;&lt;br /&gt;
&lt;br /&gt;
  if (!span.classList.contains(&amp;quot;mw-collapsible-toggle-expanded&amp;quot;)) {&lt;br /&gt;
    span.click();&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function editTableResultRow(row, valuesToDisplay, numberFormat) {&lt;br /&gt;
  row.innerHTML = &amp;quot;&amp;quot;;&lt;br /&gt;
  for (var index = 0; index &amp;lt; valuesToDisplay.length; index++) {&lt;br /&gt;
    var cell = row.insertCell();&lt;br /&gt;
    var textContent;&lt;br /&gt;
&lt;br /&gt;
    if (index &amp;gt;= 3) {&lt;br /&gt;
      textContent = numberFormat.format(valuesToDisplay[index]);&lt;br /&gt;
    } else {&lt;br /&gt;
      textContent = valuesToDisplay[index];&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    cell.textContent = textContent;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return row;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addRowToTableResultHistory(&lt;br /&gt;
  tableResultHistory,&lt;br /&gt;
  valuesToDisplay,&lt;br /&gt;
  deleteFightTemplate,&lt;br /&gt;
  numberFormat&lt;br /&gt;
) {&lt;br /&gt;
  var row = tableResultHistory.insertRow();&lt;br /&gt;
  editTableResultRow(row, valuesToDisplay, numberFormat);&lt;br /&gt;
  var cell = row.insertCell();&lt;br /&gt;
  cell.appendChild(deleteFightTemplate.cloneNode(true));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function processSavedDamage(savedDamage, damageWeightedByType, battleValues) {&lt;br /&gt;
  const { damageTypeWeights, attackTypeMapping } = battleValues;&lt;br /&gt;
&lt;br /&gt;
  for (const key in savedDamage) {&lt;br /&gt;
    const [weight, damageByType] = savedDamage[key];&lt;br /&gt;
&lt;br /&gt;
    for (let index = 0; index &amp;lt; 4; index++) {&lt;br /&gt;
      const damageWeighted = damageWeightedByType[attackTypeMapping[index]];&lt;br /&gt;
      const damageByTypeIndex = damageByType[index];&lt;br /&gt;
&lt;br /&gt;
      if (damageByTypeIndex.length === 0) continue;&lt;br /&gt;
&lt;br /&gt;
      const currentWeight =&lt;br /&gt;
        (weight * damageTypeWeights[index]) / damageByTypeIndex.length;&lt;br /&gt;
&lt;br /&gt;
      for (const damage of damageByTypeIndex) {&lt;br /&gt;
        damageWeighted[damage] = (damageWeighted[damage] || 0) + currentWeight;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcMeanDamage(damageWeightedByType, totalCardinal) {&lt;br /&gt;
  var sumDamage = 0;&lt;br /&gt;
&lt;br /&gt;
  for (var damageTypeName in damageWeightedByType) {&lt;br /&gt;
    if (damageTypeName === &amp;quot;miss&amp;quot;) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var damageWeighted = damageWeightedByType[damageTypeName];&lt;br /&gt;
&lt;br /&gt;
    for (var damage in damageWeighted) {&lt;br /&gt;
      sumDamage += damage * damageWeighted[damage];&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return sumDamage / totalCardinal;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function prepareDamageData(damageWeightedByType, attackValues) {&lt;br /&gt;
  const totalCardinal = attackValues.totalCardinal;&lt;br /&gt;
  const scatterDataByType = {};&lt;br /&gt;
  const criticalAttackRange = attackValues.criticalAttackRange;&lt;br /&gt;
&lt;br /&gt;
  let minDamage = Infinity;&lt;br /&gt;
  let maxDamage = 0;&lt;br /&gt;
  let sumDamage = 0;&lt;br /&gt;
&lt;br /&gt;
  let possibleDamageCount = 0;&lt;br /&gt;
  let possibleDamageCountTemp = 0;&lt;br /&gt;
  let uniqueDamageCount = 0;&lt;br /&gt;
&lt;br /&gt;
  for (const damageTypeName in damageWeightedByType) {&lt;br /&gt;
    if (damageTypeName === &amp;quot;miss&amp;quot;) {&lt;br /&gt;
      scatterDataByType.miss = damageWeightedByType.miss;&lt;br /&gt;
      possibleDamageCount++;&lt;br /&gt;
      uniqueDamageCount++;&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
    const damageWeighted = damageWeightedByType[damageTypeName];&lt;br /&gt;
    const scatterData = [];&lt;br /&gt;
&lt;br /&gt;
    scatterDataByType[damageTypeName] = scatterData;&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      (damageTypeName === &amp;quot;criticalHit&amp;quot; ||&lt;br /&gt;
        damageTypeName === &amp;quot;criticalPiercingHit&amp;quot;) &amp;amp;&amp;amp;&lt;br /&gt;
      criticalAttackRange&lt;br /&gt;
    ) {&lt;br /&gt;
      possibleDamageCountTemp =&lt;br /&gt;
        attackValues.possibleDamageCount * criticalAttackRange.length;&lt;br /&gt;
    } else {&lt;br /&gt;
      possibleDamageCountTemp = attackValues.possibleDamageCount;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    for (let damage in damageWeighted) {&lt;br /&gt;
      damage = +damage;&lt;br /&gt;
&lt;br /&gt;
      if (damage &amp;lt; minDamage) {&lt;br /&gt;
        minDamage = damage;&lt;br /&gt;
      }&lt;br /&gt;
      if (damage &amp;gt; maxDamage) {&lt;br /&gt;
        maxDamage = damage;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      const weight = damageWeighted[damage];&lt;br /&gt;
      const probability = weight / totalCardinal;&lt;br /&gt;
&lt;br /&gt;
      sumDamage += damage * weight;&lt;br /&gt;
      damageWeighted[damage] = probability;&lt;br /&gt;
      scatterData.push({ x: damage, y: probability });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    const scatterDataLength = scatterData.length;&lt;br /&gt;
&lt;br /&gt;
    if (!scatterDataLength) {&lt;br /&gt;
      delete scatterDataByType[damageTypeName];&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    possibleDamageCount += possibleDamageCountTemp;&lt;br /&gt;
    uniqueDamageCount += scatterDataLength;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (minDamage === Infinity) {&lt;br /&gt;
    minDamage = 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  attackValues.possibleDamageCount = possibleDamageCount;&lt;br /&gt;
&lt;br /&gt;
  return [&lt;br /&gt;
    sumDamage / totalCardinal,&lt;br /&gt;
    minDamage,&lt;br /&gt;
    maxDamage,&lt;br /&gt;
    scatterDataByType,&lt;br /&gt;
    uniqueDamageCount,&lt;br /&gt;
  ];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function aggregateDamage(scatterData, maxPoints) {&lt;br /&gt;
  var dataLength = scatterData.length;&lt;br /&gt;
  var remainingData = dataLength;&lt;br /&gt;
  var aggregateScatterData = [];&lt;br /&gt;
&lt;br /&gt;
  for (var groupIndex = 0; groupIndex &amp;lt; maxPoints; groupIndex++) {&lt;br /&gt;
    var groupLength = Math.floor(remainingData / (maxPoints - groupIndex));&lt;br /&gt;
    var startIndex = dataLength - remainingData;&lt;br /&gt;
    var aggregateDamage = 0;&lt;br /&gt;
    var aggregateProbability = 0;&lt;br /&gt;
&lt;br /&gt;
    for (var index = startIndex; index &amp;lt; startIndex + groupLength; index++) {&lt;br /&gt;
      var { x: damage, y: probability } = scatterData[index];&lt;br /&gt;
      aggregateDamage += damage * probability;&lt;br /&gt;
      aggregateProbability += probability;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    aggregateScatterData.push({&lt;br /&gt;
      x: aggregateDamage / aggregateProbability,&lt;br /&gt;
      y: aggregateProbability,&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    remainingData -= groupLength;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return aggregateScatterData;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addToDamageChart(battle, scatterDataByType) {&lt;br /&gt;
  const { chart, datasetsStyle, maxPoints, reduceChartPointsContainer } =&lt;br /&gt;
    battle.damageChart;&lt;br /&gt;
  const isReducePointsChecked = battle.reduceChartPoints.checked;&lt;br /&gt;
  const datasets = chart.data.datasets;&lt;br /&gt;
&lt;br /&gt;
  let isFirstDataset = true;&lt;br /&gt;
&lt;br /&gt;
  datasets.length = 0;&lt;br /&gt;
&lt;br /&gt;
  for (let index = 0; index &amp;lt; datasetsStyle.length; index++) {&lt;br /&gt;
    const dataset = copyObject(datasetsStyle[index]);&lt;br /&gt;
&lt;br /&gt;
    if (!scatterDataByType.hasOwnProperty(dataset.name)) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    const scatterData = scatterDataByType[dataset.name];&lt;br /&gt;
    const canBeReduced = scatterData.length &amp;gt; 2 * maxPoints;&lt;br /&gt;
&lt;br /&gt;
    dataset.hidden = !isFirstDataset;&lt;br /&gt;
    dataset.canBeReduced = canBeReduced;&lt;br /&gt;
&lt;br /&gt;
    if (canBeReduced &amp;amp;&amp;amp; isReducePointsChecked) {&lt;br /&gt;
      dataset.data = aggregateDamage(scatterData, maxPoints);&lt;br /&gt;
    } else {&lt;br /&gt;
      dataset.data = scatterData;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isFirstDataset) {&lt;br /&gt;
      isFirstDataset = false;&lt;br /&gt;
&lt;br /&gt;
      if (canBeReduced) {&lt;br /&gt;
        showElement(reduceChartPointsContainer);&lt;br /&gt;
&lt;br /&gt;
        if (!isReducePointsChecked) {&lt;br /&gt;
          handleChartAnimations(chart, false);&lt;br /&gt;
        }&lt;br /&gt;
      } else {&lt;br /&gt;
        hideElement(reduceChartPointsContainer);&lt;br /&gt;
        handleChartAnimations(chart, true);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    datasets.push(dataset);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  chart.data.missPercentage = scatterDataByType.miss;&lt;br /&gt;
  chart.update();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addToBonusVariationChart(&lt;br /&gt;
  damageByBonus,&lt;br /&gt;
  augmentationByBonus,&lt;br /&gt;
  xLabel,&lt;br /&gt;
  chart&lt;br /&gt;
) {&lt;br /&gt;
  chart.data.datasets[0].data = damageByBonus;&lt;br /&gt;
  chart.data.datasets[1].data = augmentationByBonus;&lt;br /&gt;
  chart.options.scales.x.title.text = xLabel;&lt;br /&gt;
  chart.update();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleChartAnimations(chart, addAnimations) {&lt;br /&gt;
  chart.options.animation = addAnimations;&lt;br /&gt;
  chart.options.animations.colors = addAnimations;&lt;br /&gt;
  chart.options.animations.x = addAnimations;&lt;br /&gt;
  chart.options.transitions.active.animation.duration = addAnimations * 1000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateDamageChartDescription(battle, uniqueDamageCount) {&lt;br /&gt;
  const {&lt;br /&gt;
    chartDescriptionContainer,&lt;br /&gt;
    uniqueDamageCounters,&lt;br /&gt;
    numberFormats: { default: defaultFormat },&lt;br /&gt;
  } = battle;&lt;br /&gt;
&lt;br /&gt;
  if (uniqueDamageCount &amp;gt; 1) {&lt;br /&gt;
    uniqueDamageCounters.forEach(function (element) {&lt;br /&gt;
      element.textContent = defaultFormat.format(uniqueDamageCount);&lt;br /&gt;
    });&lt;br /&gt;
    showElement(chartDescriptionContainer);&lt;br /&gt;
  } else {&lt;br /&gt;
    hideElement(chartDescriptionContainer);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getMonsterName(monsterVnum) {&lt;br /&gt;
  var monsterAttributes = monsterData[monsterVnum];&lt;br /&gt;
  return monsterAttributes[monsterAttributes.length - 1];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getTranslatedMonsterName(monsterVnum) {&lt;br /&gt;
  return translation.monsters[monsterVnum];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterClass(selectedRace, classChoice, selectValueIsChanged = false) {&lt;br /&gt;
  for (var radioNode of classChoice) {&lt;br /&gt;
    var radioGrandParent = radioNode.parentElement.parentElement;&lt;br /&gt;
&lt;br /&gt;
    if (radioNode.getAttribute(&amp;quot;data-race&amp;quot;) === selectedRace) {&lt;br /&gt;
      if (!selectValueIsChanged) {&lt;br /&gt;
        radioNode.checked = true;&lt;br /&gt;
        selectValueIsChanged = true;&lt;br /&gt;
      }&lt;br /&gt;
      showElement(radioGrandParent);&lt;br /&gt;
    } else {&lt;br /&gt;
      hideElement(radioGrandParent);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterWeapon(&lt;br /&gt;
  selectedRace,&lt;br /&gt;
  weaponElement,&lt;br /&gt;
  weaponCategory,&lt;br /&gt;
  allowedWeaponsPerRace,&lt;br /&gt;
  selectValueIsChanged = false&lt;br /&gt;
) {&lt;br /&gt;
  var allowedWeapons = allowedWeaponsPerRace[selectedRace];&lt;br /&gt;
&lt;br /&gt;
  if (!selectValueIsChanged) {&lt;br /&gt;
    var weaponType = createWeapon(weaponElement.value).type;&lt;br /&gt;
&lt;br /&gt;
    if (!isValueInArray(weaponType, allowedWeapons)) {&lt;br /&gt;
      weaponElement.value = 0;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var children = weaponCategory.children;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; children.length; index++) {&lt;br /&gt;
    var child = children[index];&lt;br /&gt;
&lt;br /&gt;
    if (isValueInArray(index, allowedWeapons)) {&lt;br /&gt;
      showElement(child);&lt;br /&gt;
    } else {&lt;br /&gt;
      hideElement(child);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function changePolymorphValues(characterCreation, monsterVnum, monsterImage) {&lt;br /&gt;
  var { polymorphMonster, polymorphMonsterImage } = characterCreation;&lt;br /&gt;
&lt;br /&gt;
  polymorphMonster.value = monsterVnum;&lt;br /&gt;
  polymorphMonsterImage.value = monsterImage;&lt;br /&gt;
&lt;br /&gt;
  polymorphMonster.dispatchEvent(newChangeEvent());&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function resetImageFromWiki(image) {&lt;br /&gt;
  image.removeAttribute(&amp;quot;srcset&amp;quot;);&lt;br /&gt;
  image.removeAttribute(&amp;quot;data-file-width&amp;quot;);&lt;br /&gt;
  image.removeAttribute(&amp;quot;data-file-height&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleImageFromWiki(image, newSrc) {&lt;br /&gt;
  image.src = newSrc;&lt;br /&gt;
  image.alt = newSrc.split(&amp;quot;/&amp;quot;).pop();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handlePolymorphDisplay(characters, monsterVnum, monsterSrc) {&lt;br /&gt;
  var { translateMonsters, polymorphDisplay } = characters;&lt;br /&gt;
  var oldImage = polymorphDisplay.firstChild;&lt;br /&gt;
  var oldLink = oldImage.nextElementSibling;&lt;br /&gt;
  var monsterName = getMonsterName(monsterVnum);&lt;br /&gt;
  var displayName = translateMonsters&lt;br /&gt;
    ? getTranslatedMonsterName(monsterVnum)&lt;br /&gt;
    : monsterName;&lt;br /&gt;
  var newLink = createWikiLink(monsterName, displayName);&lt;br /&gt;
&lt;br /&gt;
  resetImageFromWiki(oldImage);&lt;br /&gt;
  handleImageFromWiki(oldImage, monsterSrc);&lt;br /&gt;
&lt;br /&gt;
  polymorphDisplay.replaceChild(newLink, oldLink);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createWikiLink(pageName, displayName) {&lt;br /&gt;
  var wikiLink = document.createElement(&amp;quot;a&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  wikiLink.href = mw.util.getUrl(pageName);&lt;br /&gt;
  wikiLink.title = pageName;&lt;br /&gt;
  wikiLink.textContent = displayName || pageName;&lt;br /&gt;
&lt;br /&gt;
  return wikiLink;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSelectedWeapon(weaponCategory) {&lt;br /&gt;
  return weaponCategory.querySelector(&amp;quot;input[type='radio']:checked&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleWeaponDisplay(&lt;br /&gt;
  weaponCategory,&lt;br /&gt;
  weaponDisplay,&lt;br /&gt;
  weaponVnum,&lt;br /&gt;
  newWeapon&lt;br /&gt;
) {&lt;br /&gt;
  var newWeapon = newWeapon || getSelectedWeapon(weaponCategory);&lt;br /&gt;
&lt;br /&gt;
  var newImage = newWeapon.nextElementSibling;&lt;br /&gt;
  var newText = document.createElement(&amp;quot;span&amp;quot;);&lt;br /&gt;
  var oldImage = weaponDisplay.firstChild;&lt;br /&gt;
  var oldText = oldImage.nextElementSibling;&lt;br /&gt;
  var weaponTooltip = newImage.nextElementSibling;&lt;br /&gt;
  var originalWeaponName = weaponTooltip.dataset.o;&lt;br /&gt;
  var weaponName = weaponTooltip.textContent;&lt;br /&gt;
&lt;br /&gt;
  if (weaponVnum == 0) {&lt;br /&gt;
    newText.textContent = weaponName;&lt;br /&gt;
  } else {&lt;br /&gt;
    var weaponLink = createWikiLink(originalWeaponName, weaponName);&lt;br /&gt;
    newText.appendChild(weaponLink);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  weaponDisplay.replaceChild(newImage.cloneNode(), oldImage);&lt;br /&gt;
  weaponDisplay.replaceChild(newText, oldText);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterUpgrade(&lt;br /&gt;
  weaponUpgrade,&lt;br /&gt;
  weaponVnum,&lt;br /&gt;
  randomAttackValue,&lt;br /&gt;
  randomMagicAttackValue&lt;br /&gt;
) {&lt;br /&gt;
  var weapon = createWeapon(weaponVnum);&lt;br /&gt;
  var currentUpgrade = Number(weaponUpgrade.value);&lt;br /&gt;
  var weaponUpgradeChildren = weaponUpgrade.children;&lt;br /&gt;
&lt;br /&gt;
  if (weapon.isSerpent) {&lt;br /&gt;
    showElement(randomAttackValue);&lt;br /&gt;
&lt;br /&gt;
    if (weapon.isMagic) {&lt;br /&gt;
      showElement(randomMagicAttackValue);&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    hideElement(randomAttackValue);&lt;br /&gt;
    hideElement(randomMagicAttackValue);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (weapon.maxUpgrade &amp;lt; 1) {&lt;br /&gt;
    hideElement(weaponUpgrade.parentElement);&lt;br /&gt;
  } else {&lt;br /&gt;
    showElement(weaponUpgrade.parentElement);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (var upgrade = 0; upgrade &amp;lt;= weapon.maxUpgrade; upgrade++) {&lt;br /&gt;
    showElement(weaponUpgradeChildren[upgrade]);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (&lt;br /&gt;
    var upgrade = weapon.maxUpgrade + 1;&lt;br /&gt;
    upgrade &amp;lt; weaponUpgradeChildren.length;&lt;br /&gt;
    upgrade++&lt;br /&gt;
  ) {&lt;br /&gt;
    hideElement(weaponUpgradeChildren[upgrade]);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (currentUpgrade &amp;gt; weapon.maxUpgrade) {&lt;br /&gt;
    weaponUpgrade.value = weapon.maxUpgrade;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterCheckbox(checkbox, element) {&lt;br /&gt;
  if (checkbox.checked) {&lt;br /&gt;
    showElement(element);&lt;br /&gt;
  } else {&lt;br /&gt;
    hideElement(element);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterSkills(selectedClass, skillElementsToFilter) {&lt;br /&gt;
  for (var element of skillElementsToFilter) {&lt;br /&gt;
    if (isValueInArray(selectedClass, element.dataset.class)) {&lt;br /&gt;
      showElement(element);&lt;br /&gt;
    } else {&lt;br /&gt;
      hideElement(element);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterForm(characters, battle) {&lt;br /&gt;
  var { saveButton, characterCreation, toggleSiblings } = characters;&lt;br /&gt;
  var allowedWeaponsPerRace = battle.constants.allowedWeaponsPerRace;&lt;br /&gt;
  var battleChoice = battle.battleChoice;&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;change&amp;quot;, function (event) {&lt;br /&gt;
    var target = event.target;&lt;br /&gt;
    var targetName = target.name;&lt;br /&gt;
&lt;br /&gt;
    saveButtonOrange(saveButton);&lt;br /&gt;
    characters.unsavedChanges = true;&lt;br /&gt;
&lt;br /&gt;
    switch (targetName) {&lt;br /&gt;
      case &amp;quot;race&amp;quot;:&lt;br /&gt;
        var selectedRace = target.value;&lt;br /&gt;
        var classChoice = characterCreation.class;&lt;br /&gt;
        var weaponElement = characterCreation.weapon;&lt;br /&gt;
&lt;br /&gt;
        filterClass(selectedRace, classChoice);&lt;br /&gt;
        filterWeapon(&lt;br /&gt;
          selectedRace,&lt;br /&gt;
          weaponElement,&lt;br /&gt;
          characters.weaponCategory,&lt;br /&gt;
          allowedWeaponsPerRace&lt;br /&gt;
        );&lt;br /&gt;
        handleWeaponDisplay(&lt;br /&gt;
          characters.weaponCategory,&lt;br /&gt;
          characters.weaponDisplay,&lt;br /&gt;
          weaponElement.value&lt;br /&gt;
        );&lt;br /&gt;
        filterUpgrade(&lt;br /&gt;
          characterCreation.weaponUpgrade,&lt;br /&gt;
          weaponElement.value,&lt;br /&gt;
          characters.randomAttackValue,&lt;br /&gt;
          characters.randomMagicAttackValue&lt;br /&gt;
        );&lt;br /&gt;
        filterSkills(classChoice.value, characters.skillElementsToFilter);&lt;br /&gt;
        handleBonusVariationUpdate(&lt;br /&gt;
          characterCreation,&lt;br /&gt;
          characters.bonusVariation,&lt;br /&gt;
          true&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        battleChoice.resetAttackType = true;&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;class&amp;quot;:&lt;br /&gt;
        filterSkills(target.value, characters.skillElementsToFilter);&lt;br /&gt;
        handleBonusVariationUpdate(&lt;br /&gt;
          characterCreation,&lt;br /&gt;
          characters.bonusVariation,&lt;br /&gt;
          true&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        battleChoice.resetAttackType = true;&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;weapon&amp;quot;:&lt;br /&gt;
        var weaponElement = characterCreation.weapon;&lt;br /&gt;
&lt;br /&gt;
        handleWeaponDisplay(&lt;br /&gt;
          characters.weaponCategory,&lt;br /&gt;
          characters.weaponDisplay,&lt;br /&gt;
          weaponElement.value,&lt;br /&gt;
          target&lt;br /&gt;
        );&lt;br /&gt;
        filterUpgrade(&lt;br /&gt;
          characterCreation.weaponUpgrade,&lt;br /&gt;
          target.value,&lt;br /&gt;
          characters.randomAttackValue,&lt;br /&gt;
          characters.randomMagicAttackValue&lt;br /&gt;
        );&lt;br /&gt;
        handleBonusVariationUpdate(&lt;br /&gt;
          characterCreation,&lt;br /&gt;
          characters.bonusVariation&lt;br /&gt;
        );&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;isRiding&amp;quot;:&lt;br /&gt;
        battleChoice.resetAttackType = true;&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;isPolymorph&amp;quot;:&lt;br /&gt;
        battleChoice.resetAttackType = true;&lt;br /&gt;
        break;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (toggleSiblings.hasOwnProperty(targetName)) {&lt;br /&gt;
      filterCheckbox(target, toggleSiblings[targetName]);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      targetName.startsWith(&amp;quot;attackSkill&amp;quot;) ||&lt;br /&gt;
      targetName.startsWith(&amp;quot;horseSkill&amp;quot;)&lt;br /&gt;
    ) {&lt;br /&gt;
      battleChoice.resetAttackType = true;&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addUniquePseudo(characterDataObject, savedCharactersPseudo) {&lt;br /&gt;
  var characterPseudo = String(characterDataObject.name);&lt;br /&gt;
  var originalPseudo = characterPseudo;&lt;br /&gt;
  var count = 0;&lt;br /&gt;
&lt;br /&gt;
  var regex = /(.*)(\d)$/;&lt;br /&gt;
  var match = characterPseudo.match(regex);&lt;br /&gt;
&lt;br /&gt;
  if (match) {&lt;br /&gt;
    originalPseudo = match[1];&lt;br /&gt;
    count = match[2];&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  while (isValueInArray(characterPseudo, savedCharactersPseudo)) {&lt;br /&gt;
    characterPseudo = originalPseudo + count;&lt;br /&gt;
    count++;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  characterDataObject.name = characterPseudo;&lt;br /&gt;
  return [characterDataObject, characterPseudo];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function convertToNumber(value) {&lt;br /&gt;
  var valueNumber = Number(value);&lt;br /&gt;
  return isNaN(valueNumber) ? value : valueNumber;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getLocalStorageValue(key, defaultValue) {&lt;br /&gt;
  var storedValue = localStorage.getItem(key);&lt;br /&gt;
&lt;br /&gt;
  if (storedValue) {&lt;br /&gt;
    return JSON.parse(storedValue);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return defaultValue;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSavedCharacters() {&lt;br /&gt;
  return getLocalStorageValue(&amp;quot;mt2-calc.characters.saved&amp;quot;, {});&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSavedMonsters() {&lt;br /&gt;
  return getLocalStorageValue(&amp;quot;mt2-calc.monsters.saved&amp;quot;, {});&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSavedFights() {&lt;br /&gt;
  return getLocalStorageValue(&amp;quot;mt2-calc.fights.saved&amp;quot;, []);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getLastLang() {&lt;br /&gt;
  return getLocalStorageValue(&amp;quot;mt2-calc.language.last-used&amp;quot;, &amp;quot;&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveToLocalStorage(key, value) {&lt;br /&gt;
  localStorage.setItem(key, JSON.stringify(value));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateSavedCharacters(savedCharacters) {&lt;br /&gt;
  saveToLocalStorage(&amp;quot;mt2-calc.characters.saved&amp;quot;, savedCharacters);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateSavedMonsters(savedMonsters) {&lt;br /&gt;
  saveToLocalStorage(&amp;quot;mt2-calc.monsters.saved&amp;quot;, savedMonsters);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateSavedFights(savedFights) {&lt;br /&gt;
  saveToLocalStorage(&amp;quot;mt2-calc.fights.saved&amp;quot;, savedFights);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateLastLang(lang) {&lt;br /&gt;
  saveToLocalStorage(&amp;quot;mt2-calc.language.last-used&amp;quot;, lang);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveCharacter(&lt;br /&gt;
  savedCharacters,&lt;br /&gt;
  characterCreation,&lt;br /&gt;
  battle,&lt;br /&gt;
  newCharacter,&lt;br /&gt;
  characterDataObject&lt;br /&gt;
) {&lt;br /&gt;
  if (!characterDataObject) {&lt;br /&gt;
    var characterData = new FormData(characterCreation);&lt;br /&gt;
    var characterDataObject = {};&lt;br /&gt;
&lt;br /&gt;
    characterData.forEach(function (value, key) {&lt;br /&gt;
      characterDataObject[key] = convertToNumber(value);&lt;br /&gt;
    });&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var characterPseudo = characterDataObject.name;&lt;br /&gt;
  var { battleChoice } = battle;&lt;br /&gt;
&lt;br /&gt;
  savedCharacters[characterPseudo] = characterDataObject;&lt;br /&gt;
  updateSavedCharacters(savedCharacters);&lt;br /&gt;
&lt;br /&gt;
  if (newCharacter) {&lt;br /&gt;
    addBattleChoice(battleChoice, characterPseudo, characterDataObject);&lt;br /&gt;
  } else {&lt;br /&gt;
    updateBattleChoiceImage(&lt;br /&gt;
      battleChoice,&lt;br /&gt;
      characterPseudo,&lt;br /&gt;
      characterDataObject.race&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (battleChoice.resetAttackType) {&lt;br /&gt;
    if (isCharacterSelected(characterPseudo, battleChoice.attacker.selected)) {&lt;br /&gt;
      filterAttackTypeSelectionCharacter(&lt;br /&gt;
        characterDataObject,&lt;br /&gt;
        battleChoice.attackType&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
    battleChoice.resetAttackType = false;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveButtonGreen(saveButton) {&lt;br /&gt;
  saveButton.classList.remove(&amp;quot;unsaved-character&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveButtonOrange(saveButton) {&lt;br /&gt;
  saveButton.classList.add(&amp;quot;unsaved-character&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function characterCreationListener(characters, battle) {&lt;br /&gt;
  var { characterCreation, saveButton, weaponCategory } = characters;&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;submit&amp;quot;, handleSubmitForm);&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;invalid&amp;quot;, handleInvalidInput, true);&lt;br /&gt;
  document.addEventListener(&amp;quot;keydown&amp;quot;, handleSaveShortcut);&lt;br /&gt;
  weaponCategory.addEventListener(&amp;quot;mouseover&amp;quot;, handleTooltipOverflow);&lt;br /&gt;
&lt;br /&gt;
  function handleSubmitForm(event) {&lt;br /&gt;
    event.preventDefault();&lt;br /&gt;
&lt;br /&gt;
    if (characters.unsavedChanges) {&lt;br /&gt;
      saveCharacter(characters.savedCharacters, characterCreation, battle);&lt;br /&gt;
      saveButtonGreen(saveButton);&lt;br /&gt;
      characters.unsavedChanges = false;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function handleInvalidInput(event) {&lt;br /&gt;
    var target = event.target;&lt;br /&gt;
&lt;br /&gt;
    if (target.checkVisibility()) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var autoCorrectInput = target.closest(&amp;quot;.auto-correct-input&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      autoCorrectInput &amp;amp;&amp;amp;&lt;br /&gt;
      autoCorrectInput.classList.contains(&amp;quot;tabber-noactive&amp;quot;)&lt;br /&gt;
    ) {&lt;br /&gt;
      target.value = target.defaultValue;&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    openTargetTab(target);&lt;br /&gt;
    openTargetCollapsible(target);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function handleSaveShortcut(event) {&lt;br /&gt;
    if (event.ctrlKey &amp;amp;&amp;amp; event.key === &amp;quot;s&amp;quot;) {&lt;br /&gt;
      event.preventDefault();&lt;br /&gt;
      saveButton.click();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function handleTooltipOverflow(event) {&lt;br /&gt;
    var label = event.target.closest(&amp;quot;label&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (label) {&lt;br /&gt;
      var tooltip = label.lastChild;&lt;br /&gt;
&lt;br /&gt;
      if (tooltip.classList.contains(&amp;quot;popContenu&amp;quot;)) {&lt;br /&gt;
        var tooltipRect = tooltip.getBoundingClientRect();&lt;br /&gt;
        var modalRect = weaponCategory.getBoundingClientRect();&lt;br /&gt;
&lt;br /&gt;
        if (tooltipRect.right &amp;gt; modalRect.right) {&lt;br /&gt;
          tooltip.style.left = &amp;quot;-100%&amp;quot;;&lt;br /&gt;
        } else if (tooltipRect.left &amp;lt; modalRect.left) {&lt;br /&gt;
          tooltip.style.left = &amp;quot;200%&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function downloadData(content, type, filename) {&lt;br /&gt;
  var link = document.createElement(&amp;quot;a&amp;quot;);&lt;br /&gt;
  var blob = new Blob([content], { type: type });&lt;br /&gt;
  var blobURL = URL.createObjectURL(blob);&lt;br /&gt;
&lt;br /&gt;
  link.href = blobURL;&lt;br /&gt;
  link.download = filename;&lt;br /&gt;
  document.body.appendChild(link);&lt;br /&gt;
&lt;br /&gt;
  link.click();&lt;br /&gt;
  document.body.removeChild(link);&lt;br /&gt;
  URL.revokeObjectURL(blobURL);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function uploadCharacter(&lt;br /&gt;
  selectedFiles,&lt;br /&gt;
  characters,&lt;br /&gt;
  characterTemplate,&lt;br /&gt;
  charactersContainer,&lt;br /&gt;
  battle&lt;br /&gt;
) {&lt;br /&gt;
  var selectFilesLength = selectedFiles.length;&lt;br /&gt;
  var defaultPseudo = characters.defaultText.pseudo;&lt;br /&gt;
&lt;br /&gt;
  for (var fileIndex = 0; fileIndex &amp;lt; selectFilesLength; fileIndex++) {&lt;br /&gt;
    var selectedFile = selectedFiles[fileIndex];&lt;br /&gt;
&lt;br /&gt;
    if (selectedFile.type === &amp;quot;text/plain&amp;quot;) {&lt;br /&gt;
      var reader = new FileReader();&lt;br /&gt;
      reader.onload = function (e) {&lt;br /&gt;
        var fileContent = e.target.result;&lt;br /&gt;
        try {&lt;br /&gt;
          var characterDataObject = JSON.parse(fileContent);&lt;br /&gt;
&lt;br /&gt;
          if (characterDataObject.hasOwnProperty(&amp;quot;name&amp;quot;)) {&lt;br /&gt;
            var characterPseudo = String(characterDataObject.name);&lt;br /&gt;
&lt;br /&gt;
            hideElement(characters.characterCreation);&lt;br /&gt;
            characterPseudo = validPseudo(characterPseudo, defaultPseudo);&lt;br /&gt;
&lt;br /&gt;
            [characterDataObject, characterPseudo] = addUniquePseudo(&lt;br /&gt;
              characterDataObject,&lt;br /&gt;
              Object.keys(characters.savedCharacters)&lt;br /&gt;
            );&lt;br /&gt;
            var selectedCharacter = handleNewCharacter(&lt;br /&gt;
              characters,&lt;br /&gt;
              characterTemplate,&lt;br /&gt;
              charactersContainer,&lt;br /&gt;
              battle,&lt;br /&gt;
              characterPseudo&lt;br /&gt;
            )[0];&lt;br /&gt;
&lt;br /&gt;
            if (selectFilesLength === 1) {&lt;br /&gt;
              updateForm(&lt;br /&gt;
                characterDataObject,&lt;br /&gt;
                characters.characterCreation,&lt;br /&gt;
                characters,&lt;br /&gt;
                selectedCharacter,&lt;br /&gt;
                battle&lt;br /&gt;
              );&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            saveCharacter(&lt;br /&gt;
              characters.savedCharacters,&lt;br /&gt;
              characters.characterCreation,&lt;br /&gt;
              battle,&lt;br /&gt;
              true,&lt;br /&gt;
              characterDataObject&lt;br /&gt;
            );&lt;br /&gt;
          }&lt;br /&gt;
        } catch (error) {&lt;br /&gt;
          console.warn(error);&lt;br /&gt;
          if (error.name === &amp;quot;TypeError&amp;quot;) {&lt;br /&gt;
            // delete the character&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
      };&lt;br /&gt;
      reader.readAsText(selectedFile);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleUploadCharacter(&lt;br /&gt;
  characters,&lt;br /&gt;
  characterTemplate,&lt;br /&gt;
  charactersContainer,&lt;br /&gt;
  battle&lt;br /&gt;
) {&lt;br /&gt;
  var characterInput = characters.characterInput;&lt;br /&gt;
  var dropZone = characters.dropZone;&lt;br /&gt;
&lt;br /&gt;
  characterInput.accept = &amp;quot;.txt&amp;quot;;&lt;br /&gt;
  characterInput.multiple = true;&lt;br /&gt;
  dropZone.setAttribute(&amp;quot;tabindex&amp;quot;, &amp;quot;0&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  dropZone.addEventListener(&amp;quot;click&amp;quot;, function () {&lt;br /&gt;
    characterInput.click();&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  dropZone.addEventListener(&amp;quot;dragover&amp;quot;, function (event) {&lt;br /&gt;
    event.preventDefault();&lt;br /&gt;
    dropZone.classList.add(&amp;quot;drop-zone--dragover&amp;quot;);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  [&amp;quot;dragleave&amp;quot;, &amp;quot;dragend&amp;quot;].forEach(function (type) {&lt;br /&gt;
    dropZone.addEventListener(type, function () {&lt;br /&gt;
      dropZone.classList.remove(&amp;quot;drop-zone--dragover&amp;quot;);&lt;br /&gt;
    });&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  dropZone.addEventListener(&amp;quot;drop&amp;quot;, function (event) {&lt;br /&gt;
    event.preventDefault();&lt;br /&gt;
    uploadCharacter(&lt;br /&gt;
      event.dataTransfer.files,&lt;br /&gt;
      characters,&lt;br /&gt;
      characterTemplate,&lt;br /&gt;
      charactersContainer,&lt;br /&gt;
      battle&lt;br /&gt;
    );&lt;br /&gt;
    dropZone.classList.remove(&amp;quot;drop-zone--dragover&amp;quot;);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  characterInput.addEventListener(&amp;quot;change&amp;quot;, function (event) {&lt;br /&gt;
    uploadCharacter(&lt;br /&gt;
      event.target.files,&lt;br /&gt;
      characters,&lt;br /&gt;
      characterTemplate,&lt;br /&gt;
      charactersContainer,&lt;br /&gt;
      battle&lt;br /&gt;
    );&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function deleteCharacter(characters, pseudo, element, battle) {&lt;br /&gt;
  delete characters.savedCharacters[pseudo];&lt;br /&gt;
  element.remove();&lt;br /&gt;
&lt;br /&gt;
  updateSavedCharacters(characters.savedCharacters);&lt;br /&gt;
  removeBattleChoice(battle.battleChoice, pseudo, &amp;quot;character&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (&lt;br /&gt;
    !Object.keys(characters.savedCharacters).length ||&lt;br /&gt;
    characters.characterCreation.name.value === pseudo&lt;br /&gt;
  ) {&lt;br /&gt;
    saveButtonGreen(characters.saveButton);&lt;br /&gt;
    characters.unsavedChanges = false;&lt;br /&gt;
    hideElement(characters.characterCreation);&lt;br /&gt;
    showElement(characters.characterCreation.previousElementSibling);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function deleteMonster(characters, battle, monsterVnum) {&lt;br /&gt;
  var monsterElements = characters.monsterElements;&lt;br /&gt;
  var monsterType = characters.savedMonsters[monsterVnum].category;&lt;br /&gt;
&lt;br /&gt;
  if (monsterElements.hasOwnProperty(monsterVnum)) {&lt;br /&gt;
    monsterElements[monsterVnum].remove();&lt;br /&gt;
    delete monsterElements[monsterVnum];&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  delete characters.savedMonsters[monsterVnum];&lt;br /&gt;
&lt;br /&gt;
  updateSavedMonsters(characters.savedMonsters);&lt;br /&gt;
  removeBattleChoice(battle.battleChoice, monsterVnum, monsterType);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleStyle(characters, selectedElement) {&lt;br /&gt;
  var currentCharacter = characters.currentCharacter;&lt;br /&gt;
&lt;br /&gt;
  if (currentCharacter) {&lt;br /&gt;
    currentCharacter.classList.remove(&amp;quot;selected-character&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  selectedElement.classList.add(&amp;quot;selected-character&amp;quot;);&lt;br /&gt;
  characters.currentCharacter = selectedElement;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateForm(&lt;br /&gt;
  formData,&lt;br /&gt;
  characterCreation,&lt;br /&gt;
  characters,&lt;br /&gt;
  selectedElement,&lt;br /&gt;
  battle&lt;br /&gt;
) {&lt;br /&gt;
  saveButtonGreen(characters.saveButton);&lt;br /&gt;
  hideElement(characterCreation.previousElementSibling);&lt;br /&gt;
  showElement(characterCreation);&lt;br /&gt;
  handleStyle(characters, selectedElement);&lt;br /&gt;
&lt;br /&gt;
  characterCreation.reset();&lt;br /&gt;
&lt;br /&gt;
  for (var [name, value] of Object.entries(formData)) {&lt;br /&gt;
    var formElement = characterCreation[name];&lt;br /&gt;
&lt;br /&gt;
    if (!formElement) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (formElement.type === &amp;quot;checkbox&amp;quot;) {&lt;br /&gt;
      if (isChecked(value)) {&lt;br /&gt;
        formElement.checked = true;&lt;br /&gt;
      }&lt;br /&gt;
    } else {&lt;br /&gt;
      formElement.value = value;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  var selectedRace = characterCreation.race.value;&lt;br /&gt;
  var classChoice = characterCreation.class;&lt;br /&gt;
  var weaponElement = characterCreation.weapon;&lt;br /&gt;
&lt;br /&gt;
  filterClass(selectedRace, classChoice, true);&lt;br /&gt;
  filterWeapon(&lt;br /&gt;
    selectedRace,&lt;br /&gt;
    weaponElement,&lt;br /&gt;
    characters.weaponCategory,&lt;br /&gt;
    battle.constants.allowedWeaponsPerRace,&lt;br /&gt;
    true&lt;br /&gt;
  );&lt;br /&gt;
  handlePolymorphDisplay(&lt;br /&gt;
    characters,&lt;br /&gt;
    characterCreation.polymorphMonster.value,&lt;br /&gt;
    characterCreation.polymorphMonsterImage.value&lt;br /&gt;
  );&lt;br /&gt;
  handleWeaponDisplay(&lt;br /&gt;
    characters.weaponCategory,&lt;br /&gt;
    characters.weaponDisplay,&lt;br /&gt;
    weaponElement.value&lt;br /&gt;
  );&lt;br /&gt;
  filterUpgrade(&lt;br /&gt;
    characterCreation.weaponUpgrade,&lt;br /&gt;
    weaponElement.value,&lt;br /&gt;
    characters.randomAttackValue,&lt;br /&gt;
    characters.randomMagicAttackValue&lt;br /&gt;
  );&lt;br /&gt;
  for (var [targetName, sibling] of Object.entries(characters.toggleSiblings)) {&lt;br /&gt;
    filterCheckbox(characterCreation[targetName], sibling);&lt;br /&gt;
  }&lt;br /&gt;
  filterSkills(classChoice.value, characters.skillElementsToFilter);&lt;br /&gt;
  handleBonusVariationUpdate(characterCreation, characters.bonusVariation);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleClickOnCharacter(&lt;br /&gt;
  spanInput,&lt;br /&gt;
  target,&lt;br /&gt;
  characters,&lt;br /&gt;
  characterElement,&lt;br /&gt;
  battle,&lt;br /&gt;
  edition&lt;br /&gt;
) {&lt;br /&gt;
  var displayedPseudo = characters.characterCreation.name.value;&lt;br /&gt;
  var pseudo = spanInput.dataset.name;&lt;br /&gt;
  var { unsavedWarning, deleteWarning } = characters.defaultText;&lt;br /&gt;
&lt;br /&gt;
  if (edition) {&lt;br /&gt;
    if (!characters.unsavedChanges) {&lt;br /&gt;
      updateForm(&lt;br /&gt;
        characters.savedCharacters[pseudo],&lt;br /&gt;
        characters.characterCreation,&lt;br /&gt;
        characters,&lt;br /&gt;
        characterElement,&lt;br /&gt;
        battle&lt;br /&gt;
      );&lt;br /&gt;
    } else if (displayedPseudo === pseudo) {&lt;br /&gt;
      // pass&lt;br /&gt;
    } else {&lt;br /&gt;
      var result = confirm(unsavedWarning);&lt;br /&gt;
&lt;br /&gt;
      if (result) {&lt;br /&gt;
        updateForm(&lt;br /&gt;
          characters.savedCharacters[pseudo],&lt;br /&gt;
          characters.characterCreation,&lt;br /&gt;
          characters,&lt;br /&gt;
          characterElement,&lt;br /&gt;
          battle&lt;br /&gt;
        );&lt;br /&gt;
        characters.unsavedChanges = false;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    if (target.tagName === &amp;quot;path&amp;quot;) {&lt;br /&gt;
      target = target.parentElement;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    switch (target.dataset.icon) {&lt;br /&gt;
      case &amp;quot;duplicate&amp;quot;:&lt;br /&gt;
        if (!characters.unsavedChanges) {&lt;br /&gt;
          addNewCharacter(&lt;br /&gt;
            characters,&lt;br /&gt;
            characters.newCharacterTemplate,&lt;br /&gt;
            characters.charactersContainer,&lt;br /&gt;
            battle,&lt;br /&gt;
            pseudo&lt;br /&gt;
          );&lt;br /&gt;
        } else {&lt;br /&gt;
          var result = confirm(unsavedWarning);&lt;br /&gt;
&lt;br /&gt;
          if (result) {&lt;br /&gt;
            addNewCharacter(&lt;br /&gt;
              characters,&lt;br /&gt;
              characters.newCharacterTemplate,&lt;br /&gt;
              characters.charactersContainer,&lt;br /&gt;
              battle,&lt;br /&gt;
              pseudo&lt;br /&gt;
            );&lt;br /&gt;
            saveButtonGreen(characters.saveButton);&lt;br /&gt;
            characters.unsavedChanges = false;&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
        break;&lt;br /&gt;
&lt;br /&gt;
      case &amp;quot;download&amp;quot;:&lt;br /&gt;
        var character = characters.savedCharacters[pseudo];&lt;br /&gt;
        downloadData(&lt;br /&gt;
          JSON.stringify(character),&lt;br /&gt;
          &amp;quot;text/plain&amp;quot;,&lt;br /&gt;
          character.name + &amp;quot;.txt&amp;quot;&lt;br /&gt;
        );&lt;br /&gt;
        break;&lt;br /&gt;
&lt;br /&gt;
      case &amp;quot;delete&amp;quot;:&lt;br /&gt;
        var result = confirm(deleteWarning.replace(&amp;quot;[[]]&amp;quot;, pseudo));&lt;br /&gt;
        if (result) {&lt;br /&gt;
          deleteCharacter(characters, pseudo, characterElement, battle);&lt;br /&gt;
        }&lt;br /&gt;
        break;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleNewCharacter(&lt;br /&gt;
  characters,&lt;br /&gt;
  characterTemplate,&lt;br /&gt;
  charactersContainer,&lt;br /&gt;
  battle,&lt;br /&gt;
  pseudo&lt;br /&gt;
) {&lt;br /&gt;
  var newCharacterTemplate = characterTemplate.cloneNode(true);&lt;br /&gt;
  var spanInput = newCharacterTemplate.querySelector(&amp;quot;span.input&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  newCharacterTemplate.setAttribute(&amp;quot;tabindex&amp;quot;, &amp;quot;0&amp;quot;);&lt;br /&gt;
  charactersContainer.appendChild(newCharacterTemplate);&lt;br /&gt;
&lt;br /&gt;
  if (pseudo) {&lt;br /&gt;
    spanInput.textContent = pseudo;&lt;br /&gt;
    spanInput.setAttribute(&amp;quot;data-name&amp;quot;, pseudo);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  newCharacterTemplate.addEventListener(&amp;quot;click&amp;quot;, function (event) {&lt;br /&gt;
    var target = event.target;&lt;br /&gt;
&lt;br /&gt;
    if (target.tagName === &amp;quot;path&amp;quot; || target.tagName === &amp;quot;svg&amp;quot;) {&lt;br /&gt;
      handleClickOnCharacter(&lt;br /&gt;
        spanInput,&lt;br /&gt;
        target,&lt;br /&gt;
        characters,&lt;br /&gt;
        newCharacterTemplate,&lt;br /&gt;
        battle&lt;br /&gt;
      );&lt;br /&gt;
    } else {&lt;br /&gt;
      handleClickOnCharacter(&lt;br /&gt;
        spanInput,&lt;br /&gt;
        null,&lt;br /&gt;
        characters,&lt;br /&gt;
        newCharacterTemplate,&lt;br /&gt;
        battle,&lt;br /&gt;
        true&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  newCharacterTemplate.addEventListener(&amp;quot;keydown&amp;quot;, function (event) {&lt;br /&gt;
    if (event.keyCode === 13) {&lt;br /&gt;
      event.target.click();&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  return [newCharacterTemplate, spanInput];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function validPseudo(pseudo, defaultPseudo) {&lt;br /&gt;
  var newPseudo = pseudoFormat(pseudo);&lt;br /&gt;
&lt;br /&gt;
  if (!newPseudo) {&lt;br /&gt;
    return pseudoFormat(defaultPseudo);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return newPseudo;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addNewCharacter(&lt;br /&gt;
  characters,&lt;br /&gt;
  characterTemplate,&lt;br /&gt;
  charactersContainer,&lt;br /&gt;
  battle,&lt;br /&gt;
  pseudoToDuplicate&lt;br /&gt;
) {&lt;br /&gt;
  function editAndSetCharacterPseudoInput(selectedCharacter, spanInput) {&lt;br /&gt;
    var maxPseudoLength = 20;&lt;br /&gt;
    var defaultPseudo = characters.defaultText.pseudo;&lt;br /&gt;
&lt;br /&gt;
    var selection = window.getSelection();&lt;br /&gt;
    var range = document.createRange();&lt;br /&gt;
&lt;br /&gt;
    if (pseudoToDuplicate) {&lt;br /&gt;
      spanInput.textContent = pseudoToDuplicate;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    spanInput.contentEditable = true;&lt;br /&gt;
    spanInput.focus();&lt;br /&gt;
    range.selectNodeContents(spanInput);&lt;br /&gt;
    selection.removeAllRanges();&lt;br /&gt;
    selection.addRange(range);&lt;br /&gt;
&lt;br /&gt;
    function pseudoValidation() {&lt;br /&gt;
      var characterPseudo = validPseudo(spanInput.textContent, defaultPseudo);&lt;br /&gt;
      var characterDataObject = { name: characterPseudo };&lt;br /&gt;
&lt;br /&gt;
      if (pseudoToDuplicate) {&lt;br /&gt;
        characterDataObject = copyObject(&lt;br /&gt;
          characters.savedCharacters[pseudoToDuplicate]&lt;br /&gt;
        );&lt;br /&gt;
        characterDataObject.name = characterPseudo;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      [characterDataObject, characterPseudo] = addUniquePseudo(&lt;br /&gt;
        characterDataObject,&lt;br /&gt;
        Object.keys(characters.savedCharacters)&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      selection.removeAllRanges();&lt;br /&gt;
      spanInput.contentEditable = false;&lt;br /&gt;
      spanInput.textContent = characterPseudo;&lt;br /&gt;
      spanInput.setAttribute(&amp;quot;data-name&amp;quot;, characterPseudo);&lt;br /&gt;
&lt;br /&gt;
      updateForm(&lt;br /&gt;
        characterDataObject,&lt;br /&gt;
        characters.characterCreation,&lt;br /&gt;
        characters,&lt;br /&gt;
        selectedCharacter,&lt;br /&gt;
        battle&lt;br /&gt;
      );&lt;br /&gt;
      saveCharacter(&lt;br /&gt;
        characters.savedCharacters,&lt;br /&gt;
        characters.characterCreation,&lt;br /&gt;
        battle,&lt;br /&gt;
        true&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handleMaxLength(event) {&lt;br /&gt;
      if (spanInput.textContent.length &amp;gt; maxPseudoLength) {&lt;br /&gt;
        spanInput.textContent = spanInput.textContent.slice(0, maxPseudoLength);&lt;br /&gt;
        range.setStart(spanInput.childNodes[0], maxPseudoLength);&lt;br /&gt;
        selection.removeAllRanges();&lt;br /&gt;
        selection.addRange(range);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handleBlur() {&lt;br /&gt;
      spanInput.removeEventListener(&amp;quot;blur&amp;quot;, handleBlur);&lt;br /&gt;
      spanInput.removeEventListener(&amp;quot;input&amp;quot;, handleMaxLength);&lt;br /&gt;
      pseudoValidation();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handleKeyDown(event) {&lt;br /&gt;
      if (event.key === &amp;quot;Enter&amp;quot;) {&lt;br /&gt;
        event.preventDefault();&lt;br /&gt;
&lt;br /&gt;
        spanInput.removeEventListener(&amp;quot;keydown&amp;quot;, handleKeyDown);&lt;br /&gt;
        spanInput.removeEventListener(&amp;quot;blur&amp;quot;, handleBlur);&lt;br /&gt;
        spanInput.removeEventListener(&amp;quot;input&amp;quot;, handleMaxLength);&lt;br /&gt;
&lt;br /&gt;
        pseudoValidation();&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    spanInput.addEventListener(&amp;quot;input&amp;quot;, handleMaxLength);&lt;br /&gt;
    spanInput.addEventListener(&amp;quot;keydown&amp;quot;, handleKeyDown);&lt;br /&gt;
    spanInput.addEventListener(&amp;quot;blur&amp;quot;, handleBlur);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  hideElement(characters.characterCreation);&lt;br /&gt;
  var [selectedCharacter, spanInput] = handleNewCharacter(&lt;br /&gt;
    characters,&lt;br /&gt;
    characterTemplate,&lt;br /&gt;
    charactersContainer,&lt;br /&gt;
    battle&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  editAndSetCharacterPseudoInput(selectedCharacter, spanInput);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleFocus() {&lt;br /&gt;
  var tooltipLinks = document.querySelectorAll(&amp;quot;div.tooltip a&amp;quot;);&lt;br /&gt;
  tooltipLinks.forEach(function (link) {&lt;br /&gt;
    link.setAttribute(&amp;quot;tabindex&amp;quot;, -1);&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function resetBonusVariation(bonusVariation) {&lt;br /&gt;
  function resetInput(input) {&lt;br /&gt;
    input.removeAttribute(&amp;quot;min&amp;quot;);&lt;br /&gt;
    input.removeAttribute(&amp;quot;max&amp;quot;);&lt;br /&gt;
    input.defaultValue = 0;&lt;br /&gt;
    input.value = input.defaultValue;&lt;br /&gt;
  }&lt;br /&gt;
  var { minValue, maxValue, checkbox, container, disabledText, selectedText } =&lt;br /&gt;
    bonusVariation;&lt;br /&gt;
&lt;br /&gt;
  resetInput(minValue);&lt;br /&gt;
  resetInput(maxValue);&lt;br /&gt;
  showElement(disabledText);&lt;br /&gt;
  hideElement(selectedText);&lt;br /&gt;
  hideElement(container);&lt;br /&gt;
  checkbox.checked = false;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleBonusVariationUpdate(&lt;br /&gt;
  characterCreation,&lt;br /&gt;
  bonusVariation,&lt;br /&gt;
  resetSkill&lt;br /&gt;
) {&lt;br /&gt;
  var selectedBonus = characterCreation.bonusVariation.value;&lt;br /&gt;
  var displayName = characterCreation.bonusVariationName.value;&lt;br /&gt;
&lt;br /&gt;
  if (&lt;br /&gt;
    resetSkill &amp;amp;&amp;amp;&lt;br /&gt;
    (selectedBonus.startsWith(&amp;quot;attackSkill&amp;quot;) ||&lt;br /&gt;
      selectedBonus.startsWith(&amp;quot;horseSkill&amp;quot;) ||&lt;br /&gt;
      selectedBonus.startsWith(&amp;quot;skillBonus&amp;quot;))&lt;br /&gt;
  ) {&lt;br /&gt;
    resetBonusVariation(bonusVariation);&lt;br /&gt;
    return;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (&lt;br /&gt;
    characterCreation.hasOwnProperty(selectedBonus) &amp;amp;&amp;amp;&lt;br /&gt;
    selectedBonus != 0 &amp;amp;&amp;amp;&lt;br /&gt;
    displayName != 0&lt;br /&gt;
  ) {&lt;br /&gt;
    handleBonusVariation(&lt;br /&gt;
      characterCreation[selectedBonus],&lt;br /&gt;
      bonusVariation,&lt;br /&gt;
      displayName&lt;br /&gt;
    );&lt;br /&gt;
  } else {&lt;br /&gt;
    resetBonusVariation(bonusVariation);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getTargetContent(targetParent, targetName, isSkill) {&lt;br /&gt;
  var targetContent = &amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  if (targetParent.children.length &amp;lt;= 1) {&lt;br /&gt;
    targetContent = targetParent.textContent;&lt;br /&gt;
  } else if (targetName === &amp;quot;weaponUpgrade&amp;quot;) {&lt;br /&gt;
    targetContent = targetParent.children[1].textContent;&lt;br /&gt;
  } else if (targetName === &amp;quot;level&amp;quot;) {&lt;br /&gt;
    targetContent = targetParent.textContent.replace(&amp;quot;Lv&amp;quot;, &amp;quot;&amp;quot;).trim();&lt;br /&gt;
  } else if (isSkill) {&lt;br /&gt;
    var container = targetParent.children[1];&lt;br /&gt;
&lt;br /&gt;
    for (var index = 0; index &amp;lt; container.children.length; index++) {&lt;br /&gt;
      var element = container.children[index];&lt;br /&gt;
&lt;br /&gt;
      if (element.checkVisibility()) {&lt;br /&gt;
        targetContent += element.textContent;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    for (var index = 1; index &amp;lt; targetParent.children.length; index++) {&lt;br /&gt;
      var element = targetParent.children[index];&lt;br /&gt;
&lt;br /&gt;
      if (element.checkVisibility()) {&lt;br /&gt;
        targetContent += element.textContent;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return targetContent.trim();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleBonusVariation(target, bonusVariation, displayName) {&lt;br /&gt;
  var {&lt;br /&gt;
    minValue,&lt;br /&gt;
    maxValue,&lt;br /&gt;
    checkbox,&lt;br /&gt;
    container,&lt;br /&gt;
    disabledText,&lt;br /&gt;
    selectedText,&lt;br /&gt;
    displaySpan,&lt;br /&gt;
  } = bonusVariation;&lt;br /&gt;
&lt;br /&gt;
  var {&lt;br /&gt;
    min: targetMin,&lt;br /&gt;
    max: targetMax,&lt;br /&gt;
    name: targetName,&lt;br /&gt;
    value: targetValue,&lt;br /&gt;
    parentElement: targetParent,&lt;br /&gt;
    tagName,&lt;br /&gt;
  } = target;&lt;br /&gt;
&lt;br /&gt;
  targetMin = Number(targetMin);&lt;br /&gt;
  targetMax = Number(targetMax);&lt;br /&gt;
  targetValue = Number(targetValue);&lt;br /&gt;
&lt;br /&gt;
  var isSkill = tagName === &amp;quot;SELECT&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  if (isSkill) {&lt;br /&gt;
    var options = target.options;&lt;br /&gt;
&lt;br /&gt;
    targetMin = options[0].value;&lt;br /&gt;
    targetMax = options[options.length - 1].value;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  minValue.min = targetMin;&lt;br /&gt;
  minValue.max = targetMax;&lt;br /&gt;
  minValue.defaultValue = targetMin;&lt;br /&gt;
&lt;br /&gt;
  maxValue.min = targetMin;&lt;br /&gt;
  maxValue.max = targetMax;&lt;br /&gt;
  maxValue.defaultValue = targetMin;&lt;br /&gt;
&lt;br /&gt;
  hideElement(disabledText);&lt;br /&gt;
  showElement(selectedText);&lt;br /&gt;
&lt;br /&gt;
  if (displayName) {&lt;br /&gt;
    minValue.value = Math.min(Math.max(minValue.value, targetMin), targetMax);&lt;br /&gt;
    maxValue.value = Math.max(Math.min(maxValue.value, targetMax), targetMin);&lt;br /&gt;
&lt;br /&gt;
    displaySpan.textContent = displayName;&lt;br /&gt;
  } else {&lt;br /&gt;
    var { input, inputName, tabButton } = bonusVariation;&lt;br /&gt;
    var targetContent = getTargetContent(targetParent, targetName, isSkill);&lt;br /&gt;
&lt;br /&gt;
    input.value = targetName;&lt;br /&gt;
    inputName.value = targetContent;&lt;br /&gt;
    displaySpan.textContent = targetContent;&lt;br /&gt;
&lt;br /&gt;
    minValue.value = Math.max(targetValue - 10, targetMin);&lt;br /&gt;
    maxValue.value = Math.min(targetValue + 10, targetMax);&lt;br /&gt;
&lt;br /&gt;
    showElement(container);&lt;br /&gt;
    checkbox.checked = true;&lt;br /&gt;
&lt;br /&gt;
    tabButton.click();&lt;br /&gt;
    tabButton.scrollIntoView(true);&lt;br /&gt;
&lt;br /&gt;
    input.dispatchEvent(newChangeEvent());&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function characterManagement(characters, battle) {&lt;br /&gt;
  var {&lt;br /&gt;
    newCharacterTemplate: characterTemplate,&lt;br /&gt;
    charactersContainer,&lt;br /&gt;
    addNewCharacterButton,&lt;br /&gt;
    saveButton,&lt;br /&gt;
    characterCreation,&lt;br /&gt;
    bonusVariation,&lt;br /&gt;
    defaultText: { unsavedWarning },&lt;br /&gt;
  } = characters;&lt;br /&gt;
&lt;br /&gt;
  Object.keys(characters.savedCharacters).forEach(function (pseudo) {&lt;br /&gt;
    handleNewCharacter(&lt;br /&gt;
      characters,&lt;br /&gt;
      characterTemplate,&lt;br /&gt;
      charactersContainer,&lt;br /&gt;
      battle,&lt;br /&gt;
      pseudo&lt;br /&gt;
    );&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  addNewCharacterButton.addEventListener(&amp;quot;click&amp;quot;, function (event) {&lt;br /&gt;
    if (!characters.unsavedChanges) {&lt;br /&gt;
      addNewCharacter(&lt;br /&gt;
        characters,&lt;br /&gt;
        characterTemplate,&lt;br /&gt;
        charactersContainer,&lt;br /&gt;
        battle&lt;br /&gt;
      );&lt;br /&gt;
    } else {&lt;br /&gt;
      var result = confirm(unsavedWarning);&lt;br /&gt;
&lt;br /&gt;
      if (result) {&lt;br /&gt;
        addNewCharacter(&lt;br /&gt;
          characters,&lt;br /&gt;
          characterTemplate,&lt;br /&gt;
          charactersContainer,&lt;br /&gt;
          battle&lt;br /&gt;
        );&lt;br /&gt;
        saveButtonGreen(saveButton);&lt;br /&gt;
        characters.unsavedChanges = false;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  handleUploadCharacter(&lt;br /&gt;
    characters,&lt;br /&gt;
    characterTemplate,&lt;br /&gt;
    charactersContainer,&lt;br /&gt;
    battle&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  function handleLongPress(target) {&lt;br /&gt;
    if (target.tagName !== &amp;quot;INPUT&amp;quot; &amp;amp;&amp;amp; target.tagName !== &amp;quot;SELECT&amp;quot;) {&lt;br /&gt;
      target = target.querySelector(&amp;quot;input&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      !target ||&lt;br /&gt;
      (target.type !== &amp;quot;number&amp;quot; &amp;amp;&amp;amp;&lt;br /&gt;
        !target.classList.contains(&amp;quot;skill-select&amp;quot;) &amp;amp;&amp;amp;&lt;br /&gt;
        target.name !== &amp;quot;weaponUpgrade&amp;quot;) ||&lt;br /&gt;
      target.classList.contains(&amp;quot;disabled-variation&amp;quot;)&lt;br /&gt;
    ) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    handleBonusVariation(target, bonusVariation, null);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;click&amp;quot;, function (event) {&lt;br /&gt;
    if (event.shiftKey || event.ctrlKey) {&lt;br /&gt;
      handleLongPress(event.target);&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  var longPressTimer;&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;touchstart&amp;quot;, function (event) {&lt;br /&gt;
    longPressTimer = setTimeout(function () {&lt;br /&gt;
      handleLongPress(event.target);&lt;br /&gt;
    }, 800);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;touchend&amp;quot;, function () {&lt;br /&gt;
    clearTimeout(longPressTimer);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;touchmove&amp;quot;, function () {&lt;br /&gt;
    clearTimeout(longPressTimer);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  filterForm(characters, battle);&lt;br /&gt;
  characterCreationListener(characters, battle);&lt;br /&gt;
  handleFocus();&lt;br /&gt;
&lt;br /&gt;
  window.addEventListener(&amp;quot;beforeunload&amp;quot;, function (event) {&lt;br /&gt;
    if (characters.unsavedChanges) {&lt;br /&gt;
      event.preventDefault();&lt;br /&gt;
      return &amp;quot;&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addMonsterElement(characters, battle, monsterVnum, iframeInfo) {&lt;br /&gt;
  var { monsterTemplate, monstersContainer } = characters;&lt;br /&gt;
  var monsterElement = monsterTemplate.cloneNode(true);&lt;br /&gt;
  var spanInput = monsterElement.querySelector(&amp;quot;span.input&amp;quot;);&lt;br /&gt;
  var deleteSvg = monsterElement.querySelector(&amp;quot;svg&amp;quot;);&lt;br /&gt;
  var monsterName = getMonsterName(monsterVnum);&lt;br /&gt;
  var displayName = characters.translateMonsters&lt;br /&gt;
    ? getTranslatedMonsterName(monsterVnum)&lt;br /&gt;
    : monsterName;&lt;br /&gt;
  var link = createWikiLink(monsterName, displayName);&lt;br /&gt;
&lt;br /&gt;
  monsterElement.setAttribute(&amp;quot;tabindex&amp;quot;, &amp;quot;0&amp;quot;);&lt;br /&gt;
  spanInput.appendChild(link);&lt;br /&gt;
  monstersContainer.appendChild(monsterElement);&lt;br /&gt;
  characters.monsterElements[monsterVnum] = monsterElement;&lt;br /&gt;
&lt;br /&gt;
  deleteSvg.addEventListener(&amp;quot;click&amp;quot;, function () {&lt;br /&gt;
    var monster = characters.savedMonsters[monsterVnum];&lt;br /&gt;
    iframeInfo[monster.category].shouldBeUpdated = true;&lt;br /&gt;
&lt;br /&gt;
    deleteMonster(characters, battle, monsterVnum);&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addNewMonster(&lt;br /&gt;
  characters,&lt;br /&gt;
  battle,&lt;br /&gt;
  monsterVnum,&lt;br /&gt;
  monsterImage,&lt;br /&gt;
  iframeInfo,&lt;br /&gt;
  category&lt;br /&gt;
) {&lt;br /&gt;
  if (isValueInArray(monsterVnum, Object.keys(characters.savedMonsters)))&lt;br /&gt;
    return;&lt;br /&gt;
&lt;br /&gt;
  var newMonster = {&lt;br /&gt;
    image: monsterImage,&lt;br /&gt;
    category: category,&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  characters.savedMonsters[monsterVnum] = newMonster;&lt;br /&gt;
&lt;br /&gt;
  addMonsterElement(characters, battle, monsterVnum, iframeInfo);&lt;br /&gt;
  updateSavedMonsters(characters.savedMonsters);&lt;br /&gt;
  addBattleChoice(battle.battleChoice, monsterVnum, newMonster, true);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function translateiFrame(iframeDoc) {&lt;br /&gt;
  const filterName = iframeDoc.getElementById(&amp;quot;filter-name&amp;quot;);&lt;br /&gt;
  const { general, special } = translation;&lt;br /&gt;
  const translatedPlaceholder = special.placeholder;&lt;br /&gt;
&lt;br /&gt;
  if (filterName &amp;amp;&amp;amp; translatedPlaceholder) {&lt;br /&gt;
    filterName.placeholder = translatedPlaceholder;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (const element of iframeDoc.querySelectorAll(&amp;quot;[data-t]&amp;quot;)) {&lt;br /&gt;
    const translateText = general[element.dataset.t];&lt;br /&gt;
&lt;br /&gt;
    if (translateText) {&lt;br /&gt;
      element.textContent = translateText;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function translateMonsterCard(card, cardNameElement, monsterVnum) {&lt;br /&gt;
  const mapping = translation.mapping;&lt;br /&gt;
  const levelElement = card.querySelector(&amp;quot;[data-level]&amp;quot;);&lt;br /&gt;
  const typeElement = card.querySelector(&amp;quot;[data-type] a&amp;quot;);&lt;br /&gt;
  const damageElements = card.querySelectorAll(&amp;quot;[data-damage] a&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  cardNameElement.textContent = getTranslatedMonsterName(monsterVnum);&lt;br /&gt;
&lt;br /&gt;
  levelElement.textContent = levelElement.textContent.replace(&lt;br /&gt;
    &amp;quot;Boss&amp;quot;,&lt;br /&gt;
    translation.special.boss&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  if (typeElement) {&lt;br /&gt;
    typeElement.textContent = mapping[typeElement.textContent];&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  damageElements.forEach((damageElement) =&amp;gt; {&lt;br /&gt;
    damageElement.textContent = mapping[damageElement.textContent];&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addButtonsToCardsAndTranslate(&lt;br /&gt;
  characters,&lt;br /&gt;
  iframeDoc,&lt;br /&gt;
  iframeInfo,&lt;br /&gt;
  category&lt;br /&gt;
) {&lt;br /&gt;
  const buttonTemplates = characters.monsterButtonTemplates.children[0];&lt;br /&gt;
  const cardToEdit = iframeDoc.getElementById(&amp;quot;cards-container&amp;quot;).children;&lt;br /&gt;
  const { nameToVnum } = iframeInfo;&lt;br /&gt;
  const vnumToButtons = iframeInfo[category].vnumToButtons;&lt;br /&gt;
  const translateMonsters = characters.translateMonsters;&lt;br /&gt;
&lt;br /&gt;
  for (let cardIndex = 0; cardIndex &amp;lt; cardToEdit.length; cardIndex++) {&lt;br /&gt;
    const card = cardToEdit[cardIndex];&lt;br /&gt;
    const cardNameElement = card.querySelector(&amp;quot;[data-name]&amp;quot;).firstChild;&lt;br /&gt;
    const buttonTemplatesClone = buttonTemplates.cloneNode(true);&lt;br /&gt;
    const cardName = cardNameElement.title.replace(/\s/g, &amp;quot; &amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (!nameToVnum.hasOwnProperty(cardName)) {&lt;br /&gt;
      hideElement(card);&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    const monsterVnum = nameToVnum[cardName];&lt;br /&gt;
&lt;br /&gt;
    buttonTemplatesClone.dataset.monsterId = monsterVnum;&lt;br /&gt;
    card.lastElementChild.appendChild(buttonTemplatesClone);&lt;br /&gt;
    vnumToButtons[monsterVnum] = buttonTemplatesClone.children;&lt;br /&gt;
&lt;br /&gt;
    if (translateMonsters) {&lt;br /&gt;
      translateMonsterCard(card, cardNameElement, monsterVnum);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (translateMonsters) {&lt;br /&gt;
    translateiFrame(iframeDoc);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateiFrameButtons(characters, iframeInfo, category) {&lt;br /&gt;
  var addedMonsters = Object.keys(characters.savedMonsters);&lt;br /&gt;
  var { currentiFrameIsMonster } = iframeInfo;&lt;br /&gt;
  var vnumToButtons = iframeInfo[category].vnumToButtons;&lt;br /&gt;
  var isPolymorphModal = category === &amp;quot;monster&amp;quot; &amp;amp;&amp;amp; !currentiFrameIsMonster;&lt;br /&gt;
&lt;br /&gt;
  for (var monsterVnum in vnumToButtons) {&lt;br /&gt;
    var [addButton, deleteButton, selectButton] = vnumToButtons[monsterVnum];&lt;br /&gt;
&lt;br /&gt;
    if (isPolymorphModal) {&lt;br /&gt;
      hideElement(addButton);&lt;br /&gt;
      hideElement(deleteButton);&lt;br /&gt;
      showElement(selectButton);&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isValueInArray(monsterVnum, addedMonsters)) {&lt;br /&gt;
      hideElement(addButton);&lt;br /&gt;
      showElement(deleteButton);&lt;br /&gt;
      hideElement(selectButton);&lt;br /&gt;
    } else {&lt;br /&gt;
      showElement(addButton);&lt;br /&gt;
      hideElement(deleteButton);&lt;br /&gt;
      hideElement(selectButton);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  iframeInfo.lastiFrameIsMonster = currentiFrameIsMonster;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getMonsterImage(buttonsContainer) {&lt;br /&gt;
  var elder = buttonsContainer.parentElement.firstElementChild;&lt;br /&gt;
  var image = elder.querySelector(&amp;quot;img&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (image) {&lt;br /&gt;
    return image.getAttribute(&amp;quot;src&amp;quot;) || &amp;quot;&amp;quot;;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return &amp;quot;&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleiFrame(iframeInfo, category) {&lt;br /&gt;
  var { characters, battle } = iframeInfo;&lt;br /&gt;
  var iframeInfoCategory = iframeInfo[category];&lt;br /&gt;
  var { iframe, pageName, vnumToButtons } = iframeInfoCategory;&lt;br /&gt;
  var loadingAnimation = iframeInfoCategory.iframe.previousElementSibling;&lt;br /&gt;
&lt;br /&gt;
  iframe.src = mw.util.getUrl(pageName);&lt;br /&gt;
&lt;br /&gt;
  window.addEventListener(&amp;quot;message&amp;quot;, function (event) {&lt;br /&gt;
    if (&lt;br /&gt;
      event.origin !== window.origin ||&lt;br /&gt;
      event.data?.type !== &amp;quot;filterReady&amp;quot; ||&lt;br /&gt;
      event.data.category !== category&lt;br /&gt;
    ) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
    var iframeDoc = iframe.contentDocument || iframe.contentWindow.document;&lt;br /&gt;
    var htmlElement = iframeDoc.documentElement;&lt;br /&gt;
    var iframeBody = iframeDoc.body;&lt;br /&gt;
    var content = iframeDoc.getElementById(&amp;quot;show-after-loading&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    htmlElement.setAttribute(&amp;quot;lang&amp;quot;, characters.currentLanguage);&lt;br /&gt;
    iframeBody.firstElementChild.replaceWith(content);&lt;br /&gt;
&lt;br /&gt;
    iframeBody.style.background = &amp;quot;transparent&amp;quot;;&lt;br /&gt;
    iframeBody.style.paddingRight = &amp;quot;10px&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    addButtonsToCardsAndTranslate(characters, iframeDoc, iframeInfo, category);&lt;br /&gt;
    updateiFrameButtons(characters, iframeInfo, category);&lt;br /&gt;
&lt;br /&gt;
    iframeInfoCategory.loadIsFinished = true;&lt;br /&gt;
&lt;br /&gt;
    hideElement(loadingAnimation);&lt;br /&gt;
    showElement(iframe);&lt;br /&gt;
&lt;br /&gt;
    iframeDoc.addEventListener(&amp;quot;click&amp;quot;, handleButtonClick);&lt;br /&gt;
&lt;br /&gt;
    function handleButtonClick(event) {&lt;br /&gt;
      var target = event.target;&lt;br /&gt;
      var link = target.closest(&amp;quot;a&amp;quot;);&lt;br /&gt;
      var buttonsContainer = target.closest(&amp;quot;.handle-monster&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
      if (link) {&lt;br /&gt;
        event.preventDefault();&lt;br /&gt;
        window.open(link.href, &amp;quot;_blank&amp;quot;);&lt;br /&gt;
      } else if (buttonsContainer) {&lt;br /&gt;
        var { monsterId: monsterVnum } = buttonsContainer.dataset;&lt;br /&gt;
&lt;br /&gt;
        // polymorph iframe&lt;br /&gt;
        if (category === &amp;quot;monster&amp;quot; &amp;amp;&amp;amp; !iframeInfo.currentiFrameIsMonster) {&lt;br /&gt;
          var monsterImage = getMonsterImage(buttonsContainer);&lt;br /&gt;
          changePolymorphValues(&lt;br /&gt;
            characters.characterCreation,&lt;br /&gt;
            monsterVnum,&lt;br /&gt;
            monsterImage&lt;br /&gt;
          );&lt;br /&gt;
          handlePolymorphDisplay(characters, monsterVnum, monsterImage);&lt;br /&gt;
          iframe.dispatchEvent(newChangeEvent());&lt;br /&gt;
        } else {&lt;br /&gt;
          var addedMonsters = Object.keys(characters.savedMonsters);&lt;br /&gt;
          var [addButton, deleteButton] = vnumToButtons[monsterVnum];&lt;br /&gt;
&lt;br /&gt;
          if (isValueInArray(monsterVnum, addedMonsters)) {&lt;br /&gt;
            deleteMonster(characters, battle, monsterVnum);&lt;br /&gt;
            showElement(addButton);&lt;br /&gt;
            hideElement(deleteButton);&lt;br /&gt;
          } else {&lt;br /&gt;
            var monsterImage = getMonsterImage(buttonsContainer);&lt;br /&gt;
            addNewMonster(&lt;br /&gt;
              characters,&lt;br /&gt;
              battle,&lt;br /&gt;
              monsterVnum,&lt;br /&gt;
              monsterImage,&lt;br /&gt;
              iframeInfo,&lt;br /&gt;
              category&lt;br /&gt;
            );&lt;br /&gt;
            hideElement(addButton);&lt;br /&gt;
            showElement(deleteButton);&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getNameToVnumMapping() {&lt;br /&gt;
  var nameToVnum = {};&lt;br /&gt;
&lt;br /&gt;
  for (var monsterVnum in monsterData) {&lt;br /&gt;
    nameToVnum[monsterData[monsterVnum][monsterData[monsterVnum].length - 1]] =&lt;br /&gt;
      monsterVnum;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return nameToVnum;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function monsterManagement(characters, battle) {&lt;br /&gt;
  var { monsteriFrame, stoneiFrame } = characters;&lt;br /&gt;
  var monsterVnums = Object.keys(monsterData);&lt;br /&gt;
&lt;br /&gt;
  var iframeInfo = {&lt;br /&gt;
    lastiFrameIsMonster: false,&lt;br /&gt;
    currentiFrameIsMonster: false,&lt;br /&gt;
    characters: characters,&lt;br /&gt;
    battle: battle,&lt;br /&gt;
    nameToVnum: getNameToVnumMapping(),&lt;br /&gt;
    monster: {&lt;br /&gt;
      isLoaded: false,&lt;br /&gt;
      loadIsFinished: false,&lt;br /&gt;
      shouldBeUpdated: false,&lt;br /&gt;
      vnumToButtons: {},&lt;br /&gt;
      pageName: &amp;quot;Monstres&amp;quot;,&lt;br /&gt;
      iframe: monsteriFrame,&lt;br /&gt;
    },&lt;br /&gt;
    stone: {&lt;br /&gt;
      isLoaded: false,&lt;br /&gt;
      loadIsFinished: false,&lt;br /&gt;
      shouldBeUpdated: false,&lt;br /&gt;
      vnumToButtons: {},&lt;br /&gt;
      pageName: &amp;quot;Pierres Metin&amp;quot;,&lt;br /&gt;
      iframe: stoneiFrame,&lt;br /&gt;
    },&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  document.addEventListener(&amp;quot;modalOpen&amp;quot;, function (event) {&lt;br /&gt;
    var modalName = event.detail.name;&lt;br /&gt;
&lt;br /&gt;
    if (modalName === &amp;quot;monster&amp;quot; || modalName === &amp;quot;stone&amp;quot;) {&lt;br /&gt;
      handleModal(event.target, modalName);&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  function handleModal(target, modalName) {&lt;br /&gt;
    var iframeInfoCategory = iframeInfo[modalName];&lt;br /&gt;
&lt;br /&gt;
    if (modalName === &amp;quot;monster&amp;quot;) {&lt;br /&gt;
      var isMonsteriFrame = target.id === &amp;quot;add-new-monster&amp;quot;;&lt;br /&gt;
      iframeInfo.currentiFrameIsMonster = isMonsteriFrame;&lt;br /&gt;
&lt;br /&gt;
      if (&lt;br /&gt;
        iframeInfoCategory.loadIsFinished &amp;amp;&amp;amp;&lt;br /&gt;
        ((isMonsteriFrame &amp;amp;&amp;amp; !iframeInfo.lastiFrameIsMonster) ||&lt;br /&gt;
          (!isMonsteriFrame &amp;amp;&amp;amp; iframeInfo.lastiFrameIsMonster))&lt;br /&gt;
      ) {&lt;br /&gt;
        iframeInfoCategory.shouldBeUpdated = true;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!iframeInfoCategory.isLoaded) {&lt;br /&gt;
      handleiFrame(iframeInfo, modalName);&lt;br /&gt;
      iframeInfoCategory.isLoaded = true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      iframeInfoCategory.loadIsFinished &amp;amp;&amp;amp;&lt;br /&gt;
      iframeInfoCategory.shouldBeUpdated&lt;br /&gt;
    ) {&lt;br /&gt;
      updateiFrameButtons(characters, iframeInfo, modalName);&lt;br /&gt;
      iframeInfoCategory.shouldBeUpdated = false;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  Object.keys(characters.savedMonsters)&lt;br /&gt;
    .slice()&lt;br /&gt;
    .forEach(function (monsterVnum) {&lt;br /&gt;
      if (isValueInArray(monsterVnum, monsterVnums)) {&lt;br /&gt;
        addMonsterElement(characters, battle, monsterVnum, iframeInfo);&lt;br /&gt;
      } else {&lt;br /&gt;
        deleteMonster(characters, battle, monsterVnum);&lt;br /&gt;
      }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function hideAttackType(container, input, attackType) {&lt;br /&gt;
  hideElement(container);&lt;br /&gt;
&lt;br /&gt;
  if (input.checked) {&lt;br /&gt;
    var defaultInput = attackType.defaultInput;&lt;br /&gt;
&lt;br /&gt;
    input.checked = false;&lt;br /&gt;
    defaultInput.checked = true;&lt;br /&gt;
    defaultInput.dispatchEvent(newChangeEvent());&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterAttackTypeSelectionCharacter(attacker, attackType) {&lt;br /&gt;
  var attackerClass = attacker.class;&lt;br /&gt;
  var attackerIsNotPolymorph = !isPolymorph(attacker);&lt;br /&gt;
  var { elements: attackTypeElements } = attackType;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; attackTypeElements.length; index++) {&lt;br /&gt;
    var { container, input, inputClass, inputValue } =&lt;br /&gt;
      attackTypeElements[index];&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      attackerIsNotPolymorph &amp;amp;&amp;amp;&lt;br /&gt;
      attacker[inputValue] &amp;amp;&amp;amp;&lt;br /&gt;
      (attackerClass === inputClass ||&lt;br /&gt;
        (inputValue.startsWith(&amp;quot;horseSkill&amp;quot;) &amp;amp;&amp;amp;&lt;br /&gt;
          isRiding(attacker) &amp;amp;&amp;amp;&lt;br /&gt;
          (!inputClass || isValueInArray(attackerClass, inputClass))))&lt;br /&gt;
    ) {&lt;br /&gt;
      showElement(container);&lt;br /&gt;
    } else {&lt;br /&gt;
      hideAttackType(container, input, attackType);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterAttackTypeSelectionMonster(attackType) {&lt;br /&gt;
  var attackTypeElements = attackType.elements;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; attackTypeElements.length; index++) {&lt;br /&gt;
    var { container, input } = attackTypeElements[index];&lt;br /&gt;
    hideAttackType(container, input, attackType);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function removeBattleElement(battleChoice, nameOrVnum, category, type) {&lt;br /&gt;
  var elements = battleChoice[category][type].elements;&lt;br /&gt;
&lt;br /&gt;
  if (elements.hasOwnProperty(nameOrVnum)) {&lt;br /&gt;
    elements[nameOrVnum].container.remove();&lt;br /&gt;
    delete elements[nameOrVnum];&lt;br /&gt;
    battleChoice[category][type].count--;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function removeBattleChoice(battleChoice, nameOrVnum, type) {&lt;br /&gt;
  battleChoice.categories.forEach(function (category) {&lt;br /&gt;
    if (category === &amp;quot;attacker&amp;quot; &amp;amp;&amp;amp; type === &amp;quot;stone&amp;quot;) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
    var selected = battleChoice[category].selected;&lt;br /&gt;
&lt;br /&gt;
    if (selected) {&lt;br /&gt;
      var { type: selectedType, nameOrVnum: selectedNameOrVnum } =&lt;br /&gt;
        parseTypeAndName(selected);&lt;br /&gt;
&lt;br /&gt;
      if (nameOrVnum === selectedNameOrVnum &amp;amp;&amp;amp; type === selectedType) {&lt;br /&gt;
        resetBattleChoiceButton(battleChoice, category);&lt;br /&gt;
        battleChoice[category].selected = null;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    removeBattleElement(battleChoice, nameOrVnum, category, type);&lt;br /&gt;
    updateBattleChoiceText(battleChoice, category, type);&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addBattleElement(&lt;br /&gt;
  battleChoice,&lt;br /&gt;
  pseudoOrVnum,&lt;br /&gt;
  characterOrMonster,&lt;br /&gt;
  category,&lt;br /&gt;
  isMonster&lt;br /&gt;
) {&lt;br /&gt;
  var { template, raceToImage, translateMonsters } = battleChoice;&lt;br /&gt;
  var battleChoiceCategory = battleChoice[category];&lt;br /&gt;
  var templateClone = template.cloneNode(true);&lt;br /&gt;
  var label = templateClone.firstElementChild;&lt;br /&gt;
  var [input, image, span] = label.children;&lt;br /&gt;
  var imageSrc;&lt;br /&gt;
  var name;&lt;br /&gt;
  var type;&lt;br /&gt;
&lt;br /&gt;
  if (isMonster) {&lt;br /&gt;
    type = characterOrMonster.category;&lt;br /&gt;
&lt;br /&gt;
    if (type === &amp;quot;stone&amp;quot; &amp;amp;&amp;amp; category === &amp;quot;attacker&amp;quot;) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
    imageSrc = characterOrMonster.image;&lt;br /&gt;
    name = translateMonsters&lt;br /&gt;
      ? getTranslatedMonsterName(pseudoOrVnum)&lt;br /&gt;
      : getMonsterName(pseudoOrVnum);&lt;br /&gt;
  } else {&lt;br /&gt;
    type = &amp;quot;character&amp;quot;;&lt;br /&gt;
    imageSrc = raceToImage[characterOrMonster.race];&lt;br /&gt;
    name = pseudoOrVnum;&lt;br /&gt;
    label.classList.add(&amp;quot;notranslate&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var value = type + &amp;quot;-&amp;quot; + pseudoOrVnum;&lt;br /&gt;
  var id = category + &amp;quot;-&amp;quot; + value;&lt;br /&gt;
  var currentBattleChoice = battleChoiceCategory[type];&lt;br /&gt;
&lt;br /&gt;
  label.setAttribute(&amp;quot;for&amp;quot;, id);&lt;br /&gt;
  input.value = value;&lt;br /&gt;
  input.id = id;&lt;br /&gt;
  input.name = category;&lt;br /&gt;
  span.textContent = name;&lt;br /&gt;
&lt;br /&gt;
  handleImageFromWiki(image, imageSrc);&lt;br /&gt;
&lt;br /&gt;
  currentBattleChoice.container.appendChild(templateClone);&lt;br /&gt;
  currentBattleChoice.count++;&lt;br /&gt;
  currentBattleChoice.elements[pseudoOrVnum] = {&lt;br /&gt;
    container: templateClone,&lt;br /&gt;
    image: image,&lt;br /&gt;
    name: name,&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  updateBattleChoiceText(battleChoice, category, type);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addBattleChoice(&lt;br /&gt;
  battleChoice,&lt;br /&gt;
  pseudoOrVnum,&lt;br /&gt;
  characterOrMonster,&lt;br /&gt;
  isMonster = false&lt;br /&gt;
) {&lt;br /&gt;
  addBattleElement(&lt;br /&gt;
    battleChoice,&lt;br /&gt;
    pseudoOrVnum,&lt;br /&gt;
    characterOrMonster,&lt;br /&gt;
    &amp;quot;attacker&amp;quot;,&lt;br /&gt;
    isMonster&lt;br /&gt;
  );&lt;br /&gt;
  addBattleElement(&lt;br /&gt;
    battleChoice,&lt;br /&gt;
    pseudoOrVnum,&lt;br /&gt;
    characterOrMonster,&lt;br /&gt;
    &amp;quot;victim&amp;quot;,&lt;br /&gt;
    isMonster&lt;br /&gt;
  );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateBattleChoiceImage(battleChoice, characterName, newRace) {&lt;br /&gt;
  var imageSrc = battleChoice.raceToImage[newRace];&lt;br /&gt;
&lt;br /&gt;
  battleChoice.categories.forEach(function (category) {&lt;br /&gt;
    handleImageFromWiki(&lt;br /&gt;
      battleChoice[category].character.elements[characterName].image,&lt;br /&gt;
      imageSrc&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    var selected = battleChoice[category].selected;&lt;br /&gt;
&lt;br /&gt;
    if (isCharacterSelected(characterName, selected)) {&lt;br /&gt;
      updateBattleChoiceButton(battleChoice, category, selected);&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateBattleChoiceText(battleChoice, category, type) {&lt;br /&gt;
  var { count, container } = battleChoice[category][type];&lt;br /&gt;
  var parentContainer = container.parentElement;&lt;br /&gt;
&lt;br /&gt;
  if (count === 0) {&lt;br /&gt;
    hideElement(parentContainer);&lt;br /&gt;
    showElement(parentContainer.nextElementSibling);&lt;br /&gt;
  } else if (count === 1) {&lt;br /&gt;
    showElement(parentContainer);&lt;br /&gt;
    hideElement(parentContainer.nextElementSibling);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateBattleChoice(characters, battleChoice) {&lt;br /&gt;
  var templateImage = battleChoice.template.querySelector(&amp;quot;img&amp;quot;);&lt;br /&gt;
  var attackerImage = battleChoice.attacker.buttonContent.querySelector(&amp;quot;img&amp;quot;);&lt;br /&gt;
  var victimImage = battleChoice.victim.buttonContent.querySelector(&amp;quot;img&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  resetImageFromWiki(templateImage);&lt;br /&gt;
  resetImageFromWiki(attackerImage);&lt;br /&gt;
  resetImageFromWiki(victimImage);&lt;br /&gt;
&lt;br /&gt;
  for (var [pseudo, character] of Object.entries(characters.savedCharacters)) {&lt;br /&gt;
    addBattleChoice(battleChoice, pseudo, character);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (var [vnum, monster] of Object.entries(characters.savedMonsters)) {&lt;br /&gt;
    addBattleChoice(battleChoice, vnum, monster, true);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateBattleChoiceButton(battleChoice, category, data) {&lt;br /&gt;
  var battleChoiceCategory = battleChoice[category];&lt;br /&gt;
  var { defaultButtonContent, buttonContent } = battleChoiceCategory;&lt;br /&gt;
  var [buttonImage, buttonSpan] = buttonContent.firstElementChild.children;&lt;br /&gt;
  var { type, nameOrVnum } = parseTypeAndName(data);&lt;br /&gt;
  var { name, image } = battleChoiceCategory[type].elements[nameOrVnum];&lt;br /&gt;
&lt;br /&gt;
  hideElement(defaultButtonContent);&lt;br /&gt;
  showElement(buttonContent);&lt;br /&gt;
&lt;br /&gt;
  buttonSpan.textContent = name;&lt;br /&gt;
  buttonImage.src = image.src;&lt;br /&gt;
  battleChoiceCategory.selected = data;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function resetBattleChoiceButton(battleChoice, category) {&lt;br /&gt;
  var { defaultButtonContent, buttonContent } = battleChoice[category];&lt;br /&gt;
&lt;br /&gt;
  showElement(defaultButtonContent);&lt;br /&gt;
  hideElement(buttonContent);&lt;br /&gt;
&lt;br /&gt;
  if (category === &amp;quot;attacker&amp;quot;) {&lt;br /&gt;
    filterAttackTypeSelectionMonster(battleChoice.attackType);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isPC(character) {&lt;br /&gt;
  if (character.race === 0 || character.race === 1) {&lt;br /&gt;
    return false;&lt;br /&gt;
  }&lt;br /&gt;
  return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isBoss(character) {&lt;br /&gt;
  return character.race === 0 &amp;amp;&amp;amp; character.rank &amp;gt;= 5;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isStone(character) {&lt;br /&gt;
  return character.race === 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isMeleeAttacker(monster) {&lt;br /&gt;
  return monster.attack == 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isRangeAttacker(monster) {&lt;br /&gt;
  return monster.attack == 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isMagicAttacker(monster) {&lt;br /&gt;
  return monster.attack == 2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isMagicClass(character) {&lt;br /&gt;
  return character.race === &amp;quot;shaman&amp;quot; || character.class === &amp;quot;black_magic&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isDispell(character, skillId) {&lt;br /&gt;
  return character.class === &amp;quot;weaponary&amp;quot; &amp;amp;&amp;amp; skillId === 6;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isPolymorph(character) {&lt;br /&gt;
  return isChecked(character.isPolymorph);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isRiding(character) {&lt;br /&gt;
  return isChecked(character.isRiding);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isBow(weaponType) {&lt;br /&gt;
  return weaponType === 2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcAttackFactor(attacker, victim) {&lt;br /&gt;
  function calcCoeffK(dex, level) {&lt;br /&gt;
    return Math.min(90, Math.floor((2 * dex + level) / 3));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var K1 = calcCoeffK(attacker.polymorphDex, attacker.level);&lt;br /&gt;
  var K2 = calcCoeffK(victim.polymorphDex, attacker.level);&lt;br /&gt;
&lt;br /&gt;
  var AR = (K1 + 210) / 300;&lt;br /&gt;
  var ER = (((2 * K2 + 5) / (K2 + 95)) * 3) / 10;&lt;br /&gt;
&lt;br /&gt;
  return truncateNumber(AR - ER, 8);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcMainAttackValue(attacker) {&lt;br /&gt;
  var leadership = 0;&lt;br /&gt;
  var weaponGrowth = 0;&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker)) {&lt;br /&gt;
    weaponGrowth = attacker.weapon.growth;&lt;br /&gt;
    leadership = attacker.leadership;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return 2 * (attacker.level + weaponGrowth) + leadership;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcStatAttackValue(character) {&lt;br /&gt;
  switch (character.race) {&lt;br /&gt;
    case &amp;quot;warrior&amp;quot;:&lt;br /&gt;
    case &amp;quot;sura&amp;quot;:&lt;br /&gt;
      return 2 * character.str;&lt;br /&gt;
    case &amp;quot;ninja&amp;quot;:&lt;br /&gt;
      return Math.floor((1 / 4) * (character.str + 7 * character.dex));&lt;br /&gt;
    case &amp;quot;shaman&amp;quot;:&lt;br /&gt;
      return Math.floor((1 / 3) * (5 * character.int + character.dex));&lt;br /&gt;
    case &amp;quot;lycan&amp;quot;:&lt;br /&gt;
      return character.vit + 2 * character.dex;&lt;br /&gt;
    default:&lt;br /&gt;
      return 2 * character.str;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcPvpCriticalAttackRange(minAttackValue, maxAttackValue, growth) {&lt;br /&gt;
  return Array.from(&lt;br /&gt;
    { length: maxAttackValue - minAttackValue + 1 },&lt;br /&gt;
    (_, index) =&amp;gt; (minAttackValue + growth + index) * 2&lt;br /&gt;
  );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcSecondaryAttackValue(attacker, isPlayerVsPlayer) {&lt;br /&gt;
  let attackValueOther = 0;&lt;br /&gt;
&lt;br /&gt;
  let minAttackValue = 0;&lt;br /&gt;
  let maxAttackValue = 0;&lt;br /&gt;
&lt;br /&gt;
  let minAttackValueSlash = 0;&lt;br /&gt;
  let maxAttackValueSlash = 0;&lt;br /&gt;
&lt;br /&gt;
  let type, isSerpent, growth;&lt;br /&gt;
&lt;br /&gt;
  let criticalAttackRange;&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker)) {&lt;br /&gt;
    ({ type, isSerpent, minAttackValue, maxAttackValue, growth } =&lt;br /&gt;
      attacker.weapon);&lt;br /&gt;
&lt;br /&gt;
    if (isSerpent) {&lt;br /&gt;
      minAttackValue = Math.max(0, attacker.minAttackValueRandom - growth);&lt;br /&gt;
      maxAttackValue = Math.max(&lt;br /&gt;
        minAttackValue,&lt;br /&gt;
        attacker.maxAttackValueRandom - growth&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    minAttackValueSlash = Math.min(&lt;br /&gt;
      attacker.minAttackValueSlash,&lt;br /&gt;
      attacker.maxAttackValueSlash&lt;br /&gt;
    );&lt;br /&gt;
    maxAttackValueSlash = Math.max(&lt;br /&gt;
      attacker.minAttackValueSlash,&lt;br /&gt;
      attacker.maxAttackValueSlash&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    attackValueOther += attacker.attackValue;&lt;br /&gt;
&lt;br /&gt;
    if (isBow(type) &amp;amp;&amp;amp; !isPolymorph(attacker)) {&lt;br /&gt;
      attackValueOther += 25;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isPlayerVsPlayer) {&lt;br /&gt;
      criticalAttackRange = calcPvpCriticalAttackRange(&lt;br /&gt;
        minAttackValue,&lt;br /&gt;
        maxAttackValue,&lt;br /&gt;
        growth&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    minAttackValue = attacker.minAttackValue;&lt;br /&gt;
    maxAttackValue = attacker.maxAttackValue;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  minAttackValue += attacker.minAttackValuePolymorph;&lt;br /&gt;
  maxAttackValue += attacker.maxAttackValuePolymorph;&lt;br /&gt;
&lt;br /&gt;
  attackValueOther += attacker.statAttackValue;&lt;br /&gt;
  attackValueOther += attacker.horseAttackValue;&lt;br /&gt;
&lt;br /&gt;
  const weaponInterval = maxAttackValue - minAttackValue + 1;&lt;br /&gt;
  const slashInterval = maxAttackValueSlash - minAttackValueSlash + 1;&lt;br /&gt;
&lt;br /&gt;
  const totalCardinal = weaponInterval * slashInterval * 1_000_000;&lt;br /&gt;
  const minInterval = Math.min(weaponInterval, slashInterval);&lt;br /&gt;
&lt;br /&gt;
  minAttackValue += minAttackValueSlash;&lt;br /&gt;
  maxAttackValue += maxAttackValueSlash;&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    minAttackValue: minAttackValue,&lt;br /&gt;
    maxAttackValue: maxAttackValue,&lt;br /&gt;
    attackValueOther: attackValueOther,&lt;br /&gt;
    totalCardinal: totalCardinal,&lt;br /&gt;
    weights: calcWeights(minAttackValue, maxAttackValue, minInterval),&lt;br /&gt;
    possibleDamageCount: maxAttackValue - minAttackValue + 1,&lt;br /&gt;
    criticalAttackRange: criticalAttackRange,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcMagicAttackValue(attacker, isPlayerVsPlayer) {&lt;br /&gt;
  let minMagicAttackValueSlash = 0;&lt;br /&gt;
  let maxMagicAttackValueSlash = 0;&lt;br /&gt;
&lt;br /&gt;
  let criticalAttackRange;&lt;br /&gt;
&lt;br /&gt;
  let {&lt;br /&gt;
    isSerpent,&lt;br /&gt;
    minMagicAttackValue,&lt;br /&gt;
    maxMagicAttackValue,&lt;br /&gt;
    minAttackValue,&lt;br /&gt;
    maxAttackValue,&lt;br /&gt;
    growth,&lt;br /&gt;
  } = attacker.weapon;&lt;br /&gt;
&lt;br /&gt;
  if (isSerpent) {&lt;br /&gt;
    minMagicAttackValue = Math.max(0, attacker.minMagicAttackValueRandom);&lt;br /&gt;
    maxMagicAttackValue = Math.max(&lt;br /&gt;
      minMagicAttackValue,&lt;br /&gt;
      attacker.maxMagicAttackValueRandom&lt;br /&gt;
    );&lt;br /&gt;
    minAttackValue = Math.max(0, attacker.minAttackValueRandom - growth);&lt;br /&gt;
    maxAttackValue = Math.max(&lt;br /&gt;
      minAttackValue,&lt;br /&gt;
      attacker.maxAttackValueRandom - growth&lt;br /&gt;
    );&lt;br /&gt;
  } else {&lt;br /&gt;
    minMagicAttackValue += growth;&lt;br /&gt;
    maxMagicAttackValue += growth;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (isPlayerVsPlayer) {&lt;br /&gt;
    criticalAttackRange = calcPvpCriticalAttackRange(&lt;br /&gt;
      minAttackValue,&lt;br /&gt;
      maxAttackValue,&lt;br /&gt;
      growth&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  minMagicAttackValueSlash = Math.min(&lt;br /&gt;
    attacker.minMagicAttackValueSlash,&lt;br /&gt;
    attacker.maxMagicAttackValueSlash&lt;br /&gt;
  );&lt;br /&gt;
  maxMagicAttackValueSlash = Math.max(&lt;br /&gt;
    attacker.minMagicAttackValueSlash,&lt;br /&gt;
    attacker.maxMagicAttackValueSlash&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  const weaponInterval = maxMagicAttackValue - minMagicAttackValue + 1;&lt;br /&gt;
  const slashInterval = maxMagicAttackValueSlash - minMagicAttackValueSlash + 1;&lt;br /&gt;
&lt;br /&gt;
  const totalCardinal = weaponInterval * slashInterval * 1_000_000;&lt;br /&gt;
  const minInterval = Math.min(weaponInterval, slashInterval);&lt;br /&gt;
&lt;br /&gt;
  minMagicAttackValue += minMagicAttackValueSlash;&lt;br /&gt;
  maxMagicAttackValue += maxMagicAttackValueSlash;&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    minMagicAttackValue: minMagicAttackValue,&lt;br /&gt;
    maxMagicAttackValue: maxMagicAttackValue,&lt;br /&gt;
    magicAttackValueAugmentation: getMagicAttackValueAugmentation(&lt;br /&gt;
      minMagicAttackValue,&lt;br /&gt;
      maxMagicAttackValue,&lt;br /&gt;
      attacker.magicAttackValue&lt;br /&gt;
    ),&lt;br /&gt;
    totalCardinal: totalCardinal,&lt;br /&gt;
    weights: calcWeights(minMagicAttackValue, maxMagicAttackValue, minInterval),&lt;br /&gt;
    possibleDamageCount: maxMagicAttackValue - minMagicAttackValue + 1,&lt;br /&gt;
    criticalAttackRange: criticalAttackRange,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getPolymorphPower(polymorphPoint, polymorphPowerTable) {&lt;br /&gt;
  return polymorphPowerTable[polymorphPoint];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSkillPower(skillPoint, skillPowerTable) {&lt;br /&gt;
  return skillPowerTable[skillPoint];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getMarriageBonusValue(character, marriageTable, itemName) {&lt;br /&gt;
  let index;&lt;br /&gt;
  const lovePoint = character.lovePoint;&lt;br /&gt;
&lt;br /&gt;
  if (lovePoint &amp;lt; 65) {&lt;br /&gt;
    index = 0;&lt;br /&gt;
  } else if (lovePoint &amp;lt; 80) {&lt;br /&gt;
    index = 1;&lt;br /&gt;
  } else if (lovePoint &amp;lt; 100) {&lt;br /&gt;
    index = 2;&lt;br /&gt;
  } else {&lt;br /&gt;
    index = 3;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return marriageTable[itemName][index];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcDamageWithPrimaryBonuses(damage, bonusValues) {&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.attackValueCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  damage += bonusValues.attackValueMarriage;&lt;br /&gt;
&lt;br /&gt;
  damage = Math.floor(&lt;br /&gt;
    (damage * bonusValues.monsterResistanceMarriageCoeff) / 100&lt;br /&gt;
  );&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.monsterResistanceCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  damage += Math.floor((damage * bonusValues.typeBonusCoeff) / 100);&lt;br /&gt;
  damage +=&lt;br /&gt;
    Math.floor((damage * bonusValues.raceBonusCoeff) / 100) -&lt;br /&gt;
    Math.floor((damage * bonusValues.raceResistanceCoeff) / 100);&lt;br /&gt;
  damage += Math.floor((damage * bonusValues.stoneBonusCoeff) / 100);&lt;br /&gt;
  damage += Math.floor((damage * bonusValues.monsterBonusCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  const elementBonusCoeff = bonusValues.elementBonusCoeff;&lt;br /&gt;
&lt;br /&gt;
  damage +=&lt;br /&gt;
    Math.trunc((damage * elementBonusCoeff[0]) / 10000) +&lt;br /&gt;
    Math.trunc((damage * elementBonusCoeff[1]) / 10000) +&lt;br /&gt;
    Math.trunc((damage * elementBonusCoeff[2]) / 10000) +&lt;br /&gt;
    Math.trunc((damage * elementBonusCoeff[3]) / 10000) +&lt;br /&gt;
    Math.trunc((damage * elementBonusCoeff[4]) / 10000) +&lt;br /&gt;
    Math.trunc((damage * elementBonusCoeff[5]) / 10000);&lt;br /&gt;
&lt;br /&gt;
  damage = Math.floor(damage * bonusValues.damageMultiplier);&lt;br /&gt;
&lt;br /&gt;
  return damage;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcFinalDamage(&lt;br /&gt;
  finalDamage,&lt;br /&gt;
  minPiercingDamage,&lt;br /&gt;
  tempDamage,&lt;br /&gt;
  bonusValues,&lt;br /&gt;
  criticalAttackRange,&lt;br /&gt;
  damageByType&lt;br /&gt;
) {&lt;br /&gt;
  for (let criticalIndex = 0; criticalIndex &amp;lt; 2; criticalIndex++) {&lt;br /&gt;
    if (bonusValues.skipCriticalStep[criticalIndex]) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
    let beforeCriticalDamage = finalDamage;&lt;br /&gt;
    let damageValues = criticalIndex&lt;br /&gt;
      ? criticalAttackRange || [finalDamage]&lt;br /&gt;
      : [0];&lt;br /&gt;
&lt;br /&gt;
    for (let index = 0, len = damageValues.length; index &amp;lt; len; index++) {&lt;br /&gt;
      let afterCriticalDamage = beforeCriticalDamage + damageValues[index];&lt;br /&gt;
&lt;br /&gt;
      for (let piercingIndex = 0; piercingIndex &amp;lt; 2; piercingIndex++) {&lt;br /&gt;
        if (bonusValues.skipPiercingStep[piercingIndex]) {&lt;br /&gt;
          continue;&lt;br /&gt;
        }&lt;br /&gt;
        let damage = afterCriticalDamage;&lt;br /&gt;
&lt;br /&gt;
        if (piercingIndex) {&lt;br /&gt;
          damage += bonusValues.defenseBoost + Math.min(0, minPiercingDamage);&lt;br /&gt;
          damage += Math.floor(&lt;br /&gt;
            (tempDamage * bonusValues.extraPiercingHitCoeff) / 1000&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        damage = Math.floor((damage * bonusValues.averageDamageCoeff) / 100);&lt;br /&gt;
        damage = Math.floor(&lt;br /&gt;
          (damage * bonusValues.averageDamageResistanceCoeff) / 100&lt;br /&gt;
        );&lt;br /&gt;
        damage = Math.floor((damage * bonusValues.skillDamageCoeff) / 100);&lt;br /&gt;
        damage = Math.floor(&lt;br /&gt;
          (damage * bonusValues.skillDamageResistanceCoeff) / 100&lt;br /&gt;
        );&lt;br /&gt;
        damage = Math.floor((damage * bonusValues.rankBonusCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
        if (bonusValues.useDarkProtection) {&lt;br /&gt;
          const { darkProtectionPoint, darkProtectionSp } = bonusValues;&lt;br /&gt;
&lt;br /&gt;
          const damageReduction = Math.floor(damage / 3);&lt;br /&gt;
          const spAbsorption = Math.floor(&lt;br /&gt;
            (damageReduction * darkProtectionPoint) / 100&lt;br /&gt;
          );&lt;br /&gt;
&lt;br /&gt;
          if (spAbsorption &amp;lt;= darkProtectionSp) {&lt;br /&gt;
            damage -= damageReduction;&lt;br /&gt;
          } else {&lt;br /&gt;
            damage -= Math.floor(&lt;br /&gt;
              (darkProtectionSp * 100) / darkProtectionPoint&lt;br /&gt;
            );&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        damage = Math.max(0, damage + bonusValues.defensePercent);&lt;br /&gt;
        damage += Math.min(&lt;br /&gt;
          300,&lt;br /&gt;
          Math.floor((damage * bonusValues.damageBonusCoeff) / 100)&lt;br /&gt;
        );&lt;br /&gt;
        damage = Math.floor((damage * bonusValues.empireMalusCoeff) / 10);&lt;br /&gt;
        damage = Math.floor((damage * bonusValues.sungMaStrBonusCoeff) / 10000);&lt;br /&gt;
        damage -= Math.floor(damage * bonusValues.sungmaStrMalusCoeff);&lt;br /&gt;
&lt;br /&gt;
        damage = Math.floor(&lt;br /&gt;
          (damage * bonusValues.whiteDragonElixirCoeff) / 100&lt;br /&gt;
        );&lt;br /&gt;
        damage = Math.floor(&lt;br /&gt;
          (damage * bonusValues.steelDragonElixirCoeff) / 100&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        damageByType[criticalIndex + 2 * piercingIndex].push(damage);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveFinalDamage(&lt;br /&gt;
  damage,&lt;br /&gt;
  minPiercingDamage,&lt;br /&gt;
  damageWithPrimaryBonuses,&lt;br /&gt;
  bonusValues,&lt;br /&gt;
  criticalAttackRange,&lt;br /&gt;
  damageByType&lt;br /&gt;
) {&lt;br /&gt;
  damage = Math.floor(damage * bonusValues.magicResistanceCoeff);&lt;br /&gt;
  damage = Math.trunc((damage * bonusValues.weaponDefenseCoeff) / 100);&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.tigerStrengthCoeff) / 100);&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.berserkBonusCoeff) / 100);&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.fearBonusCoeff) / 100);&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.blessingBonusCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  calcFinalDamage(&lt;br /&gt;
    damage,&lt;br /&gt;
    minPiercingDamage,&lt;br /&gt;
    damageWithPrimaryBonuses,&lt;br /&gt;
    bonusValues,&lt;br /&gt;
    criticalAttackRange,&lt;br /&gt;
    damageByType&lt;br /&gt;
  );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveFinalSkillDamage(&lt;br /&gt;
  damage,&lt;br /&gt;
  minPiercingDamage,&lt;br /&gt;
  bonusValues,&lt;br /&gt;
  criticalAttackRange,&lt;br /&gt;
  damageByType&lt;br /&gt;
) {&lt;br /&gt;
  damage = Math.floor(damage * bonusValues.magicResistanceCoeff);&lt;br /&gt;
  damage = Math.trunc((damage * bonusValues.weaponDefenseCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  damage -= bonusValues.defense;&lt;br /&gt;
&lt;br /&gt;
  damage = floorMultiplication(damage, bonusValues.skillWardCoeff);&lt;br /&gt;
  damage = floorMultiplication(damage, bonusValues.skillBonusCoeff);&lt;br /&gt;
&lt;br /&gt;
  const tempDamage = Math.floor(&lt;br /&gt;
    (damage * bonusValues.skillBonusByBonusCoeff) / 100&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  damage = Math.floor(&lt;br /&gt;
    (tempDamage * bonusValues.magicAttackValueCoeff) / 100 + 0.5&lt;br /&gt;
  );&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.tigerStrengthCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  calcFinalDamage(&lt;br /&gt;
    damage,&lt;br /&gt;
    minPiercingDamage,&lt;br /&gt;
    tempDamage,&lt;br /&gt;
    bonusValues,&lt;br /&gt;
    criticalAttackRange,&lt;br /&gt;
    damageByType&lt;br /&gt;
  );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function computePolymorphPoint(attacker, victim, polymorphPowerTable) {&lt;br /&gt;
  attacker.polymorphDex = attacker.dex;&lt;br /&gt;
  victim.polymorphDex = victim.dex;&lt;br /&gt;
&lt;br /&gt;
  attacker.minAttackValuePolymorph = 0;&lt;br /&gt;
  attacker.maxAttackValuePolymorph = 0;&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker) &amp;amp;&amp;amp; isPolymorph(attacker)) {&lt;br /&gt;
    var polymorphPowerPct =&lt;br /&gt;
      getPolymorphPower(attacker.polymorphPoint, polymorphPowerTable) / 100;&lt;br /&gt;
    var polymorphMonster = createMonster(&lt;br /&gt;
      attacker.polymorphMonster,&lt;br /&gt;
      null,&lt;br /&gt;
      null,&lt;br /&gt;
      true&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    var polymorphStr = floorMultiplication(&lt;br /&gt;
      polymorphPowerPct,&lt;br /&gt;
      polymorphMonster.str&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    attacker.polymorphDex += floorMultiplication(&lt;br /&gt;
      polymorphPowerPct,&lt;br /&gt;
      polymorphMonster.dex&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    attacker.minAttackValuePolymorph = floorMultiplication(&lt;br /&gt;
      polymorphPowerPct,&lt;br /&gt;
      polymorphMonster.minAttackValue&lt;br /&gt;
    );&lt;br /&gt;
    attacker.maxAttackValuePolymorph = floorMultiplication(&lt;br /&gt;
      polymorphPowerPct,&lt;br /&gt;
      polymorphMonster.maxAttackValue&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    if (!attacker.weapon) {&lt;br /&gt;
      attacker.maxAttackValuePolymorph += 1;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    attacker.attackValue = 0;&lt;br /&gt;
&lt;br /&gt;
    if (isMagicClass(attacker)) {&lt;br /&gt;
      attacker.statAttackValue = 2 * (polymorphStr + attacker.int);&lt;br /&gt;
    } else {&lt;br /&gt;
      attacker.statAttackValue = 2 * (polymorphStr + attacker.str);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function computeHorse(attacker) {&lt;br /&gt;
  attacker.horseAttackValue = 0;&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker) &amp;amp;&amp;amp; isRiding(attacker) &amp;amp;&amp;amp; !isPolymorph(attacker)) {&lt;br /&gt;
    var horseConstant = 30;&lt;br /&gt;
&lt;br /&gt;
    if (attacker.class === &amp;quot;weaponary&amp;quot;) {&lt;br /&gt;
      horseConstant = 60;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    attacker.horseAttackValue = floorMultiplication(&lt;br /&gt;
      2 * attacker.level + attacker.statAttackValue,&lt;br /&gt;
      attacker.horsePoint / horseConstant&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getRankBonus(attacker) {&lt;br /&gt;
  if (!isChecked(attacker.lowRank)) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  switch (attacker.rank) {&lt;br /&gt;
    case &amp;quot;aggressive&amp;quot;:&lt;br /&gt;
      return 1;&lt;br /&gt;
    case &amp;quot;fraudulent&amp;quot;:&lt;br /&gt;
      return 2;&lt;br /&gt;
    case &amp;quot;malicious&amp;quot;:&lt;br /&gt;
      return 3;&lt;br /&gt;
    case &amp;quot;cruel&amp;quot;:&lt;br /&gt;
      return 5;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcElementCoeffPvP(elementBonus, mapping, attacker, victim) {&lt;br /&gt;
  var minElementMalus = 0;&lt;br /&gt;
  var maxDifference = 0;&lt;br /&gt;
  var savedElementDifferences = [];&lt;br /&gt;
  var elementBonusIndex = 0;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; elementBonus.length; index++) {&lt;br /&gt;
    if (!attacker[mapping.elementBonus[index]]) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var elementDifference =&lt;br /&gt;
      attacker[mapping.elementBonus[index]] -&lt;br /&gt;
      victim[mapping.elementResistance[index]];&lt;br /&gt;
&lt;br /&gt;
    if (elementDifference &amp;gt;= 0) {&lt;br /&gt;
      elementBonus[elementBonusIndex] = 10 * elementDifference;&lt;br /&gt;
      minElementMalus -= elementDifference;&lt;br /&gt;
      maxDifference = Math.max(maxDifference, elementDifference);&lt;br /&gt;
      elementBonusIndex++;&lt;br /&gt;
    } else {&lt;br /&gt;
      savedElementDifferences.push(elementDifference);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (!savedElementDifferences.length) {&lt;br /&gt;
    return;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  minElementMalus += maxDifference;&lt;br /&gt;
  savedElementDifferences.sort(compareNumbers);&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; savedElementDifferences.length; index++) {&lt;br /&gt;
    var elementDifference = savedElementDifferences[index];&lt;br /&gt;
&lt;br /&gt;
    elementBonus[elementBonusIndex + index] =&lt;br /&gt;
      10 * Math.max(minElementMalus, elementDifference);&lt;br /&gt;
&lt;br /&gt;
    minElementMalus = Math.min(&lt;br /&gt;
      0,&lt;br /&gt;
      Math.max(minElementMalus, minElementMalus - elementDifference)&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcCriticalHitChance(criticalHitPercentage) {&lt;br /&gt;
  if (criticalHitPercentage &amp;lt;= 9) {&lt;br /&gt;
    return Math.floor((criticalHitPercentage + 5) / 5);&lt;br /&gt;
  }&lt;br /&gt;
  return Math.floor((criticalHitPercentage + 5) / 6);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcCriticalSkillChance(criticalHitPercentage) {&lt;br /&gt;
  if (criticalHitPercentage === 0) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  } else if (criticalHitPercentage &amp;lt;= 9) {&lt;br /&gt;
    return Math.floor((criticalHitPercentage + 7) / 3);&lt;br /&gt;
  }&lt;br /&gt;
  return Math.floor((criticalHitPercentage + 5) / 3);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcPiercingSkillChance(piercingHitPercentage) {&lt;br /&gt;
  if (piercingHitPercentage &amp;lt;= 9) {&lt;br /&gt;
    return Math.floor(piercingHitPercentage / 2);&lt;br /&gt;
  }&lt;br /&gt;
  return 5 + Math.floor((piercingHitPercentage - 10) / 4);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function magicResistanceToCoeff(magicResistance) {&lt;br /&gt;
  if (magicResistance) {&lt;br /&gt;
    return 2000 / (6 * magicResistance + 1000) - 1;&lt;br /&gt;
  }&lt;br /&gt;
  return 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createBattleValues(attacker, victim, battle, skillType) {&lt;br /&gt;
  var {&lt;br /&gt;
    mapping,&lt;br /&gt;
    constants: { polymorphPowerTable, skillPowerTable, marriageTable },&lt;br /&gt;
  } = battle;&lt;br /&gt;
  var calcAttackValues;&lt;br /&gt;
&lt;br /&gt;
  var missPercentage = 0;&lt;br /&gt;
  var attackValueMeleeMagic = 0;&lt;br /&gt;
  var attackValueMarriage = 0;&lt;br /&gt;
  var monsterResistanceMarriage = 0;&lt;br /&gt;
  var monsterResistance = 0;&lt;br /&gt;
  var typeBonus = 0;&lt;br /&gt;
  var raceBonus = 0;&lt;br /&gt;
  var raceResistance = 0;&lt;br /&gt;
  var stoneBonus = 0;&lt;br /&gt;
  var monsterBonus = 0;&lt;br /&gt;
  var elementBonus = [0, 0, 0, 0, 0, 0]; // fire, ice, lightning, earth, darkness, wind, order doesn't matter&lt;br /&gt;
  var defenseMarriage = 0;&lt;br /&gt;
  var damageMultiplier = 1;&lt;br /&gt;
  var useDamage = 1;&lt;br /&gt;
  var defense = victim.defense;&lt;br /&gt;
  var defenseBoost = defense;&lt;br /&gt;
  var magicResistance = 0;&lt;br /&gt;
  var weaponDefense = 0;&lt;br /&gt;
  var tigerStrength = 0;&lt;br /&gt;
  var berserkBonus = 0;&lt;br /&gt;
  var blessingBonus = 0;&lt;br /&gt;
  var fearBonus = 0;&lt;br /&gt;
  var magicAttackValueMeleeMagic = 0;&lt;br /&gt;
  var criticalHitPercentage = attacker.criticalHit;&lt;br /&gt;
  var isPlayerVsPlayer = false;&lt;br /&gt;
  var piercingHitPercentage = attacker.piercingHit;&lt;br /&gt;
  var extraPiercingHitPercentage = Math.max(0, piercingHitPercentage - 100);&lt;br /&gt;
  var averageDamage = 0;&lt;br /&gt;
  var averageDamageResistance = 0;&lt;br /&gt;
  var skillDamage = 0;&lt;br /&gt;
  var skillDamageResistance = 0;&lt;br /&gt;
  var rankBonus = 0;&lt;br /&gt;
  var useDarkProtection = false;&lt;br /&gt;
  var darkProtectionPoint = 0;&lt;br /&gt;
  var defensePercent = 0;&lt;br /&gt;
  var damageBonus = 0;&lt;br /&gt;
  var empireMalus = 0;&lt;br /&gt;
  var sungMaStrBonus = 0;&lt;br /&gt;
  var sungmaStrMalus = 0;&lt;br /&gt;
  var whiteDragonElixir = 0;&lt;br /&gt;
  var steelDragonElixir = 0;&lt;br /&gt;
&lt;br /&gt;
  attacker.statAttackValue = calcStatAttackValue(attacker);&lt;br /&gt;
&lt;br /&gt;
  computePolymorphPoint(attacker, victim, polymorphPowerTable);&lt;br /&gt;
  computeHorse(attacker);&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker)) {&lt;br /&gt;
    if (weaponData.hasOwnProperty(attacker.weapon)) {&lt;br /&gt;
      attacker.weapon = createWeapon(attacker.weapon);&lt;br /&gt;
    } else {&lt;br /&gt;
      attacker.weapon = createWeapon(0);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    attacker.weapon.getValues(attacker.weaponUpgrade);&lt;br /&gt;
&lt;br /&gt;
    attackValueMeleeMagic =&lt;br /&gt;
      attacker.attackValuePercent + Math.min(100, attacker.attackMeleeMagic);&lt;br /&gt;
&lt;br /&gt;
    var weaponType = attacker.weapon.type;&lt;br /&gt;
&lt;br /&gt;
    if (skillType &amp;amp;&amp;amp; attacker.class === &amp;quot;archery&amp;quot;) {&lt;br /&gt;
      if (weaponType !== 2) {&lt;br /&gt;
        useDamage = 0;&lt;br /&gt;
        weaponType = 2;&lt;br /&gt;
      }&lt;br /&gt;
      defense = 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var weaponDefenseName = mapping.defenseWeapon[weaponType];&lt;br /&gt;
    var weaponDefenseBreakName = mapping.breakWeapon[weaponType];&lt;br /&gt;
&lt;br /&gt;
    if (victim.hasOwnProperty(weaponDefenseName)) {&lt;br /&gt;
      weaponDefense = victim[weaponDefenseName];&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isChecked(attacker.whiteDragonElixir)) {&lt;br /&gt;
      whiteDragonElixir = 10;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isPC(victim)) {&lt;br /&gt;
      isPlayerVsPlayer = true;&lt;br /&gt;
&lt;br /&gt;
      if (!skillType) {&lt;br /&gt;
        if (weaponType === 2 &amp;amp;&amp;amp; !isPolymorph(attacker)) {&lt;br /&gt;
          missPercentage = victim.arrowBlock;&lt;br /&gt;
        } else {&lt;br /&gt;
          missPercentage = victim.meleeBlock;&lt;br /&gt;
        }&lt;br /&gt;
        missPercentage +=&lt;br /&gt;
          victim.meleeArrowBlock -&lt;br /&gt;
          (missPercentage * victim.meleeArrowBlock) / 100;&lt;br /&gt;
&lt;br /&gt;
        criticalHitPercentage = calcCriticalHitChance(criticalHitPercentage);&lt;br /&gt;
        berserkBonus = calcBerserkBonus(skillPowerTable, victim);&lt;br /&gt;
        blessingBonus = calcBlessingBonus(skillPowerTable, victim);&lt;br /&gt;
        fearBonus = calcFearBonus(skillPowerTable, victim);&lt;br /&gt;
        averageDamageResistance = victim.averageDamageResistance;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      typeBonus = Math.max(1, attacker.humanBonus - victim.humanResistance);&lt;br /&gt;
      raceBonus = attacker[mapping.raceBonus[victim.race]];&lt;br /&gt;
      raceResistance = victim[mapping.raceResistance[attacker.race]];&lt;br /&gt;
&lt;br /&gt;
      calcElementCoeffPvP(elementBonus, mapping, attacker, victim);&lt;br /&gt;
&lt;br /&gt;
      if (weaponType !== 2 &amp;amp;&amp;amp; attacker.hasOwnProperty(weaponDefenseBreakName)) {&lt;br /&gt;
        weaponDefense -= attacker[weaponDefenseBreakName];&lt;br /&gt;
      }&lt;br /&gt;
    } else {&lt;br /&gt;
      if (isChecked(attacker.isMarried)) {&lt;br /&gt;
        if (isChecked(attacker.loveNecklace)) {&lt;br /&gt;
          attackValueMarriage = getMarriageBonusValue(&lt;br /&gt;
            attacker,&lt;br /&gt;
            marriageTable,&lt;br /&gt;
            &amp;quot;loveNecklace&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isChecked(attacker.loveEarrings)) {&lt;br /&gt;
          criticalHitPercentage += getMarriageBonusValue(&lt;br /&gt;
            attacker,&lt;br /&gt;
            marriageTable,&lt;br /&gt;
            &amp;quot;loveEarrings&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isChecked(attacker.harmonyEarrings)) {&lt;br /&gt;
          piercingHitPercentage += getMarriageBonusValue(&lt;br /&gt;
            attacker,&lt;br /&gt;
            marriageTable,&lt;br /&gt;
            &amp;quot;harmonyEarrings&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (isChecked(attacker.tigerStrength)) {&lt;br /&gt;
        tigerStrength = 40;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      for (var index = 0; index &amp;lt; elementBonus.length; index++) {&lt;br /&gt;
        var elementBonusName = mapping.elementBonus[index];&lt;br /&gt;
        var elementResistanceName = mapping.elementResistance[index];&lt;br /&gt;
&lt;br /&gt;
        if (attacker[elementBonusName] &amp;amp;&amp;amp; victim[elementBonusName]) {&lt;br /&gt;
          elementBonus[index] =&lt;br /&gt;
            50 * (attacker[elementBonusName] - victim[elementResistanceName]);&lt;br /&gt;
        } else {&lt;br /&gt;
          elementBonus[index] = 5 * attacker[elementBonusName];&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      var victimType = victim.type;&lt;br /&gt;
&lt;br /&gt;
      if (victimType !== -1) {&lt;br /&gt;
        typeBonus = attacker[mapping.typeFlag[victimType]];&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      monsterBonus = attacker.monsterBonus;&lt;br /&gt;
&lt;br /&gt;
      if (isStone(victim)) {&lt;br /&gt;
        stoneBonus = attacker.stoneBonus;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (isBoss(victim)) {&lt;br /&gt;
        if (skillType) {&lt;br /&gt;
          skillDamage += attacker.skillBossDamage;&lt;br /&gt;
        } else {&lt;br /&gt;
          averageDamage += attacker.bossDamage;&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (isChecked(attacker.onYohara)) {&lt;br /&gt;
        var sungmaStrDifference = attacker.sungmaStr - attacker.sungmaStrMalus;&lt;br /&gt;
&lt;br /&gt;
        if (sungmaStrDifference &amp;gt;= 0) {&lt;br /&gt;
          sungMaStrBonus = sungmaStrDifference;&lt;br /&gt;
        } else {&lt;br /&gt;
          sungmaStrMalus = 0.5;&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (skillType) {&lt;br /&gt;
      skillDamage += attacker.skillDamage;&lt;br /&gt;
    } else {&lt;br /&gt;
      averageDamage += attacker.averageDamage;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    rankBonus = getRankBonus(attacker);&lt;br /&gt;
    damageBonus = attacker.damageBonus;&lt;br /&gt;
&lt;br /&gt;
    if (isChecked(attacker.empireMalus)) {&lt;br /&gt;
      empireMalus = 1;&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    if (isPC(victim)) {&lt;br /&gt;
      if (isChecked(victim.isMarried)) {&lt;br /&gt;
        if (isChecked(victim.harmonyBracelet)) {&lt;br /&gt;
          monsterResistanceMarriage = getMarriageBonusValue(&lt;br /&gt;
            victim,&lt;br /&gt;
            marriageTable,&lt;br /&gt;
            &amp;quot;harmonyBracelet&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isChecked(victim.harmonyNecklace) &amp;amp;&amp;amp; !skillType) {&lt;br /&gt;
          defenseMarriage = getMarriageBonusValue(&lt;br /&gt;
            victim,&lt;br /&gt;
            marriageTable,&lt;br /&gt;
            &amp;quot;harmonyNecklace&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      monsterResistance = victim.monsterResistance;&lt;br /&gt;
&lt;br /&gt;
      for (var index = 0; index &amp;lt; elementBonus.length; index++) {&lt;br /&gt;
        var elementBonusName = mapping.elementBonus[index];&lt;br /&gt;
        var elementResistanceName = mapping.elementResistance[index];&lt;br /&gt;
&lt;br /&gt;
        if (attacker[elementBonusName]) {&lt;br /&gt;
          elementBonus[index] =&lt;br /&gt;
            80 * (attacker[elementBonusName] - victim[elementResistanceName]);&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (!skillType) {&lt;br /&gt;
        if (isMeleeAttacker(attacker)) {&lt;br /&gt;
          missPercentage = victim.meleeBlock;&lt;br /&gt;
          averageDamageResistance = victim.averageDamageResistance;&lt;br /&gt;
          berserkBonus = calcBerserkBonus(skillPowerTable, victim);&lt;br /&gt;
          blessingBonus = calcBlessingBonus(skillPowerTable, victim);&lt;br /&gt;
          fearBonus = calcFearBonus(skillPowerTable, victim);&lt;br /&gt;
        } else if (isRangeAttacker(attacker)) {&lt;br /&gt;
          missPercentage = victim.arrowBlock;&lt;br /&gt;
          weaponDefense = victim.arrowDefense;&lt;br /&gt;
          averageDamageResistance = victim.averageDamageResistance;&lt;br /&gt;
          berserkBonus = calcBerserkBonus(skillPowerTable, victim);&lt;br /&gt;
          blessingBonus = calcBlessingBonus(skillPowerTable, victim);&lt;br /&gt;
          fearBonus = calcFearBonus(skillPowerTable, victim);&lt;br /&gt;
        } else if (isMagicAttacker(attacker)) {&lt;br /&gt;
          missPercentage = victim.arrowBlock;&lt;br /&gt;
          skillDamageResistance = victim.skillDamageResistance;&lt;br /&gt;
          magicResistance = victim.magicResistance;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        missPercentage +=&lt;br /&gt;
          victim.meleeArrowBlock -&lt;br /&gt;
          (missPercentage * victim.meleeArrowBlock) / 100;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    typeBonus = 1;&lt;br /&gt;
    damageMultiplier = attacker.damageMultiplier;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillType) {&lt;br /&gt;
    criticalHitPercentage = calcCriticalSkillChance(criticalHitPercentage);&lt;br /&gt;
    piercingHitPercentage = calcPiercingSkillChance(piercingHitPercentage);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (isPC(victim)) {&lt;br /&gt;
    if (!skillType &amp;amp;&amp;amp; isChecked(victim.biologist70)) {&lt;br /&gt;
      defenseBoost = Math.floor((defenseBoost * 110) / 100);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    criticalHitPercentage = Math.max(&lt;br /&gt;
      0,&lt;br /&gt;
      criticalHitPercentage - victim.criticalHitResistance&lt;br /&gt;
    );&lt;br /&gt;
    piercingHitPercentage = Math.max(&lt;br /&gt;
      0,&lt;br /&gt;
      piercingHitPercentage - victim.piercingHitResistance&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    if (skillType) {&lt;br /&gt;
      skillDamageResistance = victim.skillDamageResistance;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      victim.useDarkProtection &amp;amp;&amp;amp;&lt;br /&gt;
      victim.class === &amp;quot;black_magic&amp;quot; &amp;amp;&amp;amp;&lt;br /&gt;
      victim.skillDarkProtection&lt;br /&gt;
    ) {&lt;br /&gt;
      useDarkProtection = true;&lt;br /&gt;
      darkProtectionPoint = calcDarkProtectionPoint(skillPowerTable, victim);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isMagicClass(victim)) {&lt;br /&gt;
      defensePercent = (-2 * victim.magicDefense * victim.defensePercent) / 100;&lt;br /&gt;
    } else {&lt;br /&gt;
      defensePercent = (-2 * defenseBoost * victim.defensePercent) / 100;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isChecked(victim.steelDragonElixir)) {&lt;br /&gt;
      steelDragonElixir = 10;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillType === &amp;quot;magic&amp;quot;) {&lt;br /&gt;
    attackValueMeleeMagic = 0;&lt;br /&gt;
    magicAttackValueMeleeMagic =&lt;br /&gt;
      attacker.attackMagic + Math.min(100, attacker.attackMeleeMagic);&lt;br /&gt;
    attackValueMarriage = 0;&lt;br /&gt;
    defense = 0;&lt;br /&gt;
    if (isDispell(attacker, 6)) {&lt;br /&gt;
      typeBonus = 0;&lt;br /&gt;
      raceBonus = 0;&lt;br /&gt;
      raceResistance = 0;&lt;br /&gt;
      stoneBonus = 0;&lt;br /&gt;
      monsterBonus = 0;&lt;br /&gt;
      for (var index = 0; index &amp;lt; elementBonus.length; index++) {&lt;br /&gt;
        elementBonus[index] = 0;&lt;br /&gt;
      }&lt;br /&gt;
    } else {&lt;br /&gt;
      magicResistance = victim.magicResistance;&lt;br /&gt;
    }&lt;br /&gt;
    weaponDefense = 0;&lt;br /&gt;
    calcAttackValues = calcMagicAttackValue;&lt;br /&gt;
  } else {&lt;br /&gt;
    calcAttackValues = calcSecondaryAttackValue;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  missPercentage = Math.min(100, missPercentage);&lt;br /&gt;
  criticalHitPercentage = Math.min(criticalHitPercentage, 100);&lt;br /&gt;
  piercingHitPercentage = Math.min(piercingHitPercentage, 100);&lt;br /&gt;
&lt;br /&gt;
  const bonusValues = {&lt;br /&gt;
    missPercentage: missPercentage,&lt;br /&gt;
    skipCriticalStep: [&lt;br /&gt;
      !Boolean(100 - criticalHitPercentage),&lt;br /&gt;
      !Boolean(criticalHitPercentage),&lt;br /&gt;
    ],&lt;br /&gt;
    skipPiercingStep: [&lt;br /&gt;
      !Boolean(100 - piercingHitPercentage),&lt;br /&gt;
      !Boolean(piercingHitPercentage),&lt;br /&gt;
    ],&lt;br /&gt;
    weaponBonusCoeff: 1,&lt;br /&gt;
    attackValueCoeff: 100 + attackValueMeleeMagic,&lt;br /&gt;
    attackValueMarriage: attackValueMarriage,&lt;br /&gt;
    monsterResistanceMarriageCoeff: 100 - monsterResistanceMarriage,&lt;br /&gt;
    monsterResistanceCoeff: 100 - monsterResistance,&lt;br /&gt;
    typeBonusCoeff: typeBonus,&lt;br /&gt;
    raceBonusCoeff: raceBonus,&lt;br /&gt;
    raceResistanceCoeff: raceResistance,&lt;br /&gt;
    stoneBonusCoeff: stoneBonus,&lt;br /&gt;
    monsterBonusCoeff: monsterBonus,&lt;br /&gt;
    elementBonusCoeff: elementBonus,&lt;br /&gt;
    damageMultiplier: damageMultiplier,&lt;br /&gt;
    useDamage: useDamage,&lt;br /&gt;
    defense: defense,&lt;br /&gt;
    defenseBoost: defenseBoost,&lt;br /&gt;
    defenseMarriage: defenseMarriage,&lt;br /&gt;
    tigerStrengthCoeff: 100 + tigerStrength,&lt;br /&gt;
    magicResistanceCoeff: magicResistanceToCoeff(magicResistance),&lt;br /&gt;
    weaponDefenseCoeff: 100 - weaponDefense,&lt;br /&gt;
    berserkBonusCoeff: 100 + berserkBonus,&lt;br /&gt;
    blessingBonusCoeff: 100 - blessingBonus,&lt;br /&gt;
    fearBonusCoeff: 100 - fearBonus,&lt;br /&gt;
    magicAttackValueCoeff: 100 + magicAttackValueMeleeMagic,&lt;br /&gt;
    extraPiercingHitCoeff: 5 * extraPiercingHitPercentage,&lt;br /&gt;
    averageDamageCoeff: 100 + averageDamage,&lt;br /&gt;
    averageDamageResistanceCoeff: 100 - Math.min(99, averageDamageResistance),&lt;br /&gt;
    skillDamageCoeff: 100 + skillDamage,&lt;br /&gt;
    skillDamageResistanceCoeff: 100 - Math.min(99, skillDamageResistance),&lt;br /&gt;
    useDarkProtection: useDarkProtection,&lt;br /&gt;
    darkProtectionPoint: darkProtectionPoint,&lt;br /&gt;
    darkProtectionSp: victim.darkProtectionSp,&lt;br /&gt;
    rankBonusCoeff: 100 + rankBonus,&lt;br /&gt;
    defensePercent: Math.floor(defensePercent),&lt;br /&gt;
    damageBonusCoeff: Math.min(20, damageBonus),&lt;br /&gt;
    empireMalusCoeff: 10 - empireMalus,&lt;br /&gt;
    sungMaStrBonusCoeff: 10000 + sungMaStrBonus,&lt;br /&gt;
    sungmaStrMalusCoeff: sungmaStrMalus,&lt;br /&gt;
    whiteDragonElixirCoeff: 100 + whiteDragonElixir,&lt;br /&gt;
    steelDragonElixirCoeff: 100 - steelDragonElixir,&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  const damageTypeWeights = [&lt;br /&gt;
    (100 - criticalHitPercentage) *&lt;br /&gt;
      (100 - piercingHitPercentage) *&lt;br /&gt;
      (100 - missPercentage),&lt;br /&gt;
    criticalHitPercentage *&lt;br /&gt;
      (100 - piercingHitPercentage) *&lt;br /&gt;
      (100 - missPercentage),&lt;br /&gt;
    (100 - criticalHitPercentage) *&lt;br /&gt;
      piercingHitPercentage *&lt;br /&gt;
      (100 - missPercentage),&lt;br /&gt;
    criticalHitPercentage * piercingHitPercentage * (100 - missPercentage),&lt;br /&gt;
  ];&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    attacker: attacker,&lt;br /&gt;
    victim: victim,&lt;br /&gt;
    attackFactor: calcAttackFactor(attacker, victim),&lt;br /&gt;
    mainAttackValue: calcMainAttackValue(attacker),&lt;br /&gt;
    attackValues: calcAttackValues(attacker, isPlayerVsPlayer),&lt;br /&gt;
    bonusValues: bonusValues,&lt;br /&gt;
    damageTypeWeights: damageTypeWeights,&lt;br /&gt;
    attackTypeMapping: mapping.attackType,&lt;br /&gt;
    damageWeightedByType: {&lt;br /&gt;
      normalHit: {},&lt;br /&gt;
      criticalHit: {},&lt;br /&gt;
      piercingHit: {},&lt;br /&gt;
      criticalPiercingHit: {},&lt;br /&gt;
    },&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateBattleValues(battleValues, skillFormula, skillInfo) {&lt;br /&gt;
  var weaponBonus = 0;&lt;br /&gt;
  var skillWard = 0;&lt;br /&gt;
  var skillBonus = 0;&lt;br /&gt;
  var skillBonusByBonus = 0;&lt;br /&gt;
  var { attacker: attacker, bonusValues: bonusValues } = battleValues;&lt;br /&gt;
  var {&lt;br /&gt;
    range: [minVariation, maxVariation],&lt;br /&gt;
  } = skillInfo;&lt;br /&gt;
  var variationLength = maxVariation - minVariation + 1;&lt;br /&gt;
&lt;br /&gt;
  if (skillInfo.hasOwnProperty(&amp;quot;weaponBonus&amp;quot;)) {&lt;br /&gt;
    var [weaponType, weaponBonusValue] = skillInfo.weaponBonus;&lt;br /&gt;
&lt;br /&gt;
    if (weaponType === attacker.weapon.type) {&lt;br /&gt;
      weaponBonus = weaponBonusValue;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillInfo.skillBonus) {&lt;br /&gt;
    skillBonus = skillInfo.skillBonus;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillInfo.skillWard) {&lt;br /&gt;
    skillWard = skillInfo.skillWard;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillInfo.skillBonusByBonus) {&lt;br /&gt;
    skillBonusByBonus = skillInfo.skillBonusByBonus;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillInfo.removeWeaponReduction) {&lt;br /&gt;
    bonusValues.weaponDefenseCoeff = 100;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  bonusValues.weaponBonusCoeff = 100 + weaponBonus;&lt;br /&gt;
  bonusValues.skillWardCoeff = 1 - skillWard / 100;&lt;br /&gt;
  bonusValues.skillBonusCoeff = 1 + skillBonus / 100;&lt;br /&gt;
  bonusValues.skillBonusByBonusCoeff = 100 + skillBonusByBonus;&lt;br /&gt;
&lt;br /&gt;
  battleValues.skillFormula = skillFormula;&lt;br /&gt;
  battleValues.skillRange = skillInfo.range;&lt;br /&gt;
  battleValues.attackValues.totalCardinal *= variationLength;&lt;br /&gt;
  battleValues.attackValues.possibleDamageCount *= variationLength;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcWeights(minValue, maxValue, minInterval) {&lt;br /&gt;
  var firstWeightLimit = minValue + minInterval - 1;&lt;br /&gt;
  var lastWeightsLimit = maxValue - minInterval + 1;&lt;br /&gt;
  var weights = [];&lt;br /&gt;
&lt;br /&gt;
  for (var value = minValue; value &amp;lt; firstWeightLimit; value++) {&lt;br /&gt;
    weights.push(value - minValue + 1);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (var value = firstWeightLimit; value &amp;lt;= lastWeightsLimit; value++) {&lt;br /&gt;
    weights.push(minInterval);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (var value = lastWeightsLimit + 1; value &amp;lt;= maxValue; value++) {&lt;br /&gt;
    weights.push(maxValue - value + 1);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return weights;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcBerserkBonus(skillPowerTable, victim) {&lt;br /&gt;
  if (!isChecked(victim.useBerserk) || victim.class !== &amp;quot;body&amp;quot;) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var skillPower = getSkillPower(victim.skillBerserk, skillPowerTable);&lt;br /&gt;
&lt;br /&gt;
  if (!skillPower) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var berserkBonus = Math.floor(skillPower * 25);&lt;br /&gt;
&lt;br /&gt;
  return berserkBonus;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcBlessingBonus(skillPowerTable, victim) {&lt;br /&gt;
  if (!isChecked(victim.isBlessed)) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var int = victim.intBlessing;&lt;br /&gt;
  var dex = victim.dexBlessing;&lt;br /&gt;
  var skillPower = getSkillPower(victim.skillBlessing, skillPowerTable);&lt;br /&gt;
&lt;br /&gt;
  if (!skillPower) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var blessingBonus = floorMultiplication(&lt;br /&gt;
    ((int * 0.3 + 5) * (2 * skillPower + 0.5) + 0.3 * dex) / (skillPower + 2.3),&lt;br /&gt;
    1&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  if (victim.class === &amp;quot;dragon&amp;quot; &amp;amp;&amp;amp; isChecked(victim.blessingOnself)) {&lt;br /&gt;
    blessingBonus = floorMultiplication(blessingBonus, 1.1);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return blessingBonus;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcFearBonus(skillPowerTable, victim) {&lt;br /&gt;
  if (!isChecked(victim.useFear) || victim.class !== &amp;quot;weaponary&amp;quot;) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var skillPower = getSkillPower(victim.skillFear, skillPowerTable);&lt;br /&gt;
&lt;br /&gt;
  if (!skillPower) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var fearBonus = 5 + Math.floor(skillPower * 20);&lt;br /&gt;
&lt;br /&gt;
  return fearBonus;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcDarkProtectionPoint(skillPowerTable, victim) {&lt;br /&gt;
  var skillPower = getSkillPower(victim.skillDarkProtection, skillPowerTable);&lt;br /&gt;
&lt;br /&gt;
  return floorMultiplication(100 - victim.int * 0.84 * skillPower, 1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSkillFormula(battle, skillId, battleValues, removeSkillVariation) {&lt;br /&gt;
  var { attacker, victim, attackFactor } = battleValues;&lt;br /&gt;
  var skillPowerTable = battle.constants.skillPowerTable;&lt;br /&gt;
&lt;br /&gt;
  var skillFormula;&lt;br /&gt;
  var skillInfo = { range: [0, 0] };&lt;br /&gt;
&lt;br /&gt;
  var { class: attackerClass, level: lv, vit, str, int, dex } = attacker;&lt;br /&gt;
&lt;br /&gt;
  if (skillId &amp;lt;= 9) {&lt;br /&gt;
    var skillPower = getSkillPower(&lt;br /&gt;
      attacker[&amp;quot;attackSkill&amp;quot; + skillId],&lt;br /&gt;
      skillPowerTable&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    var improvedBySkillBonus = false;&lt;br /&gt;
    var improvedByBonus = false;&lt;br /&gt;
&lt;br /&gt;
    if (attackerClass === &amp;quot;body&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Triple lacération&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.1 * atk + (0.5 * atk + 1.5 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Moulinet à l'épée&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              3 * atk + (0.8 * atk + 5 * str + 3 * dex + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Accélération&lt;br /&gt;
        case 5:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * atk + (atk + dex * 3 + str * 7 + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Volonté de vivre&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              (3 * atk + (atk + 1.5 * str) * skillPower) * 1.07,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          break;&lt;br /&gt;
        // Tremblement de terre&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              3 * atk +&lt;br /&gt;
                (0.9 * atk + variation + 5 * str + 3 * dex + lv) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;mental&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Attaque de l'esprit&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2.3 * atk + (4 * atk + 4 * str + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Attaque de la paume&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2.3 * atk + (3 * atk + 4 * str + 3 * vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Charge&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * atk + (2 * atk + 2 * dex + 2 * vit + 4 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          break;&lt;br /&gt;
        // Coup d'épée&lt;br /&gt;
        case 5:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * atk + (atk + 3 * dex + 5 * str + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Orbe de l'épée&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              (2 * atk + (2 * atk + 2 * dex + 2 * vit + 4 * str) * skillPower) *&lt;br /&gt;
                1.1,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          break;&lt;br /&gt;
        // Tremblement de terre&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              3 * atk +&lt;br /&gt;
                (0.9 * atk + variation + 5 * str + 3 * dex + lv) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;blade_fight&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Embuscade&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk + (1.2 * atk + variation + 4 * dex + 4 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [1, 50];&lt;br /&gt;
          skillInfo.range = [500, 700];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Attaque rapide&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk + (1.6 * atk + variation + 7 * dex + 7 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [1, 35];&lt;br /&gt;
          skillInfo.range = [200, 300];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Dague filante&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * atk + (0.5 * atk + 9 * dex + 7 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Brume empoisonnée&lt;br /&gt;
        case 5:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * lv + (atk + 3 * str + 18 * dex) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Poison insidieux&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              (2 * lv + (atk + 3 * str + 18 * dex) * skillPower) * 1.1,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          break;&lt;br /&gt;
        // Étoiles brillantes&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk + (1.7 * atk + variation + 6 * dex + 5 * lv) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;archery&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Tir à répétition&lt;br /&gt;
        // case 1:&lt;br /&gt;
        //   skillFormula = function (atk) {&lt;br /&gt;
        //     return floorMultiplication(&lt;br /&gt;
        //       atk + 0.2 * atk * Math.floor(2 + 6 * skillPower) + (0.8 * atk + 8 * dex * attackFactor + 2 * int) * skillPower,&lt;br /&gt;
        //       1&lt;br /&gt;
        //     );&lt;br /&gt;
        //   };&lt;br /&gt;
        //   improvedByBonus = true;&lt;br /&gt;
        //   break;&lt;br /&gt;
        // Pluie de flèches&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk + (1.7 * atk + 5 * dex + str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Flèche de feu&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.5 * atk + (2.6 * atk + 0.9 * int + variation) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [100, 300];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Foulée de plume&lt;br /&gt;
        case 4:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              (3 * dex + 200 + 2 * str + 2 * int) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.removeWeaponReduction = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Flèche empoisonnée&lt;br /&gt;
        case 5:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk +&lt;br /&gt;
                (1.4 * atk + variation + 7 * dex + 4 * str + 4 * int) *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [100, 200];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Coup étincelant&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              (atk +&lt;br /&gt;
                (1.2 * atk + variation + 6 * dex + 3 * str + 3 * int) *&lt;br /&gt;
                  skillPower) *&lt;br /&gt;
                1.2,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [100, 200];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Tir tempête&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.9 * atk + (2.6 * atk + variation) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;weaponary&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Toucher brûlant&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk +&lt;br /&gt;
                2 * lv +&lt;br /&gt;
                2 * int +&lt;br /&gt;
                (2 * atk + 4 * str + 14 * int) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Tourbillon du dragon&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.1 * atk +&lt;br /&gt;
                2 * lv +&lt;br /&gt;
                2 * int +&lt;br /&gt;
                (1.5 * atk + str + 12 * int) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Contre-sort&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              40 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                2 * int +&lt;br /&gt;
                (10 * int + 7 * mav + variation) * attackFactor * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [50, 100];&lt;br /&gt;
          break;&lt;br /&gt;
        // Coup démoniaque&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.9 * atk + (2.6 * atk + variation) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;black_magic&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Attaque des ténèbres&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              40 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                2 * int +&lt;br /&gt;
                (13 * int + 6 * mav + variation) * attackFactor * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [50, 100];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Attaque de flammes&lt;br /&gt;
        // case 2:&lt;br /&gt;
        //   skillFormula = function (mav, variation) {&lt;br /&gt;
        //     return floorMultiplication(&lt;br /&gt;
        //       5 * lv + 2 * int + (7 * int + 8 * mav + 4 * str + 2 * vit + variation) * skillPower,&lt;br /&gt;
        //       1&lt;br /&gt;
        //     );&lt;br /&gt;
        //   };&lt;br /&gt;
        //   skillInfo.range = [180, 100];&lt;br /&gt;
        //   improvedByBonus = true;&lt;br /&gt;
        //   break;&lt;br /&gt;
        // Esprit de flammes&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              30 +&lt;br /&gt;
                2 * lv +&lt;br /&gt;
                2 * int +&lt;br /&gt;
                (7 * int + 6 * mav + variation) * attackFactor * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [200, 500];&lt;br /&gt;
          break;&lt;br /&gt;
        // Frappe de l'esprit&lt;br /&gt;
        // case 5:&lt;br /&gt;
        //   skillFormula = function (mav, variation) {&lt;br /&gt;
        //     return floorMultiplication(&lt;br /&gt;
        //       40 + 2 * lv + 2 * int + (2 * vit + 2 * dex + 13 * int + 6 * mav + variation) * attackFactor * skillPower,&lt;br /&gt;
        //       1&lt;br /&gt;
        //     );&lt;br /&gt;
        //   };&lt;br /&gt;
        //   skillInfo.range = [180, 200];&lt;br /&gt;
        //   break;&lt;br /&gt;
        // Orbe des ténèbres&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (mav) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              120 +&lt;br /&gt;
                6 * lv +&lt;br /&gt;
                (5 * vit + 5 * dex + 29 * int + 9 * mav) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Vague mortelle&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              120 +&lt;br /&gt;
                6 * lv +&lt;br /&gt;
                (5 * vit + 5 * dex + 30 * int + variation + 9 * mav) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;dragon&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Talisman volant&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (mav) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              70 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                (18 * int + 7 * str + 5 * mav + 50) * attackFactor * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [4, 10];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Dragon chassant&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (mav) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              60 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                (16 * int + 6 * dex + 6 * mav + 120) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [4, 10];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Rugissement du dragon&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (mav) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              70 +&lt;br /&gt;
                3 * lv +&lt;br /&gt;
                (20 * int + 3 * str + 10 * mav + 100) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [4, 10];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Météore&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              120 +&lt;br /&gt;
                6 * lv +&lt;br /&gt;
                (5 * vit + 5 * dex + 30 * int + variation + 9 * mav) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;heal&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Jet de foudre&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              60 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                (8 * int + 2 * dex + 8 * mav + variation) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [6, 10];&lt;br /&gt;
          skillInfo.range = [5 * int, 15 * int];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Invocation de foudre&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              40 +&lt;br /&gt;
                4 * lv +&lt;br /&gt;
                (13 * int + 2 * str + 10 * mav + variation) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [6, 10];&lt;br /&gt;
          skillInfo.range = [5 * int, 16 * int];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Griffe de foudre&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              50 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                (8 * int + 2 * str + 8 * mav + variation) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 800];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;lycan&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Déchiqueter&lt;br /&gt;
        // case 1:&lt;br /&gt;
        //   skillFormula = function (atk) {&lt;br /&gt;
        //     return floorMultiplication(&lt;br /&gt;
        //       1.1 * atk + (0.3 * atk + 1.5 * str) * skillPower,&lt;br /&gt;
        //       1&lt;br /&gt;
        //     );&lt;br /&gt;
        //   };&lt;br /&gt;
        //   skillInfo.weaponBonus = [5, 54];&lt;br /&gt;
        //   improvedByBonus = true;&lt;br /&gt;
        //   break;&lt;br /&gt;
        // Souffle de loup&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * atk + (atk + 3 * dex + 5 * str + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [5, 35];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Bond de loup&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk + (1.6 * atk + 200 + 7 * dex + 7 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [5, 35];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Griffe de loup&lt;br /&gt;
        case 4:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              3 * atk + (0.8 * atk + 6 * str + 2 * dex + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Tempête cinglante&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.8 * atk +&lt;br /&gt;
                (atk + 6 * dex + variation + 3 * str + lv) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
    if (improvedBySkillBonus) {&lt;br /&gt;
      skillInfo.skillBonus =&lt;br /&gt;
        16 * getSkillPower(attacker.skillBonus, skillPowerTable);&lt;br /&gt;
&lt;br /&gt;
      var skillWardChoice = victim.skillWardChoice;&lt;br /&gt;
&lt;br /&gt;
      if (skillWardChoice &amp;amp;&amp;amp; skillWardChoice === attackerClass) {&lt;br /&gt;
        skillInfo.skillWard =&lt;br /&gt;
          24 * getSkillPower(victim.skillWard, skillPowerTable);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (improvedByBonus) {&lt;br /&gt;
      skillInfo.skillBonusByBonus = attacker[&amp;quot;skillBonus&amp;quot; + skillId];&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (removeSkillVariation) {&lt;br /&gt;
      var averageVariation = (skillInfo.range[0] + skillInfo.range[0]) / 2;&lt;br /&gt;
      skillInfo.range = [averageVariation, averageVariation];&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    var skillPower = getSkillPower(&lt;br /&gt;
      attacker[&amp;quot;horseSkill&amp;quot; + skillId],&lt;br /&gt;
      skillPowerTable&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    switch (skillId) {&lt;br /&gt;
      // Combat équestre&lt;br /&gt;
      case 137:&lt;br /&gt;
        skillFormula = function (atk) {&lt;br /&gt;
          return floorMultiplication(atk + 2 * atk * skillPower, 1);&lt;br /&gt;
        };&lt;br /&gt;
        break;&lt;br /&gt;
      // Charge à cheval&lt;br /&gt;
      case 138:&lt;br /&gt;
        skillFormula = function (atk) {&lt;br /&gt;
          return floorMultiplication(&lt;br /&gt;
            2.4 * (200 + 1.5 * lv) + 600 * skillPower,&lt;br /&gt;
            1&lt;br /&gt;
          );&lt;br /&gt;
        };&lt;br /&gt;
        break;&lt;br /&gt;
      // Vague de Pouvoir&lt;br /&gt;
      case 139:&lt;br /&gt;
        skillFormula = function (atk) {&lt;br /&gt;
          return floorMultiplication(&lt;br /&gt;
            2 * (200 + 1.5 * lv) + 600 * skillPower,&lt;br /&gt;
            1&lt;br /&gt;
          );&lt;br /&gt;
        };&lt;br /&gt;
        break;&lt;br /&gt;
      // Grêle de flèches&lt;br /&gt;
      case 140:&lt;br /&gt;
        skillFormula = function (atk) {&lt;br /&gt;
          return floorMultiplication(atk + 2 * atk * skillPower, 1);&lt;br /&gt;
        };&lt;br /&gt;
        break;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  updateBattleValues(battleValues, skillFormula, skillInfo);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcMagicAttackValueAugmentation(&lt;br /&gt;
  magicAttackValueWeapon,&lt;br /&gt;
  magicAttackValueBonus&lt;br /&gt;
) {&lt;br /&gt;
  if (magicAttackValueBonus) {&lt;br /&gt;
    return Math.max(&lt;br /&gt;
      1,&lt;br /&gt;
      0.0025056 *&lt;br /&gt;
        magicAttackValueBonus ** 0.602338 *&lt;br /&gt;
        magicAttackValueWeapon ** 1.20476&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
  return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getMagicAttackValueAugmentation(&lt;br /&gt;
  minMagicAttackValue,&lt;br /&gt;
  maxMagicAttackValue,&lt;br /&gt;
  magicAttackValueBonus&lt;br /&gt;
) {&lt;br /&gt;
  var magicAttackValueAugmentation = [];&lt;br /&gt;
&lt;br /&gt;
  for (&lt;br /&gt;
    var magicAttackValue = minMagicAttackValue;&lt;br /&gt;
    magicAttackValue &amp;lt;= maxMagicAttackValue;&lt;br /&gt;
    magicAttackValue++&lt;br /&gt;
  ) {&lt;br /&gt;
    magicAttackValueAugmentation.push(&lt;br /&gt;
      calcMagicAttackValueAugmentation(magicAttackValue, magicAttackValueBonus)&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return magicAttackValueAugmentation;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcPhysicalDamage(battleValues) {&lt;br /&gt;
  const {&lt;br /&gt;
    attackFactor,&lt;br /&gt;
    mainAttackValue,&lt;br /&gt;
    attackValues: {&lt;br /&gt;
      minAttackValue,&lt;br /&gt;
      maxAttackValue,&lt;br /&gt;
      attackValueOther,&lt;br /&gt;
      weights,&lt;br /&gt;
      criticalAttackRange,&lt;br /&gt;
    },&lt;br /&gt;
    bonusValues,&lt;br /&gt;
    damageWeightedByType,&lt;br /&gt;
  } = battleValues;&lt;br /&gt;
&lt;br /&gt;
  const savedDamage = {};&lt;br /&gt;
&lt;br /&gt;
  if (bonusValues.missPercentage) {&lt;br /&gt;
    damageWeightedByType.miss = bonusValues.missPercentage / 100;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (&lt;br /&gt;
    let attackValue = minAttackValue;&lt;br /&gt;
    attackValue &amp;lt;= maxAttackValue;&lt;br /&gt;
    attackValue++&lt;br /&gt;
  ) {&lt;br /&gt;
    const weight = weights[attackValue - minAttackValue];&lt;br /&gt;
    const damageByType = [[], [], [], []];&lt;br /&gt;
    const currentDamageInfo = [weight, damageByType];&lt;br /&gt;
&lt;br /&gt;
    const secondaryAttackValue = 2 * attackValue + attackValueOther;&lt;br /&gt;
    const rawDamage =&lt;br /&gt;
      mainAttackValue + floorMultiplication(attackFactor, secondaryAttackValue);&lt;br /&gt;
&lt;br /&gt;
    const damageWithPrimaryBonuses = calcDamageWithPrimaryBonuses(&lt;br /&gt;
      rawDamage,&lt;br /&gt;
      bonusValues&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    const minPiercingDamage =&lt;br /&gt;
      damageWithPrimaryBonuses -&lt;br /&gt;
      bonusValues.defenseBoost -&lt;br /&gt;
      bonusValues.defenseMarriage;&lt;br /&gt;
&lt;br /&gt;
    const damageValues =&lt;br /&gt;
      minPiercingDamage &amp;lt;= 2 ? [1, 2, 3, 4, 5] : [minPiercingDamage];&lt;br /&gt;
&lt;br /&gt;
    for (const damage of damageValues) {&lt;br /&gt;
      saveFinalDamage(&lt;br /&gt;
        damage,&lt;br /&gt;
        minPiercingDamage,&lt;br /&gt;
        damageWithPrimaryBonuses,&lt;br /&gt;
        bonusValues,&lt;br /&gt;
        criticalAttackRange,&lt;br /&gt;
        damageByType&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    savedDamage[attackValue] = currentDamageInfo;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  processSavedDamage(savedDamage, damageWeightedByType, battleValues);&lt;br /&gt;
&lt;br /&gt;
  return damageWeightedByType;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcPhysicalSkillDamage(battleValues) {&lt;br /&gt;
  const {&lt;br /&gt;
    attackFactor,&lt;br /&gt;
    mainAttackValue,&lt;br /&gt;
    attackValues: {&lt;br /&gt;
      minAttackValue,&lt;br /&gt;
      maxAttackValue,&lt;br /&gt;
      attackValueOther,&lt;br /&gt;
      weights,&lt;br /&gt;
      criticalAttackRange,&lt;br /&gt;
    },&lt;br /&gt;
    bonusValues,&lt;br /&gt;
    damageWeightedByType,&lt;br /&gt;
    skillFormula,&lt;br /&gt;
    skillRange: [minVariation, maxVariation],&lt;br /&gt;
  } = battleValues;&lt;br /&gt;
&lt;br /&gt;
  const savedDamage = {};&lt;br /&gt;
&lt;br /&gt;
  for (&lt;br /&gt;
    let attackValue = minAttackValue;&lt;br /&gt;
    attackValue &amp;lt;= maxAttackValue;&lt;br /&gt;
    attackValue++&lt;br /&gt;
  ) {&lt;br /&gt;
    const weight = weights[attackValue - minAttackValue];&lt;br /&gt;
&lt;br /&gt;
    const secondaryAttackValue = 2 * attackValue + attackValueOther;&lt;br /&gt;
    const rawDamage =&lt;br /&gt;
      mainAttackValue + floorMultiplication(attackFactor, secondaryAttackValue);&lt;br /&gt;
&lt;br /&gt;
    const damageWithPrimaryBonuses = calcDamageWithPrimaryBonuses(&lt;br /&gt;
      rawDamage,&lt;br /&gt;
      bonusValues&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    const damageValues =&lt;br /&gt;
      damageWithPrimaryBonuses &amp;lt;= 2&lt;br /&gt;
        ? [1, 2, 3, 4, 5]&lt;br /&gt;
        : [damageWithPrimaryBonuses];&lt;br /&gt;
&lt;br /&gt;
    for (let variation = minVariation; variation &amp;lt;= maxVariation; variation++) {&lt;br /&gt;
      for (const damage of damageValues) {&lt;br /&gt;
        const damageWithFormula = skillFormula(&lt;br /&gt;
          damage * bonusValues.useDamage,&lt;br /&gt;
          variation&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        let damageKey = damageWithFormula;&lt;br /&gt;
&lt;br /&gt;
        if (damageWithPrimaryBonuses &amp;lt; 0) {&lt;br /&gt;
          damageKey = `${damageWithFormula}_${Math.abs(&lt;br /&gt;
            damageWithPrimaryBonuses&lt;br /&gt;
          )}`;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        const entry = savedDamage[damageKey];&lt;br /&gt;
&lt;br /&gt;
        if (entry) {&lt;br /&gt;
          entry[0] += weight;&lt;br /&gt;
          continue;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        const damageByType = [[], [], [], []];&lt;br /&gt;
        const currentDamageInfo = [weight, damageByType];&lt;br /&gt;
&lt;br /&gt;
        const finalDamage = Math.floor(&lt;br /&gt;
          (damageWithFormula * bonusValues.weaponBonusCoeff) / 100&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        saveFinalSkillDamage(&lt;br /&gt;
          finalDamage,&lt;br /&gt;
          damageWithPrimaryBonuses,&lt;br /&gt;
          bonusValues,&lt;br /&gt;
          criticalAttackRange,&lt;br /&gt;
          damageByType&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        savedDamage[damageKey] = currentDamageInfo;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  processSavedDamage(savedDamage, damageWeightedByType, battleValues);&lt;br /&gt;
&lt;br /&gt;
  return damageWeightedByType;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcMagicSkillDamage(battleValues) {&lt;br /&gt;
  const {&lt;br /&gt;
    attackValues: {&lt;br /&gt;
      minMagicAttackValue,&lt;br /&gt;
      maxMagicAttackValue,&lt;br /&gt;
      magicAttackValueAugmentation,&lt;br /&gt;
      weights,&lt;br /&gt;
      criticalAttackRange,&lt;br /&gt;
    },&lt;br /&gt;
    bonusValues,&lt;br /&gt;
    damageWeightedByType,&lt;br /&gt;
    skillFormula,&lt;br /&gt;
    skillRange: [minVariation, maxVariation],&lt;br /&gt;
  } = battleValues;&lt;br /&gt;
&lt;br /&gt;
  const savedDamage = {};&lt;br /&gt;
&lt;br /&gt;
  for (&lt;br /&gt;
    let magicAttackValue = minMagicAttackValue;&lt;br /&gt;
    magicAttackValue &amp;lt;= maxMagicAttackValue;&lt;br /&gt;
    magicAttackValue++&lt;br /&gt;
  ) {&lt;br /&gt;
    const index = magicAttackValue - minMagicAttackValue;&lt;br /&gt;
    const weight = weights[index];&lt;br /&gt;
&lt;br /&gt;
    for (let variation = minVariation; variation &amp;lt;= maxVariation; variation++) {&lt;br /&gt;
      const rawDamage = skillFormula(&lt;br /&gt;
        magicAttackValue + magicAttackValueAugmentation[index],&lt;br /&gt;
        variation&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      const entry = savedDamage[rawDamage];&lt;br /&gt;
&lt;br /&gt;
      if (entry) {&lt;br /&gt;
        entry[0] += weight;&lt;br /&gt;
        continue;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      const damageByType = [[], [], [], []];&lt;br /&gt;
      const currentDamageInfo = [weight, damageByType];&lt;br /&gt;
&lt;br /&gt;
      let damageWithPrimaryBonuses = Math.floor(&lt;br /&gt;
        (rawDamage * bonusValues.weaponBonusCoeff) / 100&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      damageWithPrimaryBonuses = calcDamageWithPrimaryBonuses(&lt;br /&gt;
        damageWithPrimaryBonuses,&lt;br /&gt;
        bonusValues&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      const damageValues =&lt;br /&gt;
        damageWithPrimaryBonuses &amp;lt;= 2&lt;br /&gt;
          ? [1, 2, 3, 4, 5]&lt;br /&gt;
          : [damageWithPrimaryBonuses];&lt;br /&gt;
&lt;br /&gt;
      for (const damage of damageValues) {&lt;br /&gt;
        saveFinalSkillDamage(&lt;br /&gt;
          damage,&lt;br /&gt;
          damageWithPrimaryBonuses,&lt;br /&gt;
          bonusValues,&lt;br /&gt;
          criticalAttackRange,&lt;br /&gt;
          damageByType&lt;br /&gt;
        );&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      savedDamage[rawDamage] = currentDamageInfo;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  processSavedDamage(savedDamage, damageWeightedByType, battleValues);&lt;br /&gt;
&lt;br /&gt;
  return damageWeightedByType;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcDamage(&lt;br /&gt;
  attacker,&lt;br /&gt;
  victim,&lt;br /&gt;
  attackType,&lt;br /&gt;
  battle,&lt;br /&gt;
  removeSkillVariation&lt;br /&gt;
) {&lt;br /&gt;
  var damageCalculator, skillId, skillType;&lt;br /&gt;
&lt;br /&gt;
  if (attackType === &amp;quot;physical&amp;quot;) {&lt;br /&gt;
    damageCalculator = calcPhysicalDamage;&lt;br /&gt;
  } else if (attackType.startsWith(&amp;quot;attackSkill&amp;quot;)) {&lt;br /&gt;
    skillId = Number(attackType.split(&amp;quot;attackSkill&amp;quot;)[1]);&lt;br /&gt;
&lt;br /&gt;
    if (isMagicClass(attacker) || isDispell(attacker, skillId)) {&lt;br /&gt;
      skillType = &amp;quot;magic&amp;quot;;&lt;br /&gt;
      damageCalculator = calcMagicSkillDamage;&lt;br /&gt;
    } else {&lt;br /&gt;
      skillType = &amp;quot;physical&amp;quot;;&lt;br /&gt;
      damageCalculator = calcPhysicalSkillDamage;&lt;br /&gt;
    }&lt;br /&gt;
  } else if (attackType.startsWith(&amp;quot;horseSkill&amp;quot;)) {&lt;br /&gt;
    skillType = &amp;quot;physical&amp;quot;;&lt;br /&gt;
    skillId = Number(attackType.split(&amp;quot;horseSkill&amp;quot;)[1]);&lt;br /&gt;
    damageCalculator = calcPhysicalSkillDamage;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var battleValues = createBattleValues(attacker, victim, battle, skillType);&lt;br /&gt;
&lt;br /&gt;
  if (skillId) {&lt;br /&gt;
    getSkillFormula(battle, skillId, battleValues, removeSkillVariation);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    damageWeightedByType: damageCalculator(battleValues),&lt;br /&gt;
    attackValues: battleValues.attackValues,&lt;br /&gt;
    skillType: skillType,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function damageWithoutVariation(&lt;br /&gt;
  attacker,&lt;br /&gt;
  victim,&lt;br /&gt;
  attackType,&lt;br /&gt;
  battle,&lt;br /&gt;
  characters&lt;br /&gt;
) {&lt;br /&gt;
  var startDamageTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
  var { damageWeightedByType, attackValues, skillType } = calcDamage(&lt;br /&gt;
    attacker,&lt;br /&gt;
    victim,&lt;br /&gt;
    attackType,&lt;br /&gt;
    battle&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  var endDamageTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
  displayResults(&lt;br /&gt;
    attackValues,&lt;br /&gt;
    damageWeightedByType,&lt;br /&gt;
    battle,&lt;br /&gt;
    attacker.name,&lt;br /&gt;
    victim.name&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  var endDisplayTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
  displayFightInfo(&lt;br /&gt;
    attackValues.possibleDamageCount,&lt;br /&gt;
    endDamageTime - startDamageTime,&lt;br /&gt;
    endDisplayTime - endDamageTime,&lt;br /&gt;
    battle&lt;br /&gt;
  );&lt;br /&gt;
  addPotentialErrorInformation(&lt;br /&gt;
    battle.errorInformation,&lt;br /&gt;
    attacker,&lt;br /&gt;
    victim,&lt;br /&gt;
    skillType,&lt;br /&gt;
    characters&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  hideElement(battle.bonusVariationResultContainer);&lt;br /&gt;
  showElement(battle.fightResultTitle);&lt;br /&gt;
  showElement(battle.fightResultContainer);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function damageWithVariation(&lt;br /&gt;
  attacker,&lt;br /&gt;
  victim,&lt;br /&gt;
  attackType,&lt;br /&gt;
  battle,&lt;br /&gt;
  entity,&lt;br /&gt;
  entityVariation&lt;br /&gt;
) {&lt;br /&gt;
  var startTime = performance.now();&lt;br /&gt;
  var damageByBonus = [];&lt;br /&gt;
  var augmentationByBonus = [];&lt;br /&gt;
  var {&lt;br /&gt;
    bonusVariationMinValue: minVariation,&lt;br /&gt;
    bonusVariationMaxValue: maxVariation,&lt;br /&gt;
  } = entity;&lt;br /&gt;
  var step = Math.ceil((maxVariation - minVariation + 1) / 500);&lt;br /&gt;
  var simulationCount = 0;&lt;br /&gt;
  var simulationTime;&lt;br /&gt;
  var firstDamage = 1;&lt;br /&gt;
&lt;br /&gt;
  for (&lt;br /&gt;
    var bonusValue = minVariation;&lt;br /&gt;
    bonusValue &amp;lt;= maxVariation;&lt;br /&gt;
    bonusValue += step&lt;br /&gt;
  ) {&lt;br /&gt;
    entity[entityVariation] = bonusValue;&lt;br /&gt;
&lt;br /&gt;
    var {&lt;br /&gt;
      damageWeightedByType,&lt;br /&gt;
      attackValues: { totalCardinal },&lt;br /&gt;
    } = calcDamage(&lt;br /&gt;
      copyObject(attacker),&lt;br /&gt;
      copyObject(victim),&lt;br /&gt;
      attackType,&lt;br /&gt;
      battle,&lt;br /&gt;
      true&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    var meanDamage = calcMeanDamage(damageWeightedByType, totalCardinal);&lt;br /&gt;
&lt;br /&gt;
    if (bonusValue === minVariation) {&lt;br /&gt;
      firstDamage = Math.max(meanDamage, 1e-3);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    damageByBonus.push({ x: bonusValue, y: meanDamage });&lt;br /&gt;
    augmentationByBonus.push({&lt;br /&gt;
      x: bonusValue,&lt;br /&gt;
      y: meanDamage / firstDamage - 1,&lt;br /&gt;
    });&lt;br /&gt;
    simulationCount++;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var endTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
  battle.damageByBonus = damageByBonus.concat(entityVariation);&lt;br /&gt;
&lt;br /&gt;
  addToBonusVariationChart(&lt;br /&gt;
    damageByBonus,&lt;br /&gt;
    augmentationByBonus,&lt;br /&gt;
    entity.bonusVariationName,&lt;br /&gt;
    battle.bonusVariationChart&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  simulationCount = battle.numberFormats.default.format(simulationCount);&lt;br /&gt;
  simulationTime = battle.numberFormats.second.format(&lt;br /&gt;
    (endTime - startTime) / 1000&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  battle.simulationCounter.textContent = simulationCount;&lt;br /&gt;
  battle.simulationTime.textContent = simulationTime;&lt;br /&gt;
&lt;br /&gt;
  hideElement(battle.fightResultContainer);&lt;br /&gt;
  showElement(battle.fightResultTitle);&lt;br /&gt;
  showElement(battle.bonusVariationResultContainer);&lt;br /&gt;
&lt;br /&gt;
  if (&lt;br /&gt;
    isChecked(attacker.useBonusVariation) &amp;amp;&amp;amp;&lt;br /&gt;
    isChecked(victim.useBonusVariation)&lt;br /&gt;
  ) {&lt;br /&gt;
    showElement(battle.errorInformation[&amp;quot;attacker-victim-variation&amp;quot;]);&lt;br /&gt;
  } else {&lt;br /&gt;
    hideElement(battle.errorInformation[&amp;quot;attacker-victim-variation&amp;quot;]);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function changeMonsterValues(monster, instance, attacker) {&lt;br /&gt;
  switch (instance) {&lt;br /&gt;
    case &amp;quot;SungMahiTower&amp;quot;:&lt;br /&gt;
      var sungMahiFloor = 1;&lt;br /&gt;
      var sungMahiStep = 1;&lt;br /&gt;
      var rawDefense = 120;&lt;br /&gt;
&lt;br /&gt;
      if (isPC(attacker)) {&lt;br /&gt;
        sungMahiFloor = attacker.sungMahiFloor;&lt;br /&gt;
        sungMahiStep = attacker.sungMahiStep;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (monster.rank === 5) {&lt;br /&gt;
        monster.level = 121;&lt;br /&gt;
        monster.dex = 75;&lt;br /&gt;
        rawDefense += 1;&lt;br /&gt;
      } else if (monster.rank === 6) {&lt;br /&gt;
        monster.level = 123;&lt;br /&gt;
        monster.dex = 75;&lt;br /&gt;
        rawDefense += 1;&lt;br /&gt;
      } else {&lt;br /&gt;
        monster.level = 120;&lt;br /&gt;
        monster.dex = 68;&lt;br /&gt;
      }&lt;br /&gt;
      monster.vit = 100;&lt;br /&gt;
      monster.rawDefense = rawDefense + (sungMahiStep - 1) * 6;&lt;br /&gt;
      monster.fistDefense = 0;&lt;br /&gt;
      monster.swordDefense = 0;&lt;br /&gt;
      monster.twoHandedSwordDefense = 0;&lt;br /&gt;
      monster.daggerDefense = 0;&lt;br /&gt;
      monster.bellDefense = 0;&lt;br /&gt;
      monster.fanDefense = 0;&lt;br /&gt;
      monster.arrowDefense = 0;&lt;br /&gt;
      monster.clawDefense = 0;&lt;br /&gt;
      monster.magicResistance = 0;&lt;br /&gt;
      monster.fireResistance = -20;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  // Alastor&lt;br /&gt;
  if (monster.vnum === 6790) {&lt;br /&gt;
    monster.iceResistance = 0;&lt;br /&gt;
    monster.iceBonus = 0;&lt;br /&gt;
    monster.lightningResistance = -10;&lt;br /&gt;
    monster.lightningBonus = 65;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createWeapon(vnum) {&lt;br /&gt;
  var weapon = copyObject(weaponData[vnum]);&lt;br /&gt;
  var serpentVnums = [360, 380, 1210, 2230, 3250, 5200, 6150, 7330];&lt;br /&gt;
  var weaponValues = weapon[1];&lt;br /&gt;
  var isSerpent = isValueInArray(Number(vnum), serpentVnums);&lt;br /&gt;
  var isSpecial = Array.isArray(weaponValues[0]);&lt;br /&gt;
  var isMagic;&lt;br /&gt;
&lt;br /&gt;
  if (isSpecial) {&lt;br /&gt;
    isMagic = weaponValues[0][1] &amp;gt; 0;&lt;br /&gt;
  } else {&lt;br /&gt;
    isMagic = weaponValues[1] &amp;gt; 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    type: weapon[0],&lt;br /&gt;
    maxUpgrade: weapon[2].length - 1,&lt;br /&gt;
    isSerpent: isSerpent,&lt;br /&gt;
    isMagic: isMagic,&lt;br /&gt;
    getValues: function (upgrade) {&lt;br /&gt;
      var currentWeaponValues = weaponValues;&lt;br /&gt;
&lt;br /&gt;
      if (upgrade === undefined) {&lt;br /&gt;
        // rare bug when weaponUpgrade is deleted&lt;br /&gt;
        console.warn(&amp;quot;WeaponUpgrade is missing.&amp;quot;);&lt;br /&gt;
        upgrade = this.maxUpgrade;&lt;br /&gt;
      }&lt;br /&gt;
      upgrade = Math.min(upgrade, this.maxUpgrade);&lt;br /&gt;
&lt;br /&gt;
      if (isSpecial) {&lt;br /&gt;
        currentWeaponValues = weaponValues[upgrade];&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      this.minAttackValue = currentWeaponValues[2];&lt;br /&gt;
      this.maxAttackValue = currentWeaponValues[3];&lt;br /&gt;
      this.minMagicAttackValue = currentWeaponValues[0];&lt;br /&gt;
      this.maxMagicAttackValue = currentWeaponValues[1];&lt;br /&gt;
      this.growth = weapon[2][upgrade];&lt;br /&gt;
    },&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createMonster(&lt;br /&gt;
  monsterVnum,&lt;br /&gt;
  translateMonster,&lt;br /&gt;
  attacker,&lt;br /&gt;
  polymorphMonster&lt;br /&gt;
) {&lt;br /&gt;
  var monsterAttributes = monsterData[monsterVnum];&lt;br /&gt;
&lt;br /&gt;
  var monster = {&lt;br /&gt;
    vnum: Number(monsterVnum),&lt;br /&gt;
    name: translateMonster&lt;br /&gt;
      ? getTranslatedMonsterName(monsterVnum)&lt;br /&gt;
      : monsterAttributes[36],&lt;br /&gt;
    rank: monsterAttributes[0],&lt;br /&gt;
    race: monsterAttributes[1],&lt;br /&gt;
    attack: monsterAttributes[2],&lt;br /&gt;
    level: monsterAttributes[3],&lt;br /&gt;
    type: monsterAttributes[4],&lt;br /&gt;
    str: monsterAttributes[5],&lt;br /&gt;
    dex: monsterAttributes[6],&lt;br /&gt;
    vit: monsterAttributes[7],&lt;br /&gt;
    int: monsterAttributes[8],&lt;br /&gt;
    minAttackValue: monsterAttributes[9],&lt;br /&gt;
    maxAttackValue: monsterAttributes[10],&lt;br /&gt;
    rawDefense: monsterAttributes[11],&lt;br /&gt;
    criticalHit: monsterAttributes[12],&lt;br /&gt;
    piercingHit: monsterAttributes[13],&lt;br /&gt;
    fistDefense: monsterAttributes[14],&lt;br /&gt;
    swordDefense: monsterAttributes[15],&lt;br /&gt;
    twoHandedSwordDefense: monsterAttributes[16],&lt;br /&gt;
    daggerDefense: monsterAttributes[17],&lt;br /&gt;
    bellDefense: monsterAttributes[18],&lt;br /&gt;
    fanDefense: monsterAttributes[19],&lt;br /&gt;
    arrowDefense: monsterAttributes[20],&lt;br /&gt;
    clawDefense: monsterAttributes[21],&lt;br /&gt;
    fireResistance: monsterAttributes[22],&lt;br /&gt;
    lightningResistance: monsterAttributes[23],&lt;br /&gt;
    magicResistance: monsterAttributes[24],&lt;br /&gt;
    windResistance: monsterAttributes[25],&lt;br /&gt;
    lightningBonus: monsterAttributes[26],&lt;br /&gt;
    fireBonus: monsterAttributes[27],&lt;br /&gt;
    iceBonus: monsterAttributes[28],&lt;br /&gt;
    windBonus: monsterAttributes[29],&lt;br /&gt;
    earthBonus: monsterAttributes[30],&lt;br /&gt;
    darknessBonus: monsterAttributes[31],&lt;br /&gt;
    darknessResistance: monsterAttributes[32],&lt;br /&gt;
    iceResistance: monsterAttributes[33],&lt;br /&gt;
    earthResistance: monsterAttributes[34],&lt;br /&gt;
    damageMultiplier: monsterAttributes[35],&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  // monster.instance = 0;&lt;br /&gt;
&lt;br /&gt;
  // if (attacker &amp;amp;&amp;amp; monster.instance === 0) {&lt;br /&gt;
  //   changeMonsterValues(monster, &amp;quot;SungMahiTower&amp;quot;, attacker);&lt;br /&gt;
  // }&lt;br /&gt;
  if (!polymorphMonster) {&lt;br /&gt;
    changeMonsterValues(monster);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  monster.defense = monster.rawDefense + monster.level + monster.vit;&lt;br /&gt;
&lt;br /&gt;
  return monster;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addPotentialErrorInformation(&lt;br /&gt;
  errorInformation,&lt;br /&gt;
  attacker,&lt;br /&gt;
  victim,&lt;br /&gt;
  skillType,&lt;br /&gt;
  characters&lt;br /&gt;
) {&lt;br /&gt;
  for (var error of Object.values(errorInformation)) {&lt;br /&gt;
    hideElement(error);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker)) {&lt;br /&gt;
    if (isRiding(attacker)) {&lt;br /&gt;
      if (attacker.horsePoint === 0) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;horse-level&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
      showElement(errorInformation[&amp;quot;horse-stat&amp;quot;]);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isPolymorph(attacker)) {&lt;br /&gt;
      if (attacker.polymorphPoint === 0) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;polymorph-level&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (&lt;br /&gt;
        (attacker.polymorphPoint &amp;lt;= 39 &amp;amp;&amp;amp; attacker.attackValuePercent &amp;lt;= 199) ||&lt;br /&gt;
        (attacker.polymorphPoint === 40 &amp;amp;&amp;amp; attacker.attackValuePercent &amp;lt;= 299)&lt;br /&gt;
      ) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;polymorph-bonus&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
    if (skillType === &amp;quot;magic&amp;quot;) {&lt;br /&gt;
      if (attacker.magicAttackValue) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;magic-attack-value-bonus&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
      if (victim.magicResistance) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;magic-resistance&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    showElement(errorInformation[&amp;quot;monster-attacker&amp;quot;]);&lt;br /&gt;
    if (isMagicAttacker(attacker) &amp;amp;&amp;amp; victim.magicResistance) {&lt;br /&gt;
      showElement(errorInformation[&amp;quot;magic-resistance&amp;quot;]);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (isPC(victim)) {&lt;br /&gt;
    if (isRiding(victim)) {&lt;br /&gt;
      showElement(errorInformation[&amp;quot;horse-stat&amp;quot;]);&lt;br /&gt;
    }&lt;br /&gt;
    if (isPolymorph(victim)) {&lt;br /&gt;
      if (attacker.polymorphPoint === 0) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;polymorph-level&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
      showElement(errorInformation[&amp;quot;polymorph-defense&amp;quot;]);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (characters.unsavedChanges) {&lt;br /&gt;
    showElement(errorInformation[&amp;quot;save&amp;quot;]);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function reduceChartPointsListener(battle) {&lt;br /&gt;
  var {&lt;br /&gt;
    reduceChartPointsContainer,&lt;br /&gt;
    reduceChartPoints,&lt;br /&gt;
    numberFormats: { second: numberFormat },&lt;br /&gt;
    displayTime,&lt;br /&gt;
  } = battle;&lt;br /&gt;
&lt;br /&gt;
  reduceChartPoints.addEventListener(&amp;quot;change&amp;quot;, function () {&lt;br /&gt;
    reduceChartPoints.disabled = true;&lt;br /&gt;
&lt;br /&gt;
    var startDisplayTime = performance.now();&lt;br /&gt;
    var scatterDataByType = battle.scatterDataByType;&lt;br /&gt;
    var {&lt;br /&gt;
      chart,&lt;br /&gt;
      maxPoints,&lt;br /&gt;
      chart: {&lt;br /&gt;
        data: { datasets },&lt;br /&gt;
      },&lt;br /&gt;
    } = battle.damageChart;&lt;br /&gt;
    var addAnimations = false;&lt;br /&gt;
&lt;br /&gt;
    for (var index = 0; index &amp;lt; datasets.length; index++) {&lt;br /&gt;
      var dataset = datasets[index];&lt;br /&gt;
      var scatterData = scatterDataByType[dataset.name];&lt;br /&gt;
&lt;br /&gt;
      if (dataset.canBeReduced &amp;amp;&amp;amp; reduceChartPoints.checked) {&lt;br /&gt;
        dataset.data = aggregateDamage(scatterData, maxPoints);&lt;br /&gt;
        addAnimations = true;&lt;br /&gt;
      } else {&lt;br /&gt;
        dataset.data = scatterData;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    handleChartAnimations(chart, addAnimations);&lt;br /&gt;
    chart.update();&lt;br /&gt;
&lt;br /&gt;
    displayTime.textContent = numberFormat.format(&lt;br /&gt;
      (performance.now() - startDisplayTime) / 1000&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    setTimeout(function () {&lt;br /&gt;
      reduceChartPoints.disabled = false;&lt;br /&gt;
    }, 1000);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  reduceChartPointsContainer.addEventListener(&amp;quot;pointerup&amp;quot;, function (event) {&lt;br /&gt;
    if (event.pointerType === &amp;quot;mouse&amp;quot;) {&lt;br /&gt;
      if (event.target.closest(&amp;quot;label&amp;quot;)) {&lt;br /&gt;
        return;&lt;br /&gt;
      }&lt;br /&gt;
      reduceChartPoints.click();&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function downloadRawDataListener(battle) {&lt;br /&gt;
  var { downLoadRawData, downLoadRawDataVariation } = battle;&lt;br /&gt;
  var fileType = &amp;quot;text/csv;charset=utf-8;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  downLoadRawData.addEventListener(&amp;quot;click&amp;quot;, function () {&lt;br /&gt;
    var damageWeightedByType = battle.damageWeightedByType;&lt;br /&gt;
    var filename = &amp;quot;raw_damage.csv&amp;quot;;&lt;br /&gt;
    var csvContent = &amp;quot;damage,probabilities,damageType\n&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    for (var damageType in damageWeightedByType) {&lt;br /&gt;
      var damageWeighted = damageWeightedByType[damageType];&lt;br /&gt;
&lt;br /&gt;
      for (var damage in damageWeighted) {&lt;br /&gt;
        csvContent +=&lt;br /&gt;
          damage + &amp;quot;,&amp;quot; + damageWeighted[damage] + &amp;quot;,&amp;quot; + damageType + &amp;quot;\n&amp;quot;;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    downloadData(csvContent, fileType, filename);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  downLoadRawDataVariation.addEventListener(&amp;quot;click&amp;quot;, function () {&lt;br /&gt;
    var damageByBonus = battle.damageByBonus;&lt;br /&gt;
    var damageByBonusLength = damageByBonus.length;&lt;br /&gt;
    var filename = &amp;quot;damage_variation.csv&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    if (!damageByBonusLength) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var csvContent =&lt;br /&gt;
      damageByBonus[damageByBonusLength - 1] + &amp;quot;,averageDamage\n&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    for (var index = 0; index &amp;lt; damageByBonusLength - 1; index++) {&lt;br /&gt;
      var row = damageByBonus[index];&lt;br /&gt;
&lt;br /&gt;
      csvContent += row.x + &amp;quot;,&amp;quot; + row.y + &amp;quot;\n&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    downloadData(csvContent, fileType, filename);&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function displayResults(&lt;br /&gt;
  attackValues,&lt;br /&gt;
  damageWeightedByType,&lt;br /&gt;
  battle,&lt;br /&gt;
  attackerName,&lt;br /&gt;
  victimName&lt;br /&gt;
) {&lt;br /&gt;
  var [meanDamage, minDamage, maxDamage, scatterDataByType, uniqueDamageCount] =&lt;br /&gt;
    prepareDamageData(damageWeightedByType, attackValues);&lt;br /&gt;
&lt;br /&gt;
  addToDamageChart(battle, scatterDataByType);&lt;br /&gt;
  updateDamageChartDescription(battle, uniqueDamageCount);&lt;br /&gt;
  displayFightResults(&lt;br /&gt;
    battle,&lt;br /&gt;
    attackerName,&lt;br /&gt;
    victimName,&lt;br /&gt;
    meanDamage,&lt;br /&gt;
    minDamage,&lt;br /&gt;
    maxDamage&lt;br /&gt;
  );&lt;br /&gt;
  battle.damageWeightedByType = damageWeightedByType;&lt;br /&gt;
  battle.scatterDataByType = scatterDataByType;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function displayFightResults(&lt;br /&gt;
  battle,&lt;br /&gt;
  attackerName,&lt;br /&gt;
  victimName,&lt;br /&gt;
  meanDamage,&lt;br /&gt;
  minDamage,&lt;br /&gt;
  maxDamage&lt;br /&gt;
) {&lt;br /&gt;
  var {&lt;br /&gt;
    tableResultFight,&lt;br /&gt;
    tableResultHistory,&lt;br /&gt;
    savedFights,&lt;br /&gt;
    numberFormats: { default: numberFormat },&lt;br /&gt;
    deleteFightTemplate,&lt;br /&gt;
  } = battle;&lt;br /&gt;
&lt;br /&gt;
  hideElement(tableResultHistory.rows[1]);&lt;br /&gt;
&lt;br /&gt;
  var valuesToDisplay = [&lt;br /&gt;
    attackerName,&lt;br /&gt;
    victimName,&lt;br /&gt;
    battle.battleChoice.attackType.selectedText,&lt;br /&gt;
    meanDamage,&lt;br /&gt;
    minDamage,&lt;br /&gt;
    maxDamage,&lt;br /&gt;
  ];&lt;br /&gt;
&lt;br /&gt;
  savedFights.push(valuesToDisplay);&lt;br /&gt;
  updateSavedFights(savedFights);&lt;br /&gt;
&lt;br /&gt;
  editTableResultRow(tableResultFight.rows[1], valuesToDisplay, numberFormat);&lt;br /&gt;
  addRowToTableResultHistory(&lt;br /&gt;
    tableResultHistory,&lt;br /&gt;
    valuesToDisplay,&lt;br /&gt;
    deleteFightTemplate,&lt;br /&gt;
    numberFormat&lt;br /&gt;
  );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function displayFightInfo(&lt;br /&gt;
  possibleDamageCount,&lt;br /&gt;
  damageTimeDuration,&lt;br /&gt;
  displayTimeDuration,&lt;br /&gt;
  battle&lt;br /&gt;
) {&lt;br /&gt;
  const {&lt;br /&gt;
    damageInfoContainer,&lt;br /&gt;
    numberFormats: { default: defaultFormat, second: secondFormat },&lt;br /&gt;
    possibleDamageCounter,&lt;br /&gt;
    damageTime,&lt;br /&gt;
    displayTime,&lt;br /&gt;
  } = battle;&lt;br /&gt;
&lt;br /&gt;
  if (possibleDamageCount &amp;lt;= 1) {&lt;br /&gt;
    hideElement(damageInfoContainer);&lt;br /&gt;
    return;&lt;br /&gt;
  } else {&lt;br /&gt;
    showElement(damageInfoContainer);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  possibleDamageCount = defaultFormat.format(possibleDamageCount);&lt;br /&gt;
  damageTimeDuration = secondFormat.format(damageTimeDuration / 1000);&lt;br /&gt;
  displayTimeDuration = secondFormat.format(displayTimeDuration / 1000);&lt;br /&gt;
&lt;br /&gt;
  possibleDamageCounter.textContent = possibleDamageCount;&lt;br /&gt;
  damageTime.textContent = damageTimeDuration;&lt;br /&gt;
  displayTime.textContent = displayTimeDuration;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function parseTypeAndName(data) {&lt;br /&gt;
  var [type, nameOrVnum] = splitFirst(data, &amp;quot;-&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    type: type,&lt;br /&gt;
    nameOrVnum: nameOrVnum,&lt;br /&gt;
    isCharacter: type === &amp;quot;character&amp;quot;,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isCharacterSelected(characterName, selected) {&lt;br /&gt;
  if (!selected) {&lt;br /&gt;
    return false;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var { nameOrVnum, isCharacter } = parseTypeAndName(selected);&lt;br /&gt;
&lt;br /&gt;
  return nameOrVnum === characterName &amp;amp;&amp;amp; isCharacter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function useBonusVariationMode(character, variation) {&lt;br /&gt;
  return (&lt;br /&gt;
    isChecked(character.useBonusVariation) &amp;amp;&amp;amp;&lt;br /&gt;
    character.hasOwnProperty(variation) &amp;amp;&amp;amp;&lt;br /&gt;
    character.bonusVariationMinValue &amp;lt; character.bonusVariationMaxValue&lt;br /&gt;
  );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createBattle(characters, battle) {&lt;br /&gt;
  var battleChoice = battle.battleChoice;&lt;br /&gt;
  var battleForm = battleChoice.form;&lt;br /&gt;
  var lastInvalidTime = 0;&lt;br /&gt;
&lt;br /&gt;
  battleForm.addEventListener(&amp;quot;change&amp;quot;, handleBattleFormChange);&lt;br /&gt;
  battleForm.addEventListener(&amp;quot;invalid&amp;quot;, handleBattleFormInvalid, true);&lt;br /&gt;
  battleForm.addEventListener(&amp;quot;submit&amp;quot;, handleBattleFormSubmit);&lt;br /&gt;
&lt;br /&gt;
  function handleBattleFormChange(event) {&lt;br /&gt;
    var target = event.target;&lt;br /&gt;
    var { name: targetName, value: targetValue, type: targetType } = target;&lt;br /&gt;
&lt;br /&gt;
    if (targetType !== &amp;quot;radio&amp;quot;) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (targetName === &amp;quot;attackType&amp;quot;) {&lt;br /&gt;
      battleChoice.attackType.selectedText =&lt;br /&gt;
        target.previousElementSibling.textContent;&lt;br /&gt;
    } else {&lt;br /&gt;
      updateBattleChoiceButton(battleChoice, targetName, targetValue);&lt;br /&gt;
&lt;br /&gt;
      if (targetName === &amp;quot;attacker&amp;quot;) {&lt;br /&gt;
        filterAttackTypeSelection(characters, battleChoice, targetValue);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function handleBattleFormInvalid(event) {&lt;br /&gt;
    var currentTime = Date.now();&lt;br /&gt;
&lt;br /&gt;
    if (currentTime - lastInvalidTime &amp;lt; 100) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    lastInvalidTime = currentTime;&lt;br /&gt;
&lt;br /&gt;
    var target = event.target;&lt;br /&gt;
    var modal = target.closest(&amp;quot;.modal&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (!modal) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var dataModal = modal.dataset.modal;&lt;br /&gt;
&lt;br /&gt;
    if (!dataModal) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var category = dataModal.split(&amp;quot;-&amp;quot;)[0];&lt;br /&gt;
&lt;br /&gt;
    if (isValueInArray(category, battleChoice.categories)) {&lt;br /&gt;
      battleChoice[category].button.click();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function handleBattleFormSubmit(event) {&lt;br /&gt;
    event.preventDefault();&lt;br /&gt;
&lt;br /&gt;
    // auto save&lt;br /&gt;
    if (characters.unsavedChanges) {&lt;br /&gt;
      characters.saveButton.click();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var battleInfo = new FormData(event.target);&lt;br /&gt;
    var attackerData = battleInfo.get(&amp;quot;attacker&amp;quot;);&lt;br /&gt;
    var attackType = battleInfo.get(&amp;quot;attackType&amp;quot;);&lt;br /&gt;
    var victimData = battleInfo.get(&amp;quot;victim&amp;quot;);&lt;br /&gt;
    var attackerVariation;&lt;br /&gt;
    var victimVariation;&lt;br /&gt;
&lt;br /&gt;
    if (!attackerData &amp;amp;&amp;amp; !attackType &amp;amp;&amp;amp; !victimData) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var { nameOrVnum: attackerNameOrVnum, isCharacter: attackerIsPlayer } =&lt;br /&gt;
      parseTypeAndName(attackerData);&lt;br /&gt;
    var { nameOrVnum: victimNameOrVnum, isCharacter: victimIsPlayer } =&lt;br /&gt;
      parseTypeAndName(victimData);&lt;br /&gt;
&lt;br /&gt;
    if (attackerIsPlayer) {&lt;br /&gt;
      var attacker = copyObject(characters.savedCharacters[attackerNameOrVnum]);&lt;br /&gt;
      attackerVariation = attacker.bonusVariation;&lt;br /&gt;
    } else {&lt;br /&gt;
      var attacker = createMonster(&lt;br /&gt;
        attackerNameOrVnum,&lt;br /&gt;
        characters.translateMonsters&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (victimIsPlayer) {&lt;br /&gt;
      var victim = copyObject(characters.savedCharacters[victimNameOrVnum]);&lt;br /&gt;
      victimVariation = victim.bonusVariation;&lt;br /&gt;
    } else {&lt;br /&gt;
      var victim = createMonster(&lt;br /&gt;
        victimNameOrVnum,&lt;br /&gt;
        characters.translateMonsters,&lt;br /&gt;
        attacker&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (useBonusVariationMode(attacker, attackerVariation)) {&lt;br /&gt;
      damageWithVariation(&lt;br /&gt;
        attacker,&lt;br /&gt;
        victim,&lt;br /&gt;
        attackType,&lt;br /&gt;
        battle,&lt;br /&gt;
        attacker,&lt;br /&gt;
        attackerVariation&lt;br /&gt;
      );&lt;br /&gt;
    } else if (useBonusVariationMode(victim, victimVariation)) {&lt;br /&gt;
      damageWithVariation(&lt;br /&gt;
        attacker,&lt;br /&gt;
        victim,&lt;br /&gt;
        attackType,&lt;br /&gt;
        battle,&lt;br /&gt;
        victim,&lt;br /&gt;
        victimVariation&lt;br /&gt;
      );&lt;br /&gt;
    } else {&lt;br /&gt;
      damageWithoutVariation(attacker, victim, attackType, battle, characters);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createMapping() {&lt;br /&gt;
  return {&lt;br /&gt;
    typeFlag: [&lt;br /&gt;
      &amp;quot;animalBonus&amp;quot;, // 0&lt;br /&gt;
      &amp;quot;humanBonus&amp;quot;, // 1&lt;br /&gt;
      &amp;quot;orcBonus&amp;quot;, // 2&lt;br /&gt;
      &amp;quot;mysticBonus&amp;quot;, // 3&lt;br /&gt;
      &amp;quot;undeadBonus&amp;quot;, // 4&lt;br /&gt;
      &amp;quot;insectBonus&amp;quot;, // 5&lt;br /&gt;
      &amp;quot;desertBonus&amp;quot;, // 6&lt;br /&gt;
      &amp;quot;devilBonus&amp;quot;, // 7&lt;br /&gt;
    ],&lt;br /&gt;
    raceBonus: {&lt;br /&gt;
      warrior: &amp;quot;warriorBonus&amp;quot;,&lt;br /&gt;
      sura: &amp;quot;suraBonus&amp;quot;,&lt;br /&gt;
      ninja: &amp;quot;ninjaBonus&amp;quot;,&lt;br /&gt;
      shaman: &amp;quot;shamanBonus&amp;quot;,&lt;br /&gt;
      lycan: &amp;quot;lycanBonus&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    raceResistance: {&lt;br /&gt;
      warrior: &amp;quot;warriorResistance&amp;quot;,&lt;br /&gt;
      sura: &amp;quot;suraResistance&amp;quot;,&lt;br /&gt;
      ninja: &amp;quot;ninjaResistance&amp;quot;,&lt;br /&gt;
      shaman: &amp;quot;shamanResistance&amp;quot;,&lt;br /&gt;
      lycan: &amp;quot;lycanResistance&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    defenseWeapon: [&lt;br /&gt;
      &amp;quot;swordDefense&amp;quot;, // 0&lt;br /&gt;
      &amp;quot;daggerDefense&amp;quot;, // 1&lt;br /&gt;
      &amp;quot;arrowDefense&amp;quot;, // 2&lt;br /&gt;
      &amp;quot;twoHandedSwordDefense&amp;quot;, // 3&lt;br /&gt;
      &amp;quot;bellDefense&amp;quot;, // 4&lt;br /&gt;
      &amp;quot;clawDefense&amp;quot;, // 5&lt;br /&gt;
      &amp;quot;fanDefense&amp;quot;, // 6&lt;br /&gt;
      &amp;quot;swordDefense&amp;quot;, // 7&lt;br /&gt;
      &amp;quot;fistDefense&amp;quot;, // 8&lt;br /&gt;
    ],&lt;br /&gt;
    breakWeapon: [&lt;br /&gt;
      &amp;quot;breakSwordDefense&amp;quot;, // 0&lt;br /&gt;
      &amp;quot;breakDaggerDefense&amp;quot;, // 1&lt;br /&gt;
      &amp;quot;breakArrowDefense&amp;quot;, // 2&lt;br /&gt;
      &amp;quot;breakTwoHandedSwordDefense&amp;quot;, // 3&lt;br /&gt;
      &amp;quot;breakBellDefense&amp;quot;, // 4&lt;br /&gt;
      &amp;quot;breakClawDefense&amp;quot;, // 5&lt;br /&gt;
      &amp;quot;breakFanDefense&amp;quot;, // 6&lt;br /&gt;
      &amp;quot;breakSwordDefense&amp;quot;, // 7&lt;br /&gt;
    ],&lt;br /&gt;
    elementBonus: [&lt;br /&gt;
      &amp;quot;fireBonus&amp;quot;, // 0&lt;br /&gt;
      &amp;quot;iceBonus&amp;quot;, // 1&lt;br /&gt;
      &amp;quot;windBonus&amp;quot;, // 2&lt;br /&gt;
      &amp;quot;lightningBonus&amp;quot;, // 3&lt;br /&gt;
      &amp;quot;earthBonus&amp;quot;, // 4&lt;br /&gt;
      &amp;quot;darknessBonus&amp;quot;, // 5&lt;br /&gt;
    ],&lt;br /&gt;
    elementResistance: [&lt;br /&gt;
      &amp;quot;fireResistance&amp;quot;, // 0&lt;br /&gt;
      &amp;quot;iceResistance&amp;quot;, // 1&lt;br /&gt;
      &amp;quot;windResistance&amp;quot;, // 2&lt;br /&gt;
      &amp;quot;lightningResistance&amp;quot;, // 3&lt;br /&gt;
      &amp;quot;earthResistance&amp;quot;, // 4&lt;br /&gt;
      &amp;quot;darknessResistance&amp;quot;, // 5&lt;br /&gt;
    ],&lt;br /&gt;
    attackType: [&lt;br /&gt;
      &amp;quot;normalHit&amp;quot;,&lt;br /&gt;
      &amp;quot;criticalHit&amp;quot;,&lt;br /&gt;
      &amp;quot;piercingHit&amp;quot;,&lt;br /&gt;
      &amp;quot;criticalPiercingHit&amp;quot;,&lt;br /&gt;
    ],&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createConstants() {&lt;br /&gt;
  var constants = {&lt;br /&gt;
    polymorphPowerTable: [&lt;br /&gt;
      10, 11, 11, 12, 13, 13, 14, 15, 16, 17, 18, 19, 20, 22, 23, 24, 26, 27,&lt;br /&gt;
      29, 31, 33, 35, 37, 39, 41, 44, 46, 49, 52, 55, 59, 62, 66, 70, 74, 79,&lt;br /&gt;
      84, 89, 94, 100, 0,&lt;br /&gt;
    ],&lt;br /&gt;
    skillPowerTable: [&lt;br /&gt;
      0, 0.05, 0.06, 0.08, 0.1, 0.12, 0.14, 0.16, 0.18, 0.2, 0.22, 0.24, 0.26,&lt;br /&gt;
      0.28, 0.3, 0.32, 0.34, 0.36, 0.38, 0.4, 0.5, 0.52, 0.54, 0.56, 0.58, 0.6,&lt;br /&gt;
      0.63, 0.66, 0.69, 0.72, 0.82, 0.85, 0.88, 0.91, 0.94, 0.98, 1.02, 1.06,&lt;br /&gt;
      1.1, 1.15, 1.25,&lt;br /&gt;
    ],&lt;br /&gt;
    marriageTable: {&lt;br /&gt;
      harmonyEarrings: [4, 5, 6, 8],&lt;br /&gt;
      loveEarrings: [4, 5, 6, 8],&lt;br /&gt;
      harmonyBracelet: [4, 5, 6, 8],&lt;br /&gt;
      loveNecklace: [20, 25, 30, 40],&lt;br /&gt;
      harmonyNecklace: [12, 16, 20, 30],&lt;br /&gt;
    },&lt;br /&gt;
    allowedWeaponsPerRace: {&lt;br /&gt;
      warrior: [0, 3, 8],&lt;br /&gt;
      ninja: [0, 1, 2, 8],&lt;br /&gt;
      sura: [0, 7, 8],&lt;br /&gt;
      shaman: [4, 6, 8],&lt;br /&gt;
      lycan: [5, 8],&lt;br /&gt;
    },&lt;br /&gt;
  };&lt;br /&gt;
  return constants;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initResultTableHistory(battle) {&lt;br /&gt;
  var {&lt;br /&gt;
    tableResultHistory,&lt;br /&gt;
    savedFights,&lt;br /&gt;
    deleteFightTemplate,&lt;br /&gt;
    numberFormats: { default: numberFormat },&lt;br /&gt;
  } = battle;&lt;br /&gt;
  var startIndex = 3;&lt;br /&gt;
&lt;br /&gt;
  if (savedFights.length) {&lt;br /&gt;
    hideElement(tableResultHistory.rows[1]);&lt;br /&gt;
&lt;br /&gt;
    for (var savedFight of savedFights) {&lt;br /&gt;
      addRowToTableResultHistory(&lt;br /&gt;
        tableResultHistory,&lt;br /&gt;
        savedFight,&lt;br /&gt;
        deleteFightTemplate,&lt;br /&gt;
        numberFormat&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  tableResultHistory.addEventListener(&amp;quot;click&amp;quot;, function (event) {&lt;br /&gt;
    var deleteButton = event.target.closest(&amp;quot;.svg-icon-delete&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (deleteButton) {&lt;br /&gt;
      var row = deleteButton.closest(&amp;quot;tr&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
      if (row) {&lt;br /&gt;
        savedFights.splice(row.rowIndex - startIndex, 1);&lt;br /&gt;
        updateSavedFights(savedFights);&lt;br /&gt;
&lt;br /&gt;
        row.remove();&lt;br /&gt;
&lt;br /&gt;
        if (tableResultHistory.rows.length === startIndex) {&lt;br /&gt;
          showElement(tableResultHistory.rows[1]);&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initDamageChart(battle, currentLanguage, defaultText) {&lt;br /&gt;
  const { reduceChartPointsContainer, reduceChartPoints } = battle;&lt;br /&gt;
  const { default: defaultFormat, percent: percentFormat } =&lt;br /&gt;
    battle.numberFormats;&lt;br /&gt;
  const customPlugins = {&lt;br /&gt;
    id: &amp;quot;customPlugins&amp;quot;,&lt;br /&gt;
    afterDraw(chart) {&lt;br /&gt;
      const missPercentage = chart.data.missPercentage;&lt;br /&gt;
&lt;br /&gt;
      if (!missPercentage) {&lt;br /&gt;
        return;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      const {&lt;br /&gt;
        ctx,&lt;br /&gt;
        chartArea: { top, right },&lt;br /&gt;
      } = chart;&lt;br /&gt;
      ctx.save();&lt;br /&gt;
      const text =&lt;br /&gt;
        defaultText.miss + &amp;quot; : &amp;quot; + percentFormat.format(missPercentage);&lt;br /&gt;
      const padding = 4;&lt;br /&gt;
      const fontSize = 14;&lt;br /&gt;
&lt;br /&gt;
      ctx.font = fontSize + &amp;quot;px Helvetica Neue&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
      const textWidth = ctx.measureText(text).width;&lt;br /&gt;
      const xPosition = right - textWidth - 5;&lt;br /&gt;
      const yPosition = top + 5;&lt;br /&gt;
&lt;br /&gt;
      ctx.fillStyle = &amp;quot;rgba(255, 0, 0, 0.2)&amp;quot;;&lt;br /&gt;
      ctx.fillRect(&lt;br /&gt;
        xPosition - padding,&lt;br /&gt;
        yPosition - padding,&lt;br /&gt;
        textWidth + 2 * padding,&lt;br /&gt;
        fontSize + 2 * padding&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      ctx.strokeStyle = &amp;quot;red&amp;quot;;&lt;br /&gt;
      ctx.strokeRect(&lt;br /&gt;
        xPosition - padding,&lt;br /&gt;
        yPosition - padding,&lt;br /&gt;
        textWidth + 2 * padding,&lt;br /&gt;
        fontSize + 2 * padding&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      ctx.fillStyle = &amp;quot;#666&amp;quot;;&lt;br /&gt;
      ctx.textBaseline = &amp;quot;top&amp;quot;;&lt;br /&gt;
      ctx.fillText(text, xPosition, yPosition + 1);&lt;br /&gt;
&lt;br /&gt;
      ctx.restore();&lt;br /&gt;
    },&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  Chart.register(customPlugins);&lt;br /&gt;
&lt;br /&gt;
  const ctx = battle.plotDamage.getContext(&amp;quot;2d&amp;quot;);&lt;br /&gt;
  const maxLabelsInTooltip = 10;&lt;br /&gt;
  const nullLabelText = &amp;quot; ...&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  const chart = new Chart(ctx, {&lt;br /&gt;
    type: &amp;quot;scatter&amp;quot;,&lt;br /&gt;
    data: {&lt;br /&gt;
      missPercentage: 0,&lt;br /&gt;
      datasets: [],&lt;br /&gt;
    },&lt;br /&gt;
    options: {&lt;br /&gt;
      locale: currentLanguage,&lt;br /&gt;
      responsive: true,&lt;br /&gt;
      maintainAspectRatio: false,&lt;br /&gt;
      plugins: {&lt;br /&gt;
        legend: {&lt;br /&gt;
          display: true,&lt;br /&gt;
          onHover: function (e) {&lt;br /&gt;
            e.native.target.style.cursor = &amp;quot;pointer&amp;quot;;&lt;br /&gt;
          },&lt;br /&gt;
          onLeave: function (e) {&lt;br /&gt;
            e.native.target.style.cursor = &amp;quot;default&amp;quot;;&lt;br /&gt;
          },&lt;br /&gt;
          onClick: function (e, legendItem, legend) {&lt;br /&gt;
            const currentIndex = legendItem.datasetIndex;&lt;br /&gt;
            const ci = legend.chart;&lt;br /&gt;
            const isCurrentDatasetVisible = ci.isDatasetVisible(currentIndex);&lt;br /&gt;
            const datasets = ci.data.datasets;&lt;br /&gt;
            const isReducePointsChecked = reduceChartPoints.checked;&lt;br /&gt;
            let hideReducePoints = true;&lt;br /&gt;
&lt;br /&gt;
            datasets[currentIndex].hidden = isCurrentDatasetVisible;&lt;br /&gt;
            legendItem.hidden = isCurrentDatasetVisible;&lt;br /&gt;
&lt;br /&gt;
            for (const index in datasets) {&lt;br /&gt;
              if (ci.isDatasetVisible(index) &amp;amp;&amp;amp; datasets[index].canBeReduced) {&lt;br /&gt;
                showElement(reduceChartPointsContainer);&lt;br /&gt;
                hideReducePoints = false;&lt;br /&gt;
                break;&lt;br /&gt;
              }&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            if (hideReducePoints) {&lt;br /&gt;
              hideElement(reduceChartPointsContainer);&lt;br /&gt;
              handleChartAnimations(ci, true);&lt;br /&gt;
            } else {&lt;br /&gt;
              handleChartAnimations(ci, isReducePointsChecked);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            ci.update();&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        title: {&lt;br /&gt;
          display: true,&lt;br /&gt;
          text: defaultText.damageRepartition,&lt;br /&gt;
          font: {&lt;br /&gt;
            size: 20,&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        tooltip: {&lt;br /&gt;
          callbacks: {&lt;br /&gt;
            label: function (context) {&lt;br /&gt;
              if (context.label === null) {&lt;br /&gt;
                return nullLabelText;&lt;br /&gt;
              }&lt;br /&gt;
&lt;br /&gt;
              const xValue = defaultFormat.format(context.parsed.x);&lt;br /&gt;
              const yValue = defaultFormat.format(context.parsed.y);&lt;br /&gt;
              const label =&lt;br /&gt;
                &amp;quot; &amp;quot; +&lt;br /&gt;
                context.dataset.label +&lt;br /&gt;
                &amp;quot; : (&amp;quot; +&lt;br /&gt;
                xValue +&lt;br /&gt;
                &amp;quot;, &amp;quot; +&lt;br /&gt;
                yValue +&lt;br /&gt;
                &amp;quot;)&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
              return label;&lt;br /&gt;
            },&lt;br /&gt;
            beforeBody: function (tooltipItems) {&lt;br /&gt;
              if (tooltipItems.length &amp;gt; maxLabelsInTooltip + 1) {&lt;br /&gt;
                tooltipItems.splice(maxLabelsInTooltip + 1);&lt;br /&gt;
                tooltipItems[maxLabelsInTooltip].label = null;&lt;br /&gt;
              }&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          caretPadding: 10,&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
      scales: {&lt;br /&gt;
        x: {&lt;br /&gt;
          type: &amp;quot;linear&amp;quot;,&lt;br /&gt;
          position: &amp;quot;bottom&amp;quot;,&lt;br /&gt;
          title: {&lt;br /&gt;
            display: true,&lt;br /&gt;
            text: defaultText.damage,&lt;br /&gt;
            font: {&lt;br /&gt;
              size: 16,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          ticks: {&lt;br /&gt;
            callback: function (value) {&lt;br /&gt;
              return Number.isInteger(value) ? value : &amp;quot;&amp;quot;;&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        y: {&lt;br /&gt;
          title: {&lt;br /&gt;
            display: true,&lt;br /&gt;
            text: defaultText.percentage,&lt;br /&gt;
            font: {&lt;br /&gt;
              size: 16,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          ticks: {&lt;br /&gt;
            format: {&lt;br /&gt;
              style: &amp;quot;percent&amp;quot;,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
      elements: {&lt;br /&gt;
        point: {&lt;br /&gt;
          borderWidth: 1,&lt;br /&gt;
          radius: 3,&lt;br /&gt;
          hitRadius: 3,&lt;br /&gt;
          hoverRadius: 6,&lt;br /&gt;
          hoverBorderWidth: 2,&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
    },&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  const datasetsStyle = [&lt;br /&gt;
    {&lt;br /&gt;
      name: &amp;quot;normalHit&amp;quot;,&lt;br /&gt;
      canBeReduced: false,&lt;br /&gt;
      label: defaultText.normalHit,&lt;br /&gt;
      backgroundColor: &amp;quot;rgba(75, 192, 192, 0.2)&amp;quot;,&lt;br /&gt;
      borderColor: &amp;quot;rgba(75, 192, 192, 1)&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      name: &amp;quot;piercingHit&amp;quot;,&lt;br /&gt;
      canBeReduced: false,&lt;br /&gt;
      label: defaultText.piercingHit,&lt;br /&gt;
      backgroundColor: &amp;quot;rgba(192, 192, 75, 0.2)&amp;quot;,&lt;br /&gt;
      borderColor: &amp;quot;rgba(192, 192, 75, 1)&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      name: &amp;quot;criticalHit&amp;quot;,&lt;br /&gt;
      canBeReduced: false,&lt;br /&gt;
      label: defaultText.criticalHit,&lt;br /&gt;
      backgroundColor: &amp;quot;rgba(192, 75, 192, 0.2)&amp;quot;,&lt;br /&gt;
      borderColor: &amp;quot;rgba(192, 75, 192, 1)&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      name: &amp;quot;criticalPiercingHit&amp;quot;,&lt;br /&gt;
      canBeReduced: false,&lt;br /&gt;
      label: defaultText.criticalPiercingHit,&lt;br /&gt;
      backgroundColor: &amp;quot;rgba(75, 75, 192, 0.2)&amp;quot;,&lt;br /&gt;
      borderColor: &amp;quot;rgba(75, 75, 192, 1)&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
  ];&lt;br /&gt;
  battle.damageChart = {&lt;br /&gt;
    chart: chart,&lt;br /&gt;
    datasetsStyle: datasetsStyle,&lt;br /&gt;
    maxPoints: 500,&lt;br /&gt;
    reduceChartPointsContainer: reduceChartPointsContainer,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initBonusVariationChart(battle, currentLanguage, defaultText) {&lt;br /&gt;
  const { plotBonusVariation } = battle;&lt;br /&gt;
&lt;br /&gt;
  const ctx = plotBonusVariation.getContext(&amp;quot;2d&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  const chart = new Chart(ctx, {&lt;br /&gt;
    type: &amp;quot;line&amp;quot;,&lt;br /&gt;
    data: {&lt;br /&gt;
      datasets: [&lt;br /&gt;
        {&lt;br /&gt;
          label: defaultText.averageDamage,&lt;br /&gt;
          backgroundColor: &amp;quot;rgba(75, 192, 192, 0.2)&amp;quot;,&lt;br /&gt;
          borderColor: &amp;quot;rgba(75, 192, 192, 1)&amp;quot;,&lt;br /&gt;
          fill: true,&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          label: defaultText.damageAugmentation,&lt;br /&gt;
          backgroundColor: &amp;quot;rgba(192, 192, 75, 0.2)&amp;quot;,&lt;br /&gt;
          borderColor: &amp;quot;rgba(192, 192, 75, 1)&amp;quot;,&lt;br /&gt;
          hidden: true,&lt;br /&gt;
          yTicksFormat: { style: &amp;quot;percent&amp;quot; },&lt;br /&gt;
          fill: true,&lt;br /&gt;
        },&lt;br /&gt;
      ],&lt;br /&gt;
    },&lt;br /&gt;
    options: {&lt;br /&gt;
      locale: currentLanguage,&lt;br /&gt;
      responsive: true,&lt;br /&gt;
      maintainAspectRatio: false,&lt;br /&gt;
      plugins: {&lt;br /&gt;
        legend: {&lt;br /&gt;
          display: true,&lt;br /&gt;
          onHover: function (e) {&lt;br /&gt;
            e.native.target.style.cursor = &amp;quot;pointer&amp;quot;;&lt;br /&gt;
          },&lt;br /&gt;
          onLeave: function (e) {&lt;br /&gt;
            e.native.target.style.cursor = &amp;quot;default&amp;quot;;&lt;br /&gt;
          },&lt;br /&gt;
          onClick: function (e, legendItem, legend) {&lt;br /&gt;
            var currentIndex = legendItem.datasetIndex;&lt;br /&gt;
            var ci = legend.chart;&lt;br /&gt;
            var datasets = ci.data.datasets;&lt;br /&gt;
            var isCurrentDatasetVisible = ci.isDatasetVisible(currentIndex);&lt;br /&gt;
            var yAxis = ci.options.scales.y;&lt;br /&gt;
&lt;br /&gt;
            var otherIndex = currentIndex === 0 ? 1 : 0;&lt;br /&gt;
            var visibleDataset = isCurrentDatasetVisible&lt;br /&gt;
              ? datasets[otherIndex]&lt;br /&gt;
              : datasets[currentIndex];&lt;br /&gt;
&lt;br /&gt;
            datasets[currentIndex].hidden = isCurrentDatasetVisible;&lt;br /&gt;
            datasets[otherIndex].hidden = !isCurrentDatasetVisible;&lt;br /&gt;
&lt;br /&gt;
            yAxis.title.text = visibleDataset.label;&lt;br /&gt;
            yAxis.ticks.format = visibleDataset.yTicksFormat;&lt;br /&gt;
&lt;br /&gt;
            ci.update();&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        title: {&lt;br /&gt;
          display: true,&lt;br /&gt;
          text: defaultText.bonusVariationTitle.split(&amp;quot;[[]]&amp;quot;),&lt;br /&gt;
          font: {&lt;br /&gt;
            size: 18,&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        tooltip: {&lt;br /&gt;
          caretPadding: 10,&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
      scales: {&lt;br /&gt;
        x: {&lt;br /&gt;
          type: &amp;quot;linear&amp;quot;,&lt;br /&gt;
          position: &amp;quot;bottom&amp;quot;,&lt;br /&gt;
          title: {&lt;br /&gt;
            display: true,&lt;br /&gt;
            text: &amp;quot;Bonus&amp;quot;,&lt;br /&gt;
            font: {&lt;br /&gt;
              size: 16,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          ticks: {&lt;br /&gt;
            callback: function (value) {&lt;br /&gt;
              if (Number.isInteger(value)) {&lt;br /&gt;
                return Number(value);&lt;br /&gt;
              }&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        y: {&lt;br /&gt;
          title: {&lt;br /&gt;
            display: true,&lt;br /&gt;
            text: defaultText.averageDamage,&lt;br /&gt;
            font: {&lt;br /&gt;
              size: 16,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
      elements: {&lt;br /&gt;
        point: {&lt;br /&gt;
          borderWidth: 1,&lt;br /&gt;
          radius: 3,&lt;br /&gt;
          hitRadius: 3,&lt;br /&gt;
          hoverRadius: 6,&lt;br /&gt;
          hoverBorderWidth: 2,&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
    },&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  battle.bonusVariationChart = chart;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterAttackTypeSelection(characters, battleChoice, targetValue) {&lt;br /&gt;
  var { nameOrVnum: attackerNameOrVnum, isCharacter: isAttackerPlayer } =&lt;br /&gt;
    parseTypeAndName(targetValue);&lt;br /&gt;
&lt;br /&gt;
  if (isAttackerPlayer) {&lt;br /&gt;
    var attacker = characters.savedCharacters[attackerNameOrVnum];&lt;br /&gt;
    filterAttackTypeSelectionCharacter(attacker, battleChoice.attackType);&lt;br /&gt;
  } else {&lt;br /&gt;
    filterAttackTypeSelectionMonster(battleChoice.attackType);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addBattleData(battle) {&lt;br /&gt;
  var errorElements = document.querySelectorAll(&amp;quot;[data-error]&amp;quot;);&lt;br /&gt;
  var { elements: attackTypeElements, container: attackTypeContainer } =&lt;br /&gt;
    battle.battleChoice.attackType;&lt;br /&gt;
  var attackTypeChilds = attackTypeContainer.children;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; errorElements.length; index++) {&lt;br /&gt;
    var errorElement = errorElements[index];&lt;br /&gt;
    battle.errorInformation[errorElement.dataset.error] = errorElement;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (var index = 1; index &amp;lt; attackTypeChilds.length - 1; index++) {&lt;br /&gt;
    var attackTypeChild = attackTypeChilds[index];&lt;br /&gt;
    var input = attackTypeChild.querySelector(&amp;quot;input&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    attackTypeElements.push({&lt;br /&gt;
      container: attackTypeChild,&lt;br /&gt;
      input: input,&lt;br /&gt;
      inputClass: input.dataset.class,&lt;br /&gt;
      inputValue: input.value,&lt;br /&gt;
    });&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createDamageCalculatorInformation(&lt;br /&gt;
  defaultLang,&lt;br /&gt;
  currentLanguage,&lt;br /&gt;
  defaultText&lt;br /&gt;
) {&lt;br /&gt;
  const characters = {&lt;br /&gt;
    unsavedChanges: false,&lt;br /&gt;
    savedCharacters: {},&lt;br /&gt;
    currentCharacter: null,&lt;br /&gt;
    savedMonsters: getSavedMonsters(),&lt;br /&gt;
    monsterElements: {},&lt;br /&gt;
    characterCreation: document.getElementById(&amp;quot;character-creation&amp;quot;),&lt;br /&gt;
    addNewCharacterButton: document.getElementById(&amp;quot;add-new-character&amp;quot;),&lt;br /&gt;
    dropZone: document.getElementById(&amp;quot;character-drop-zone&amp;quot;),&lt;br /&gt;
    characterInput: document.getElementById(&amp;quot;character-input&amp;quot;),&lt;br /&gt;
    newCharacterTemplate: document.getElementById(&amp;quot;new-character-template&amp;quot;)&lt;br /&gt;
      .children[0],&lt;br /&gt;
    charactersContainer: document.getElementById(&amp;quot;characters-container&amp;quot;),&lt;br /&gt;
    monsterButtonTemplates: document.getElementById(&amp;quot;monster-button-templates&amp;quot;),&lt;br /&gt;
    monsterTemplate: document.getElementById(&amp;quot;new-monster-template&amp;quot;)&lt;br /&gt;
      .children[0],&lt;br /&gt;
    monstersContainer: document.getElementById(&amp;quot;monsters-container&amp;quot;),&lt;br /&gt;
    monsteriFrame: document.getElementById(&amp;quot;monster-iframe&amp;quot;),&lt;br /&gt;
    stoneiFrame: document.getElementById(&amp;quot;stone-iframe&amp;quot;),&lt;br /&gt;
    saveButton: document.getElementById(&amp;quot;save-character&amp;quot;),&lt;br /&gt;
    weaponCategory: document.getElementById(&amp;quot;weapon-category&amp;quot;),&lt;br /&gt;
    weaponDisplay: document.getElementById(&amp;quot;weapon-display&amp;quot;),&lt;br /&gt;
    randomAttackValue: document.getElementById(&amp;quot;random-attack-value&amp;quot;),&lt;br /&gt;
    randomMagicAttackValue: document.getElementById(&lt;br /&gt;
      &amp;quot;random-magic-attack-value&amp;quot;&lt;br /&gt;
    ),&lt;br /&gt;
    toggleSiblings: {},&lt;br /&gt;
    polymorphDisplay: document.getElementById(&amp;quot;polymorph-display&amp;quot;),&lt;br /&gt;
    bonusVariation: {&lt;br /&gt;
      tabButton: document.getElementById(&amp;quot;Variation&amp;quot;),&lt;br /&gt;
      checkbox: document.getElementById(&amp;quot;use-bonus-variation&amp;quot;),&lt;br /&gt;
      input: document.getElementById(&amp;quot;bonus-variation&amp;quot;),&lt;br /&gt;
      inputName: document.getElementById(&amp;quot;bonus-variation-name&amp;quot;),&lt;br /&gt;
      container: document.getElementById(&amp;quot;bonus-variation-creation&amp;quot;),&lt;br /&gt;
      minValue: document.getElementById(&amp;quot;bonus-variation-min-value&amp;quot;),&lt;br /&gt;
      maxValue: document.getElementById(&amp;quot;bonus-variation-max-value&amp;quot;),&lt;br /&gt;
      disabledText: document.getElementById(&amp;quot;bonus-variation-disabled&amp;quot;),&lt;br /&gt;
      selectedText: document.getElementById(&amp;quot;bonus-variation-selected&amp;quot;),&lt;br /&gt;
      displaySpan: document.getElementById(&amp;quot;bonus-variation-display&amp;quot;),&lt;br /&gt;
    },&lt;br /&gt;
    skillElementsToFilter: document.querySelectorAll(&lt;br /&gt;
      &amp;quot;#skill-container [data-class]&amp;quot;&lt;br /&gt;
    ),&lt;br /&gt;
    currentLanguage: currentLanguage,&lt;br /&gt;
    translateMonsters: defaultLang !== currentLanguage,&lt;br /&gt;
    defaultText: defaultText,&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  for (const [pseudo, character] of Object.entries(getSavedCharacters())) {&lt;br /&gt;
    characters.savedCharacters[pseudo] = character;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  document.querySelectorAll(&amp;quot;.toggle-sibling&amp;quot;).forEach(function (element) {&lt;br /&gt;
    const target = element.dataset.target;&lt;br /&gt;
    const sibling = document.getElementById(target);&lt;br /&gt;
    characters.toggleSiblings[element.name] = sibling;&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  const constants = createConstants();&lt;br /&gt;
&lt;br /&gt;
  const battle = {&lt;br /&gt;
    savedFights: getSavedFights(),&lt;br /&gt;
    battleChoice: {&lt;br /&gt;
      resetAttackType: false,&lt;br /&gt;
      form: document.getElementById(&amp;quot;create-battle&amp;quot;),&lt;br /&gt;
      template: document.getElementById(&amp;quot;battle-selection-template&amp;quot;)&lt;br /&gt;
        .children[0],&lt;br /&gt;
      raceToImage: {&lt;br /&gt;
        warrior: &amp;quot;/images/0/0f/Bandeaurougehomme.png&amp;quot;,&lt;br /&gt;
        ninja: &amp;quot;/images/0/0e/Queuedechevalclair.png&amp;quot;,&lt;br /&gt;
        sura: &amp;quot;/images/3/37/Couperespectablerouge.png&amp;quot;,&lt;br /&gt;
        shaman: &amp;quot;/images/6/6a/Coupeeleganteclairfemme.png&amp;quot;,&lt;br /&gt;
        lycan: &amp;quot;/images/4/4e/Protectionfrontalerouge.png&amp;quot;,&lt;br /&gt;
      },&lt;br /&gt;
      categories: [&amp;quot;attacker&amp;quot;, &amp;quot;victim&amp;quot;],&lt;br /&gt;
      translateMonsters: defaultLang !== currentLanguage,&lt;br /&gt;
      attacker: {&lt;br /&gt;
        character: {&lt;br /&gt;
          count: 0,&lt;br /&gt;
          container: document.getElementById(&amp;quot;attacker-selection-characters&amp;quot;),&lt;br /&gt;
          elements: {},&lt;br /&gt;
        },&lt;br /&gt;
        monster: {&lt;br /&gt;
          count: 0,&lt;br /&gt;
          container: document.getElementById(&amp;quot;attacker-selection-monsters&amp;quot;),&lt;br /&gt;
          elements: {},&lt;br /&gt;
        },&lt;br /&gt;
        button: document.getElementById(&amp;quot;attacker-trigger&amp;quot;),&lt;br /&gt;
        defaultButtonContent: document.getElementById(&lt;br /&gt;
          &amp;quot;attacker-default-button-content&amp;quot;&lt;br /&gt;
        ),&lt;br /&gt;
        buttonContent: document.getElementById(&amp;quot;attacker-button-content&amp;quot;),&lt;br /&gt;
        container: document.getElementById(&amp;quot;attacker-selection&amp;quot;),&lt;br /&gt;
        selected: null,&lt;br /&gt;
      },&lt;br /&gt;
      victim: {&lt;br /&gt;
        character: {&lt;br /&gt;
          count: 0,&lt;br /&gt;
          container: document.getElementById(&amp;quot;victim-selection-characters&amp;quot;),&lt;br /&gt;
          elements: {},&lt;br /&gt;
        },&lt;br /&gt;
        monster: {&lt;br /&gt;
          count: 0,&lt;br /&gt;
          container: document.getElementById(&amp;quot;victim-selection-monsters&amp;quot;),&lt;br /&gt;
          elements: {},&lt;br /&gt;
        },&lt;br /&gt;
        stone: {&lt;br /&gt;
          count: 0,&lt;br /&gt;
          container: document.getElementById(&amp;quot;victim-selection-stones&amp;quot;),&lt;br /&gt;
          elements: {},&lt;br /&gt;
        },&lt;br /&gt;
        button: document.getElementById(&amp;quot;victim-trigger&amp;quot;),&lt;br /&gt;
        defaultButtonContent: document.getElementById(&lt;br /&gt;
          &amp;quot;victim-default-button-content&amp;quot;&lt;br /&gt;
        ),&lt;br /&gt;
        buttonContent: document.getElementById(&amp;quot;victim-button-content&amp;quot;),&lt;br /&gt;
        selected: null,&lt;br /&gt;
      },&lt;br /&gt;
      attackType: {&lt;br /&gt;
        container: document.getElementById(&amp;quot;attack-type-selection&amp;quot;),&lt;br /&gt;
        elements: [],&lt;br /&gt;
        defaultInput: document.getElementById(&amp;quot;physical-attack&amp;quot;),&lt;br /&gt;
        selectedText: &amp;quot;&amp;quot;,&lt;br /&gt;
      },&lt;br /&gt;
    },&lt;br /&gt;
    damageWeightedByType: {},&lt;br /&gt;
    scatterDataByType: {},&lt;br /&gt;
    damageByBonus: [],&lt;br /&gt;
    tableResultFight: document.getElementById(&amp;quot;result-table-fight&amp;quot;),&lt;br /&gt;
    tableResultHistory: document.getElementById(&amp;quot;result-table-history&amp;quot;),&lt;br /&gt;
    deleteFightTemplate: document.getElementById(&amp;quot;delete-fight-template&amp;quot;)&lt;br /&gt;
      .children[0],&lt;br /&gt;
    errorInformation: {},&lt;br /&gt;
    fightResultTitle: document.getElementById(&amp;quot;fight-result-title&amp;quot;),&lt;br /&gt;
    fightResultContainer: document.getElementById(&amp;quot;fight-result-container&amp;quot;),&lt;br /&gt;
    downLoadRawData: document.getElementById(&amp;quot;download-raw-data&amp;quot;),&lt;br /&gt;
    downLoadRawDataVariation: document.getElementById(&lt;br /&gt;
      &amp;quot;download-raw-data-variation&amp;quot;&lt;br /&gt;
    ),&lt;br /&gt;
    bonusVariationResultContainer: document.getElementById(&lt;br /&gt;
      &amp;quot;bonus-variation-result-container&amp;quot;&lt;br /&gt;
    ),&lt;br /&gt;
    reduceChartPointsContainer: document.getElementById(&lt;br /&gt;
      &amp;quot;reduce-chart-points-container&amp;quot;&lt;br /&gt;
    ),&lt;br /&gt;
    reduceChartPoints: document.getElementById(&amp;quot;reduce-chart-points&amp;quot;),&lt;br /&gt;
    plotDamage: document.getElementById(&amp;quot;plot-damage&amp;quot;),&lt;br /&gt;
    plotBonusVariation: document.getElementById(&amp;quot;plot-bonus-variation&amp;quot;),&lt;br /&gt;
    chartDescriptionContainer: document.getElementById(&lt;br /&gt;
      &amp;quot;chart-description-container&amp;quot;&lt;br /&gt;
    ),&lt;br /&gt;
    damageInfoContainer: document.getElementById(&amp;quot;damage-info-container&amp;quot;),&lt;br /&gt;
    uniqueDamageCounters: document.querySelectorAll(&amp;quot;.unique-damage-counter&amp;quot;),&lt;br /&gt;
    possibleDamageCounter: document.getElementById(&amp;quot;possible-damage-counter&amp;quot;),&lt;br /&gt;
    damageTime: document.getElementById(&amp;quot;damage-time&amp;quot;),&lt;br /&gt;
    displayTime: document.getElementById(&amp;quot;display-time&amp;quot;),&lt;br /&gt;
    simulationCounter: document.getElementById(&amp;quot;simulation-counter&amp;quot;),&lt;br /&gt;
    simulationTime: document.getElementById(&amp;quot;simulation-time&amp;quot;),&lt;br /&gt;
    numberFormats: {&lt;br /&gt;
      default: new Intl.NumberFormat(currentLanguage, {&lt;br /&gt;
        minimumFractionDigits: 0,&lt;br /&gt;
        maximumFractionDigits: 1,&lt;br /&gt;
      }),&lt;br /&gt;
      percent: new Intl.NumberFormat(currentLanguage, {&lt;br /&gt;
        style: &amp;quot;percent&amp;quot;,&lt;br /&gt;
        maximumFractionDigits: 3,&lt;br /&gt;
      }),&lt;br /&gt;
      second: new Intl.NumberFormat(currentLanguage, {&lt;br /&gt;
        style: &amp;quot;unit&amp;quot;,&lt;br /&gt;
        unit: &amp;quot;second&amp;quot;,&lt;br /&gt;
        unitDisplay: &amp;quot;long&amp;quot;,&lt;br /&gt;
        maximumFractionDigits: 3,&lt;br /&gt;
      }),&lt;br /&gt;
    },&lt;br /&gt;
    mapping: createMapping(),&lt;br /&gt;
    constants: constants,&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  addBattleData(battle);&lt;br /&gt;
  initResultTableHistory(battle);&lt;br /&gt;
  initDamageChart(battle, currentLanguage, defaultText);&lt;br /&gt;
  initBonusVariationChart(battle, currentLanguage, defaultText);&lt;br /&gt;
  reduceChartPointsListener(battle);&lt;br /&gt;
  downloadRawDataListener(battle);&lt;br /&gt;
&lt;br /&gt;
  return [characters, battle];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function parseText(input) {&lt;br /&gt;
  const regex = /\[\[(.*?)\]\]|([^\[]+)/g;&lt;br /&gt;
  const result = [];&lt;br /&gt;
&lt;br /&gt;
  input.replace(regex, (_, matchA, matchText) =&amp;gt; {&lt;br /&gt;
    if (matchA !== undefined) {&lt;br /&gt;
      result.push({&lt;br /&gt;
        text: matchA,&lt;br /&gt;
        category: matchA === &amp;quot;&amp;quot; ? &amp;quot;NOTRANSLATE&amp;quot; : &amp;quot;A&amp;quot;,&lt;br /&gt;
      });&lt;br /&gt;
    } else if (matchText) {&lt;br /&gt;
      result.push({ text: matchText, category: &amp;quot;#text&amp;quot; });&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  return result;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function translateText(general) {&lt;br /&gt;
  const nodesToTranslate = [&amp;quot;A&amp;quot;, &amp;quot;I&amp;quot;, &amp;quot;B&amp;quot;];&lt;br /&gt;
&lt;br /&gt;
  for (const element of document.querySelectorAll(&amp;quot;[data-t]&amp;quot;)) {&lt;br /&gt;
    const translateText = general[element.dataset.t];&lt;br /&gt;
&lt;br /&gt;
    if (!translateText) continue;&lt;br /&gt;
&lt;br /&gt;
    const childNodes = element.childNodes;&lt;br /&gt;
    const numChildren = childNodes.length;&lt;br /&gt;
&lt;br /&gt;
    if (numChildren === 1) {&lt;br /&gt;
      childNodes[0].textContent = translateText;&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    const parsedText = parseText(translateText);&lt;br /&gt;
    const numParsed = parsedText.length;&lt;br /&gt;
&lt;br /&gt;
    let childIndex = 0;&lt;br /&gt;
    let textIndex = 0;&lt;br /&gt;
&lt;br /&gt;
    while (childIndex &amp;lt; numChildren) {&lt;br /&gt;
      const child = childNodes[childIndex];&lt;br /&gt;
&lt;br /&gt;
      if (textIndex === numParsed) {&lt;br /&gt;
        console.warn(&amp;quot;Bad translation for element&amp;quot;, element);&lt;br /&gt;
        break;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      const parsed = parsedText[textIndex];&lt;br /&gt;
&lt;br /&gt;
      let childName = child.nodeName;&lt;br /&gt;
      const isNodeToTranslate = nodesToTranslate.includes(childName);&lt;br /&gt;
&lt;br /&gt;
      if (&lt;br /&gt;
        (childName === &amp;quot;A&amp;quot; &amp;amp;&amp;amp; child.firstChild?.nodeName === &amp;quot;IMG&amp;quot;) ||&lt;br /&gt;
        !(isNodeToTranslate || childName === &amp;quot;#text&amp;quot;) ||&lt;br /&gt;
        child.dataset?.notranslate&lt;br /&gt;
      ) {&lt;br /&gt;
        childName = &amp;quot;NOTRANSLATE&amp;quot;;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (&lt;br /&gt;
        childName === parsed.category ||&lt;br /&gt;
        (parsed.category === &amp;quot;A&amp;quot; &amp;amp;&amp;amp; isNodeToTranslate)&lt;br /&gt;
      ) {&lt;br /&gt;
        if (childName !== &amp;quot;NOTRANSLATE&amp;quot;) {&lt;br /&gt;
          child.textContent = parsed.text;&lt;br /&gt;
        }&lt;br /&gt;
        childIndex++;&lt;br /&gt;
        textIndex++;&lt;br /&gt;
      } else if (childName === &amp;quot;NOTRANSLATE&amp;quot;) {&lt;br /&gt;
        childIndex++;&lt;br /&gt;
      } else if (isNodeToTranslate) {&lt;br /&gt;
        element.insertBefore(document.createTextNode(parsed.text), child);&lt;br /&gt;
        textIndex++;&lt;br /&gt;
      } else {&lt;br /&gt;
        child.textContent = &amp;quot;&amp;quot;;&lt;br /&gt;
        childIndex++;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (textIndex &amp;lt; parsedText.length) {&lt;br /&gt;
      const textNode = document.createTextNode(parsedText[textIndex].text);&lt;br /&gt;
      element.appendChild(textNode);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function translateWeapons(weapons) {&lt;br /&gt;
  const characterCreation = document.getElementById(&amp;quot;character-creation&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  for (const weaponInput of characterCreation.elements[&amp;quot;weapon&amp;quot;]) {&lt;br /&gt;
    const weaponTranslation = weapons[weaponInput.value];&lt;br /&gt;
&lt;br /&gt;
    if (weaponTranslation) {&lt;br /&gt;
      weaponInput.parentElement.lastElementChild.textContent =&lt;br /&gt;
        weaponTranslation;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleSpecialIndexes(generalTranslations, specialIndexes) {&lt;br /&gt;
  const specialTranslations = {};&lt;br /&gt;
&lt;br /&gt;
  translation.special = specialTranslations;&lt;br /&gt;
&lt;br /&gt;
  for (const [generalIndex, specialKey] of Object.entries(specialIndexes)) {&lt;br /&gt;
    const translatedValue = generalTranslations[generalIndex];&lt;br /&gt;
&lt;br /&gt;
    if (translatedValue) {&lt;br /&gt;
      specialTranslations[specialKey] = translatedValue;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  translation.mapping = {&lt;br /&gt;
    &amp;quot;Demi-humain&amp;quot;: specialTranslations.halfHuman,&lt;br /&gt;
    Mal: specialTranslations.devil,&lt;br /&gt;
    Désert: specialTranslations.desert,&lt;br /&gt;
    Animal: specialTranslations.animal,&lt;br /&gt;
    Orc: specialTranslations.orc,&lt;br /&gt;
    Mystique: specialTranslations.mystic,&lt;br /&gt;
    &amp;quot;Mort-vivant&amp;quot;: specialTranslations.undead,&lt;br /&gt;
    Insecte: specialTranslations.insect,&lt;br /&gt;
    Zodiaque: specialTranslations.zodiac,&lt;br /&gt;
    &amp;quot;Aucun type&amp;quot;: specialTranslations.noType,&lt;br /&gt;
    Mêlée: specialTranslations.melee,&lt;br /&gt;
    Flèche: specialTranslations.arrow,&lt;br /&gt;
    Magique: specialTranslations.magic,&lt;br /&gt;
    DC: specialTranslations.skill,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function translateTitle() {&lt;br /&gt;
  const translatedTitle = translation.special.pageTitle;&lt;br /&gt;
&lt;br /&gt;
  if (translatedTitle) {&lt;br /&gt;
    document.querySelector(&amp;quot;h1&amp;quot;).textContent = translatedTitle;&lt;br /&gt;
    document.querySelector(&amp;quot;ul.subpage&amp;quot;).lastElementChild.textContent =&lt;br /&gt;
      translatedTitle;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function translateSummary() {&lt;br /&gt;
  const tocContainer = document.getElementById(&amp;quot;toc&amp;quot;);&lt;br /&gt;
  const { toc, hide } = translation.special;&lt;br /&gt;
&lt;br /&gt;
  if (tocContainer) {&lt;br /&gt;
    if (toc) {&lt;br /&gt;
      tocContainer.querySelector(&amp;quot;h2&amp;quot;).textContent = toc;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (hide) {&lt;br /&gt;
      tocContainer.querySelector(&amp;quot;a.togglelink&amp;quot;).textContent = hide;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    for (const link of tocContainer.querySelectorAll(&amp;quot;ul a&amp;quot;)) {&lt;br /&gt;
      const hash = link.hash.substr(1);&lt;br /&gt;
      const title = document.getElementById(hash);&lt;br /&gt;
&lt;br /&gt;
      if (title) {&lt;br /&gt;
        const toctext = link.querySelector(&amp;quot;span.toctext&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        if (toctext) {&lt;br /&gt;
          toctext.firstElementChild.textContent = title.textContent;&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function translateDefaultText(defaultText) {&lt;br /&gt;
  const specialTranslations = translation.special;&lt;br /&gt;
&lt;br /&gt;
  for (const key of Object.keys(defaultText)) {&lt;br /&gt;
    if (specialTranslations.hasOwnProperty(key)) {&lt;br /&gt;
      defaultText[key] = specialTranslations[key];&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function translatePage(defaultText, currentLanguage) {&lt;br /&gt;
  const mwContent = document.querySelector(&amp;quot;.mw-content-ltr&amp;quot;);&lt;br /&gt;
  const { general, weapons } = translation;&lt;br /&gt;
  const specialIndexes = {&lt;br /&gt;
    471: &amp;quot;placeholder&amp;quot;,&lt;br /&gt;
    473: &amp;quot;boss&amp;quot;,&lt;br /&gt;
    474: &amp;quot;pageTitle&amp;quot;,&lt;br /&gt;
    475: &amp;quot;toc&amp;quot;,&lt;br /&gt;
    476: &amp;quot;hide&amp;quot;,&lt;br /&gt;
    502: &amp;quot;unsavedWarning&amp;quot;,&lt;br /&gt;
    503: &amp;quot;deleteWarning&amp;quot;,&lt;br /&gt;
    504: &amp;quot;pseudo&amp;quot;,&lt;br /&gt;
    481: &amp;quot;damage&amp;quot;,&lt;br /&gt;
    505: &amp;quot;percentage&amp;quot;,&lt;br /&gt;
    506: &amp;quot;miss&amp;quot;,&lt;br /&gt;
    507: &amp;quot;normalHit&amp;quot;,&lt;br /&gt;
    508: &amp;quot;criticalHit&amp;quot;,&lt;br /&gt;
    509: &amp;quot;piercingHit&amp;quot;,&lt;br /&gt;
    510: &amp;quot;criticalPiercingHit&amp;quot;,&lt;br /&gt;
    511: &amp;quot;damageRepartition&amp;quot;,&lt;br /&gt;
    512: &amp;quot;averageDamage&amp;quot;,&lt;br /&gt;
    513: &amp;quot;damageAugmentation&amp;quot;,&lt;br /&gt;
    514: &amp;quot;bonusVariationTitle&amp;quot;,&lt;br /&gt;
    489: &amp;quot;halfHuman&amp;quot;,&lt;br /&gt;
    490: &amp;quot;devil&amp;quot;,&lt;br /&gt;
    491: &amp;quot;desert&amp;quot;,&lt;br /&gt;
    492: &amp;quot;animal&amp;quot;,&lt;br /&gt;
    493: &amp;quot;orc&amp;quot;,&lt;br /&gt;
    494: &amp;quot;mystic&amp;quot;,&lt;br /&gt;
    495: &amp;quot;undead&amp;quot;,&lt;br /&gt;
    496: &amp;quot;insect&amp;quot;,&lt;br /&gt;
    497: &amp;quot;zodiac&amp;quot;,&lt;br /&gt;
    515: &amp;quot;noType&amp;quot;,&lt;br /&gt;
    498: &amp;quot;melee&amp;quot;,&lt;br /&gt;
    499: &amp;quot;arrow&amp;quot;,&lt;br /&gt;
    500: &amp;quot;magic&amp;quot;,&lt;br /&gt;
    516: &amp;quot;skill&amp;quot;,&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  translateText(general);&lt;br /&gt;
  translateWeapons(weapons);&lt;br /&gt;
  handleSpecialIndexes(general, specialIndexes);&lt;br /&gt;
  translateTitle();&lt;br /&gt;
  translateSummary();&lt;br /&gt;
  translateDefaultText(defaultText);&lt;br /&gt;
&lt;br /&gt;
  if (mwContent) {&lt;br /&gt;
    mwContent.setAttribute(&amp;quot;lang&amp;quot;, currentLanguage);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getDefaultText() {&lt;br /&gt;
  return {&lt;br /&gt;
    unsavedWarning:&lt;br /&gt;
      &amp;quot;Voulez-vous continuer ? Les dernières modifications ne seront pas sauvegardées.&amp;quot;,&lt;br /&gt;
    deleteWarning:&lt;br /&gt;
      &amp;quot;Voulez-vous vraiment supprimer définitivement le personnage [[]] ?&amp;quot;,&lt;br /&gt;
    pseudo: &amp;quot;Pseudo&amp;quot;,&lt;br /&gt;
    damage: &amp;quot;Dégâts&amp;quot;,&lt;br /&gt;
    percentage: &amp;quot;Pourcentage&amp;quot;,&lt;br /&gt;
    miss: &amp;quot;Miss&amp;quot;,&lt;br /&gt;
    normalHit: &amp;quot;Coup classique&amp;quot;,&lt;br /&gt;
    criticalHit: &amp;quot;Coup critique&amp;quot;,&lt;br /&gt;
    piercingHit: &amp;quot;Coup perçant&amp;quot;,&lt;br /&gt;
    criticalPiercingHit: &amp;quot;Coup critique perçant&amp;quot;,&lt;br /&gt;
    damageRepartition: &amp;quot;Distribution des dégâts&amp;quot;,&lt;br /&gt;
    averageDamage: &amp;quot;Dégâts moyens&amp;quot;,&lt;br /&gt;
    damageAugmentation: &amp;quot;Augmentation des dégâts&amp;quot;,&lt;br /&gt;
    bonusVariationTitle:&lt;br /&gt;
      &amp;quot;Évolution des dégâts moyens[[]]par rapport à la valeur d'un bonus&amp;quot;,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setLanguage(radios, lang, url, reload = false) {&lt;br /&gt;
  url.searchParams.set(&amp;quot;lang&amp;quot;, lang);&lt;br /&gt;
  updateLastLang(lang);&lt;br /&gt;
&lt;br /&gt;
  if (reload) {&lt;br /&gt;
    window.location.href = url.toString();&lt;br /&gt;
  } else {&lt;br /&gt;
    radios.value = lang;&lt;br /&gt;
    history.replaceState(null, &amp;quot;&amp;quot;, url);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getCurrentLanguage(defaultLang) {&lt;br /&gt;
  const url = new URL(window.location.href);&lt;br /&gt;
  const URLlang = url.searchParams.get(&amp;quot;lang&amp;quot;);&lt;br /&gt;
  const lastLang = getLastLang();&lt;br /&gt;
  const browserLang = navigator.language.split(&amp;quot;-&amp;quot;)[0];&lt;br /&gt;
  const languageSelection = document.getElementById(&amp;quot;language-selection&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (!languageSelection) {&lt;br /&gt;
    return defaultLang;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  const radios = languageSelection.elements[&amp;quot;country&amp;quot;];&lt;br /&gt;
&lt;br /&gt;
  if (!radios) {&lt;br /&gt;
    return defaultLang;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  languageSelection.addEventListener(&amp;quot;change&amp;quot;, changeLanguage);&lt;br /&gt;
&lt;br /&gt;
  function changeLanguage(event) {&lt;br /&gt;
    const newLang = event.target.value;&lt;br /&gt;
    const newUrl = new URL(window.location.href);&lt;br /&gt;
    setLanguage(radios, newLang, newUrl, true);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  const allowedLanguages = Array.from(radios).map((input) =&amp;gt; input.value);&lt;br /&gt;
&lt;br /&gt;
  for (const lang of [URLlang, lastLang, browserLang]) {&lt;br /&gt;
    if (allowedLanguages.includes(lang)) {&lt;br /&gt;
      setLanguage(radios, lang, url);&lt;br /&gt;
      return lang;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return defaultLang;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadStyle(src) {&lt;br /&gt;
  var link = document.createElement(&amp;quot;link&amp;quot;);&lt;br /&gt;
  link.href = src;&lt;br /&gt;
  link.rel = &amp;quot;stylesheet&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  document.head.appendChild(link);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
async function addScript(src) {&lt;br /&gt;
  return new Promise((resolve, reject) =&amp;gt; {&lt;br /&gt;
    const script = document.createElement(&amp;quot;script&amp;quot;);&lt;br /&gt;
    script.src = src;&lt;br /&gt;
    script.async = true;&lt;br /&gt;
&lt;br /&gt;
    script.onload = () =&amp;gt; resolve();&lt;br /&gt;
    script.onerror = () =&amp;gt; reject(new Error(`Failed to load script: ${src}`));&lt;br /&gt;
&lt;br /&gt;
    document.head.appendChild(script);&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
(async function () {&lt;br /&gt;
  const basePath = &amp;quot;/index.php?title=Utilisateur:Ankhseram/&amp;quot;;&lt;br /&gt;
  const dataScript = `${basePath}WeaponsAndMonsters.js&amp;amp;action=raw&amp;amp;ctype=text/javascript`;&lt;br /&gt;
  const simulatorStyle = `${basePath}SimulatorStyle.css&amp;amp;action=raw&amp;amp;ctype=text/css`;&lt;br /&gt;
  const chartLibrary = &amp;quot;https://cdn.jsdelivr.net/npm/chart.js&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  const defaultLang = &amp;quot;fr&amp;quot;;&lt;br /&gt;
  const defaultText = getDefaultText();&lt;br /&gt;
  const currentLanguage = getCurrentLanguage(defaultLang);&lt;br /&gt;
&lt;br /&gt;
  loadStyle(simulatorStyle);&lt;br /&gt;
&lt;br /&gt;
  let translationScript;&lt;br /&gt;
&lt;br /&gt;
  if (currentLanguage !== defaultLang) {&lt;br /&gt;
    translationScript = `${basePath}Calculator/${currentLanguage}.js&amp;amp;action=raw&amp;amp;ctype=text/javascript`;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  const scriptsToLoad = [addScript(chartLibrary), addScript(dataScript)];&lt;br /&gt;
&lt;br /&gt;
  if (translationScript) {&lt;br /&gt;
    scriptsToLoad.push(addScript(translationScript));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  await Promise.all(scriptsToLoad);&lt;br /&gt;
&lt;br /&gt;
  if (translationScript) {&lt;br /&gt;
    translatePage(defaultText, currentLanguage);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  const [characters, battle] = createDamageCalculatorInformation(&lt;br /&gt;
    defaultLang,&lt;br /&gt;
    currentLanguage,&lt;br /&gt;
    defaultText&lt;br /&gt;
  );&lt;br /&gt;
  characterManagement(characters, battle);&lt;br /&gt;
  monsterManagement(characters, battle);&lt;br /&gt;
  updateBattleChoice(characters, battle.battleChoice);&lt;br /&gt;
  createBattle(characters, battle);&lt;br /&gt;
})();&lt;/div&gt;</summary>
		<author><name>Dexter</name></author>
		
	</entry>
	<entry>
		<id>https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Script/Filter.js&amp;diff=106745</id>
		<title>MediaWiki:Script/Filter.js</title>
		<link rel="alternate" type="text/html" href="https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Script/Filter.js&amp;diff=106745"/>
		<updated>2025-03-11T05:40:11Z</updated>

		<summary type="html">&lt;p&gt;Dexter : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;function removeAccent(str) {&lt;br /&gt;
  return str&lt;br /&gt;
    .normalize(&amp;quot;NFD&amp;quot;)&lt;br /&gt;
    .replace(/[\u0300-\u036f]/g, &amp;quot;&amp;quot;)&lt;br /&gt;
    .toLowerCase();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function toNormalForm(str) {&lt;br /&gt;
  return removeAccent(str)&lt;br /&gt;
    .replace(/-/g, &amp;quot; &amp;quot;)&lt;br /&gt;
    .replace(/[^a-zA-Z0-9 ]/g, &amp;quot;&amp;quot;)&lt;br /&gt;
    .replace(/\s+/g, &amp;quot; &amp;quot;)&lt;br /&gt;
    .trim();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function editCardData(cardsData) {&lt;br /&gt;
  for (let cardIndex = 0; cardIndex &amp;lt; cardsData.length; cardIndex++) {&lt;br /&gt;
    const cardData = cardsData[cardIndex];&lt;br /&gt;
    const cardName = cardData.card.querySelector(&amp;quot;[data-name]&amp;quot;).textContent;&lt;br /&gt;
&lt;br /&gt;
    cardData.name = toNormalForm(cardName);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function observeLanguageChange(filterName, cardsData) {&lt;br /&gt;
  if (!filterName) {&lt;br /&gt;
    return;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  const observer = new MutationObserver(function (mutation) {&lt;br /&gt;
    editCardData(cardsData);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  observer.observe(filterName, { attributes: true });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function openFilter() {&lt;br /&gt;
  const filterButton = document.getElementById(&amp;quot;open-filter&amp;quot;);&lt;br /&gt;
  const filterDropdown = filterButton.nextElementSibling;&lt;br /&gt;
&lt;br /&gt;
  hideElement(filterDropdown);&lt;br /&gt;
&lt;br /&gt;
  filterButton.addEventListener(&amp;quot;click&amp;quot;, handleDropdown);&lt;br /&gt;
&lt;br /&gt;
  function handleDropdown() {&lt;br /&gt;
    toggleElement(filterDropdown);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  document.addEventListener(&amp;quot;mousedown&amp;quot;, function (event) {&lt;br /&gt;
    if (&lt;br /&gt;
      !filterButton.contains(event.target) &amp;amp;&amp;amp;&lt;br /&gt;
      !filterDropdown.contains(event.target)&lt;br /&gt;
    ) {&lt;br /&gt;
      hideElement(filterDropdown);&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function fillData(filter, filterData) {&lt;br /&gt;
  const { filter: category, value } = filter.dataset;&lt;br /&gt;
&lt;br /&gt;
  if (filter.type === &amp;quot;checkbox&amp;quot;) {&lt;br /&gt;
    const span = filter.parentElement.querySelector(&amp;quot;span.counter&amp;quot;);&lt;br /&gt;
    const filterInfo = { value: 0, span };&lt;br /&gt;
    const { checkbox } = filterData;&lt;br /&gt;
&lt;br /&gt;
    checkbox[category] = checkbox[category] || {};&lt;br /&gt;
    checkbox[category][value] = filterInfo;&lt;br /&gt;
  } else if (filter.type === &amp;quot;number&amp;quot;) {&lt;br /&gt;
    const { range } = filterData;&lt;br /&gt;
    if (range.hasOwnProperty(category)) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
    const init = { min: Number(filter.min), max: Number(filter.max) };&lt;br /&gt;
    range[category] = { init: init };&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function extractInitData(card, cardData) {&lt;br /&gt;
  const cardNameElement = card.querySelector(&amp;quot;[data-name]&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  cardData.card = card;&lt;br /&gt;
  cardData.name = toNormalForm(cardNameElement.textContent);&lt;br /&gt;
  cardData.trueName = cardNameElement.firstChild.title;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function extractLevelData(card, cardData) {&lt;br /&gt;
  const levelElement = card.querySelector(&amp;quot;[data-level]&amp;quot;);&lt;br /&gt;
  const [level, rank] = levelElement.textContent.slice(1, -1).split(&amp;quot;, &amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  cardData[&amp;quot;level&amp;quot;] = Number(level);&lt;br /&gt;
  cardData[&amp;quot;rank&amp;quot;] = removeAccent(rank);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function extractElementData(card, cardData) {&lt;br /&gt;
  const elementChild = card.querySelector(&amp;quot;[data-elem]&amp;quot;).children;&lt;br /&gt;
  let elementValue = &amp;quot;&amp;quot;;&lt;br /&gt;
  if (elementChild.length) {&lt;br /&gt;
    for (&lt;br /&gt;
      let elementIndex = 0;&lt;br /&gt;
      elementIndex &amp;lt; elementChild.length;&lt;br /&gt;
      elementIndex++&lt;br /&gt;
    ) {&lt;br /&gt;
      elementValue += elementChild[elementIndex].title + &amp;quot; &amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  elementValue = elementValue.trim() || &amp;quot;Aucun&amp;quot;;&lt;br /&gt;
  cardData.elem = removeAccent(elementValue);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function extractTypeData(card, cardData) {&lt;br /&gt;
  const typeElement = card.querySelector(&amp;quot;[data-type]&amp;quot;);&lt;br /&gt;
  cardData.type = removeAccent(typeElement.textContent.split(&amp;quot; &amp;quot;)[0]);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function extractDamageData(card, cardData) {&lt;br /&gt;
  const damageElement = card.querySelector(&amp;quot;[data-damage]&amp;quot;);&lt;br /&gt;
  cardData.damage = removeAccent(damageElement.textContent.replace(&amp;quot; + &amp;quot;, &amp;quot; &amp;quot;));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function extractLocData(card, cardData) {&lt;br /&gt;
  const locElement = card.querySelector(&amp;quot;[data-loc]&amp;quot;);&lt;br /&gt;
  cardData.loc = locElement.dataset.loc;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getCardsData(cardsContainer, filterData, dataExtractionMapping) {&lt;br /&gt;
  const cards = cardsContainer.children;&lt;br /&gt;
  const activeExtractors = [extractInitData];&lt;br /&gt;
&lt;br /&gt;
  for (const [key, extractorFunction] of Object.entries(&lt;br /&gt;
    dataExtractionMapping&lt;br /&gt;
  )) {&lt;br /&gt;
    if (&lt;br /&gt;
      filterData.range.hasOwnProperty(key) ||&lt;br /&gt;
      filterData.checkbox.hasOwnProperty(key)&lt;br /&gt;
    ) {&lt;br /&gt;
      activeExtractors.push(extractorFunction);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  const cardsData = [];&lt;br /&gt;
&lt;br /&gt;
  for (let cardIndex = 0; cardIndex &amp;lt; cards.length; cardIndex++) {&lt;br /&gt;
    const card = cards[cardIndex];&lt;br /&gt;
    const cardData = {};&lt;br /&gt;
&lt;br /&gt;
    for (const extractor of activeExtractors) {&lt;br /&gt;
      extractor(card, cardData);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    cardsData.push(cardData);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return cardsData;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterInitialization(filterForm) {&lt;br /&gt;
  const filterData = {&lt;br /&gt;
    form: filterForm,&lt;br /&gt;
    filters: { filterName: &amp;quot;&amp;quot;, filter: {}, rangeFilter: {} },&lt;br /&gt;
    range: {},&lt;br /&gt;
    checkbox: {},&lt;br /&gt;
    reverse: false,&lt;br /&gt;
    filterCounter: {&lt;br /&gt;
      count: 0,&lt;br /&gt;
      span: document.getElementById(&amp;quot;filter-counter&amp;quot;),&lt;br /&gt;
    },&lt;br /&gt;
  };&lt;br /&gt;
  const filters = filterForm.querySelectorAll(&amp;quot;[data-filter]&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  filters.forEach((filter) =&amp;gt; fillData(filter, filterData));&lt;br /&gt;
&lt;br /&gt;
  return filterData;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function displayCounterValue(checkbox) {&lt;br /&gt;
  for (let filterCategory in checkbox) {&lt;br /&gt;
    const category = checkbox[filterCategory];&lt;br /&gt;
&lt;br /&gt;
    for (let filterValue in category) {&lt;br /&gt;
      const valueData = category[filterValue];&lt;br /&gt;
&lt;br /&gt;
      valueData.span.textContent = &amp;quot; (&amp;quot; + valueData.value + &amp;quot;)&amp;quot;;&lt;br /&gt;
      valueData.value = 0;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateCounter(cardData, checkbox, filterCategory) {&lt;br /&gt;
  cardData[filterCategory].split(&amp;quot; &amp;quot;).forEach((cardValue) =&amp;gt; {&lt;br /&gt;
    checkbox[filterCategory][cardValue].value += 1;&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isObjectValuesInRangeFilter(parameters, rangeFilter) {&lt;br /&gt;
  return Object.entries(rangeFilter).every(&lt;br /&gt;
    ([property, { min, max }]) =&amp;gt;&lt;br /&gt;
      parameters[property] &amp;gt;= min &amp;amp;&amp;amp; parameters[property] &amp;lt;= max&lt;br /&gt;
  );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterByName(parameters, filterName) {&lt;br /&gt;
  if (filterName) {&lt;br /&gt;
    return parameters.name.includes(filterName);&lt;br /&gt;
  }&lt;br /&gt;
  return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isObjectValuesInFilter(parameters, filter) {&lt;br /&gt;
  return Object.entries(filter).every(([property, values]) =&amp;gt;&lt;br /&gt;
    parameters[property].split(&amp;quot; &amp;quot;).some((value) =&amp;gt; values.includes(value))&lt;br /&gt;
  );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isObjectValuesInFilters(parameters, filter, rangeFilter, filterName) {&lt;br /&gt;
  return (&lt;br /&gt;
    isObjectValuesInFilter(parameters, filter) &amp;amp;&amp;amp;&lt;br /&gt;
    filterByName(parameters, filterName) &amp;amp;&amp;amp;&lt;br /&gt;
    isObjectValuesInRangeFilter(parameters, rangeFilter)&lt;br /&gt;
  );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterCards(cardsContainer, filterData, cardsData) {&lt;br /&gt;
  const { filters, checkbox, filterCounter } = filterData;&lt;br /&gt;
  const { filter, rangeFilter, filterName } = filters;&lt;br /&gt;
&lt;br /&gt;
  if (filterData.reverse) {&lt;br /&gt;
    for (&lt;br /&gt;
      let reverseIndex = 1;&lt;br /&gt;
      reverseIndex &amp;lt; cardsData.length;&lt;br /&gt;
      reverseIndex++&lt;br /&gt;
    ) {&lt;br /&gt;
      cardsContainer.insertBefore(&lt;br /&gt;
        cardsData[reverseIndex].card,&lt;br /&gt;
        cardsContainer.firstChild&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
    cardsData.reverse();&lt;br /&gt;
    filterData.reverse = false;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (let cardIndex = 0; cardIndex &amp;lt; cardsData.length; cardIndex++) {&lt;br /&gt;
    const cardData = cardsData[cardIndex];&lt;br /&gt;
&lt;br /&gt;
    if (isObjectValuesInFilters(cardData, filter, rangeFilter, filterName)) {&lt;br /&gt;
      showElement(cardData.card);&lt;br /&gt;
      for (let filterCategory in checkbox) {&lt;br /&gt;
        updateCounter(cardData, checkbox, filterCategory);&lt;br /&gt;
      }&lt;br /&gt;
    } else {&lt;br /&gt;
      hideElement(cardData.card);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  displayCounterValue(checkbox);&lt;br /&gt;
  updateFilterCounter(filterCounter);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleCheckbox(target, filter, filterCounter) {&lt;br /&gt;
  const { filter: category, value } = target.dataset;&lt;br /&gt;
&lt;br /&gt;
  if (target.checked) {&lt;br /&gt;
    filter[category] = filter[category] || [];&lt;br /&gt;
    filter[category].push(value);&lt;br /&gt;
    filterCounter.count += 1;&lt;br /&gt;
  } else {&lt;br /&gt;
    const index = filter[category].indexOf(value);&lt;br /&gt;
    if (index !== -1) {&lt;br /&gt;
      filter[category].splice(index, 1);&lt;br /&gt;
    }&lt;br /&gt;
    if (!filter[category].length) {&lt;br /&gt;
      delete filter[category];&lt;br /&gt;
    }&lt;br /&gt;
    filterCounter.count -= 1;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleNumberType(target, rangeFilter, range, filterCounter) {&lt;br /&gt;
  const { filter: category, value: extremum } = target.dataset;&lt;br /&gt;
  const currentValue = Number(target.value);&lt;br /&gt;
  const initialRange = range[category].init;&lt;br /&gt;
&lt;br /&gt;
  if (rangeFilter[category]) {&lt;br /&gt;
    rangeFilter[category][extremum] = currentValue;&lt;br /&gt;
  } else {&lt;br /&gt;
    rangeFilter[category] = {&lt;br /&gt;
      min: initialRange.min,&lt;br /&gt;
      max: initialRange.max,&lt;br /&gt;
    };&lt;br /&gt;
    rangeFilter[category][extremum] = currentValue;&lt;br /&gt;
    filterCounter.count += 1;&lt;br /&gt;
  }&lt;br /&gt;
  if (&lt;br /&gt;
    rangeFilter[category].max === initialRange.max &amp;amp;&amp;amp;&lt;br /&gt;
    rangeFilter[category].min === initialRange.min&lt;br /&gt;
  ) {&lt;br /&gt;
    delete rangeFilter[category];&lt;br /&gt;
    filterCounter.count -= 1;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateFilterCounter(filterCounter) {&lt;br /&gt;
  if (filterCounter.count) {&lt;br /&gt;
    filterCounter.span.textContent = `(${filterCounter.count})`;&lt;br /&gt;
  } else {&lt;br /&gt;
    filterCounter.span.textContent = &amp;quot;&amp;quot;;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleFormEvents(cardsContainer, filterForm, filterData, cardsData) {&lt;br /&gt;
  const { filters, range, filterCounter } = filterData;&lt;br /&gt;
  let debounceTimer;&lt;br /&gt;
&lt;br /&gt;
  filterForm.addEventListener(&amp;quot;submit&amp;quot;, function (event) {&lt;br /&gt;
    event.preventDefault();&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  filterForm.addEventListener(&amp;quot;change&amp;quot;, updateFilter);&lt;br /&gt;
&lt;br /&gt;
  filterForm.addEventListener(&amp;quot;input&amp;quot;, function (event) {&lt;br /&gt;
    clearTimeout(debounceTimer);&lt;br /&gt;
    debounceTimer = setTimeout(() =&amp;gt; {&lt;br /&gt;
      if (event.target.id === &amp;quot;filter-name&amp;quot;) {&lt;br /&gt;
        updateFilter(event, true);&lt;br /&gt;
      }&lt;br /&gt;
    }, 500);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  function updateFilter(event, filterByName = false) {&lt;br /&gt;
    const target = event.target;&lt;br /&gt;
    const targetType = target.type;&lt;br /&gt;
&lt;br /&gt;
    if (filterByName) {&lt;br /&gt;
      filters.filterName = toNormalForm(target.value);&lt;br /&gt;
    } else if (targetType === &amp;quot;checkbox&amp;quot;) {&lt;br /&gt;
      handleCheckbox(target, filters.filter, filterCounter);&lt;br /&gt;
    } else if (targetType === &amp;quot;number&amp;quot;) {&lt;br /&gt;
      handleNumberType(target, filters.rangeFilter, range, filterCounter);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    filterCards(cardsContainer, filterData, cardsData);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function processUrlParameter(filterName, filterData, key, value) {&lt;br /&gt;
  const { filters, filterCounter } = filterData;&lt;br /&gt;
&lt;br /&gt;
  if (key === &amp;quot;name&amp;quot;) {&lt;br /&gt;
    filterName.value = toNormalForm(value);&lt;br /&gt;
    filters.filterName = value;&lt;br /&gt;
  } else if (Object.keys(filterData.checkbox).indexOf(key) !== -1) {&lt;br /&gt;
    const checkboxElement = document.getElementById(key + &amp;quot;-&amp;quot; + value);&lt;br /&gt;
&lt;br /&gt;
    if (!checkboxElement) return;&lt;br /&gt;
&lt;br /&gt;
    checkboxElement.checked = true;&lt;br /&gt;
    filters.filter[key] = filters.filter[key] || [];&lt;br /&gt;
    filters.filter[key].push(value);&lt;br /&gt;
    filterCounter.count += 1;&lt;br /&gt;
  } else if (key === &amp;quot;reverse&amp;quot;) {&lt;br /&gt;
    if (value === &amp;quot;1&amp;quot;) {&lt;br /&gt;
      filterData.reverse = true;&lt;br /&gt;
      const reverseElement = document.getElementById(&amp;quot;filter-reverse&amp;quot;);&lt;br /&gt;
      if (reverseElement) {&lt;br /&gt;
        reverseElement.checked = true;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    const [splitKey, extremum] = key.split(&amp;quot;-&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (Object.keys(filterData.range).indexOf(splitKey) !== -1) {&lt;br /&gt;
      const rangeElement = document.getElementById(key);&lt;br /&gt;
&lt;br /&gt;
      if (!rangeElement) return;&lt;br /&gt;
&lt;br /&gt;
      rangeElement.value = value;&lt;br /&gt;
&lt;br /&gt;
      const rangeData = filterData.range[splitKey];&lt;br /&gt;
      const rangeFilter = filters.rangeFilter;&lt;br /&gt;
&lt;br /&gt;
      if (rangeFilter[splitKey]) {&lt;br /&gt;
        rangeFilter[splitKey][extremum] = value;&lt;br /&gt;
      } else {&lt;br /&gt;
        rangeFilter[splitKey] = {&lt;br /&gt;
          min: rangeData.init.min,&lt;br /&gt;
          max: rangeData.init.max,&lt;br /&gt;
        };&lt;br /&gt;
        rangeFilter[splitKey][extremum] = value;&lt;br /&gt;
        filterCounter.count += 1;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterWithUrl(filterName, filterData) {&lt;br /&gt;
  const url = new URL(window.location.href);&lt;br /&gt;
  const { hash, search } = url;&lt;br /&gt;
  let useParams = true;&lt;br /&gt;
&lt;br /&gt;
  if (hash) {&lt;br /&gt;
    const start = &amp;quot;.3F&amp;quot;;&lt;br /&gt;
    const equal = &amp;quot;.3D&amp;quot;;&lt;br /&gt;
    const and = &amp;quot;.26&amp;quot;;&lt;br /&gt;
    const startParametersIndex = hash.indexOf(start);&lt;br /&gt;
&lt;br /&gt;
    if (startParametersIndex !== -1) {&lt;br /&gt;
      const parameters = hash.slice(startParametersIndex + start.length);&lt;br /&gt;
&lt;br /&gt;
      parameters.split(and).forEach(function (keyValue) {&lt;br /&gt;
        const [key, value] = keyValue.split(equal);&lt;br /&gt;
        processUrlParameter(filterName, filterData, key, value);&lt;br /&gt;
      });&lt;br /&gt;
&lt;br /&gt;
      useParams = false;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (useParams) {&lt;br /&gt;
    const URLparams = new URLSearchParams(search);&lt;br /&gt;
&lt;br /&gt;
    for (const [key, value] of URLparams.entries()) {&lt;br /&gt;
      processUrlParameter(filterName, filterData, key, value);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function dispatchFilterReadyEvent(filterForm) {&lt;br /&gt;
  window.top.postMessage(&lt;br /&gt;
    {&lt;br /&gt;
      type: &amp;quot;filterReady&amp;quot;,&lt;br /&gt;
      category: filterForm.dataset.category,&lt;br /&gt;
    },&lt;br /&gt;
    &amp;quot;*&amp;quot;&lt;br /&gt;
  );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
(function () {&lt;br /&gt;
  const filterForm = document.getElementById(&amp;quot;filter-form&amp;quot;);&lt;br /&gt;
  const filterName = document.getElementById(&amp;quot;filter-name&amp;quot;);&lt;br /&gt;
  const cardsContainer = document.getElementById(&amp;quot;cards-container&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  const dataExtractionMapping = {&lt;br /&gt;
    level: extractLevelData,&lt;br /&gt;
    elem: extractElementData,&lt;br /&gt;
    type: extractTypeData,&lt;br /&gt;
    damage: extractDamageData,&lt;br /&gt;
    loc: extractLocData,&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  const filterData = filterInitialization(filterForm);&lt;br /&gt;
  const cardsData = getCardsData(&lt;br /&gt;
    cardsContainer,&lt;br /&gt;
    filterData,&lt;br /&gt;
    dataExtractionMapping&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  observeLanguageChange(filterName, cardsData);&lt;br /&gt;
  openFilter();&lt;br /&gt;
  filterWithUrl(filterName, filterData);&lt;br /&gt;
  filterCards(cardsContainer, filterData, cardsData);&lt;br /&gt;
  handleFormEvents(cardsContainer, filterForm, filterData, cardsData);&lt;br /&gt;
  dispatchFilterReadyEvent(filterForm);&lt;br /&gt;
})();&lt;/div&gt;</summary>
		<author><name>Dexter</name></author>
		
	</entry>
	<entry>
		<id>https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Script/Calculator.js&amp;diff=106744</id>
		<title>MediaWiki:Script/Calculator.js</title>
		<link rel="alternate" type="text/html" href="https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Script/Calculator.js&amp;diff=106744"/>
		<updated>2025-03-11T05:39:19Z</updated>

		<summary type="html">&lt;p&gt;Dexter : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;function removeAccent(str) {&lt;br /&gt;
  return str.normalize(&amp;quot;NFD&amp;quot;).replace(/[\u0300-\u036f]/g, &amp;quot;&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function pseudoFormat(str) {&lt;br /&gt;
  return removeAccent(str).replace(/[^A-Za-z0-9 \(\)\+_-]+/g, &amp;quot;&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isValueInArray(value, array) {&lt;br /&gt;
  return array.indexOf(value) !== -1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function splitFirst(value, delimiter) {&lt;br /&gt;
  var parts = value.split(delimiter);&lt;br /&gt;
  var first = parts[0];&lt;br /&gt;
  var rest = parts.slice(1).join(delimiter);&lt;br /&gt;
  return [first, rest];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function copyObject(object) {&lt;br /&gt;
  var copy = {};&lt;br /&gt;
  for (var key in object) {&lt;br /&gt;
    copy[key] = object[key];&lt;br /&gt;
  }&lt;br /&gt;
  return copy;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function compareNumbers(a, b) {&lt;br /&gt;
  return b - a;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isChecked(attribute) {&lt;br /&gt;
  return attribute === &amp;quot;on&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function floorMultiplication(firstFactor, secondFactor) {&lt;br /&gt;
  return Math.floor((firstFactor * secondFactor).toFixed(8));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function truncateNumber(number, precision) {&lt;br /&gt;
  return Math.floor(number * 10 ** precision) / 10 ** precision;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function newChangeEvent() {&lt;br /&gt;
  return new Event(&amp;quot;change&amp;quot;, { bubbles: true });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function openTargetTab(target) {&lt;br /&gt;
  var tabberContainer = target.closest(&amp;quot;.tabber-container&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (!tabberContainer) {&lt;br /&gt;
    return;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var [buttonsContainer, tabsContainer] = tabberContainer.children;&lt;br /&gt;
  var buttons = buttonsContainer.children;&lt;br /&gt;
  var tabs = tabsContainer.children;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; tabs.length; index++) {&lt;br /&gt;
    var tab = tabs[index];&lt;br /&gt;
    if (tab.contains(target) &amp;amp;&amp;amp; !tab.checkVisibility()) {&lt;br /&gt;
      buttons[index].click();&lt;br /&gt;
      break;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function openTargetCollapsible(target) {&lt;br /&gt;
  var collapsible = target.closest(&amp;quot;.improved-collapsible&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (!collapsible) {&lt;br /&gt;
    return;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var span = collapsible.firstElementChild;&lt;br /&gt;
&lt;br /&gt;
  if (!span.classList.contains(&amp;quot;mw-collapsible-toggle-expanded&amp;quot;)) {&lt;br /&gt;
    span.click();&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function editTableResultRow(row, valuesToDisplay, numberFormat) {&lt;br /&gt;
  row.innerHTML = &amp;quot;&amp;quot;;&lt;br /&gt;
  for (var index = 0; index &amp;lt; valuesToDisplay.length; index++) {&lt;br /&gt;
    var cell = row.insertCell();&lt;br /&gt;
    var textContent;&lt;br /&gt;
&lt;br /&gt;
    if (index &amp;gt;= 3) {&lt;br /&gt;
      textContent = numberFormat.format(valuesToDisplay[index]);&lt;br /&gt;
    } else {&lt;br /&gt;
      textContent = valuesToDisplay[index];&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    cell.textContent = textContent;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return row;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addRowToTableResultHistory(&lt;br /&gt;
  tableResultHistory,&lt;br /&gt;
  valuesToDisplay,&lt;br /&gt;
  deleteFightTemplate,&lt;br /&gt;
  numberFormat&lt;br /&gt;
) {&lt;br /&gt;
  var row = tableResultHistory.insertRow();&lt;br /&gt;
  editTableResultRow(row, valuesToDisplay, numberFormat);&lt;br /&gt;
  var cell = row.insertCell();&lt;br /&gt;
  cell.appendChild(deleteFightTemplate.cloneNode(true));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function processSavedDamage(savedDamage, damageWeightedByType, battleValues) {&lt;br /&gt;
  const { damageTypeWeights, attackTypeMapping } = battleValues;&lt;br /&gt;
&lt;br /&gt;
  for (const key in savedDamage) {&lt;br /&gt;
    const [weight, damageByType] = savedDamage[key];&lt;br /&gt;
&lt;br /&gt;
    for (let index = 0; index &amp;lt; 4; index++) {&lt;br /&gt;
      const damageWeighted = damageWeightedByType[attackTypeMapping[index]];&lt;br /&gt;
      const damageByTypeIndex = damageByType[index];&lt;br /&gt;
&lt;br /&gt;
      if (damageByTypeIndex.length === 0) continue;&lt;br /&gt;
&lt;br /&gt;
      const currentWeight =&lt;br /&gt;
        (weight * damageTypeWeights[index]) / damageByTypeIndex.length;&lt;br /&gt;
&lt;br /&gt;
      for (const damage of damageByTypeIndex) {&lt;br /&gt;
        damageWeighted[damage] = (damageWeighted[damage] || 0) + currentWeight;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcMeanDamage(damageWeightedByType, totalCardinal) {&lt;br /&gt;
  var sumDamage = 0;&lt;br /&gt;
&lt;br /&gt;
  for (var damageTypeName in damageWeightedByType) {&lt;br /&gt;
    if (damageTypeName === &amp;quot;miss&amp;quot;) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var damageWeighted = damageWeightedByType[damageTypeName];&lt;br /&gt;
&lt;br /&gt;
    for (var damage in damageWeighted) {&lt;br /&gt;
      sumDamage += damage * damageWeighted[damage];&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return sumDamage / totalCardinal;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function prepareDamageData(damageWeightedByType, attackValues) {&lt;br /&gt;
  const totalCardinal = attackValues.totalCardinal;&lt;br /&gt;
  const scatterDataByType = {};&lt;br /&gt;
  const criticalAttackRange = attackValues.criticalAttackRange;&lt;br /&gt;
&lt;br /&gt;
  let minDamage = Infinity;&lt;br /&gt;
  let maxDamage = 0;&lt;br /&gt;
  let sumDamage = 0;&lt;br /&gt;
&lt;br /&gt;
  let possibleDamageCount = 0;&lt;br /&gt;
  let possibleDamageCountTemp = 0;&lt;br /&gt;
  let uniqueDamageCount = 0;&lt;br /&gt;
&lt;br /&gt;
  for (const damageTypeName in damageWeightedByType) {&lt;br /&gt;
    if (damageTypeName === &amp;quot;miss&amp;quot;) {&lt;br /&gt;
      scatterDataByType.miss = damageWeightedByType.miss;&lt;br /&gt;
      possibleDamageCount++;&lt;br /&gt;
      uniqueDamageCount++;&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
    const damageWeighted = damageWeightedByType[damageTypeName];&lt;br /&gt;
    const scatterData = [];&lt;br /&gt;
&lt;br /&gt;
    scatterDataByType[damageTypeName] = scatterData;&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      (damageTypeName === &amp;quot;criticalHit&amp;quot; ||&lt;br /&gt;
        damageTypeName === &amp;quot;criticalPiercingHit&amp;quot;) &amp;amp;&amp;amp;&lt;br /&gt;
      criticalAttackRange&lt;br /&gt;
    ) {&lt;br /&gt;
      possibleDamageCountTemp =&lt;br /&gt;
        attackValues.possibleDamageCount * criticalAttackRange.length;&lt;br /&gt;
    } else {&lt;br /&gt;
      possibleDamageCountTemp = attackValues.possibleDamageCount;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    for (let damage in damageWeighted) {&lt;br /&gt;
      damage = +damage;&lt;br /&gt;
&lt;br /&gt;
      if (damage &amp;lt; minDamage) {&lt;br /&gt;
        minDamage = damage;&lt;br /&gt;
      }&lt;br /&gt;
      if (damage &amp;gt; maxDamage) {&lt;br /&gt;
        maxDamage = damage;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      const weight = damageWeighted[damage];&lt;br /&gt;
      const probability = weight / totalCardinal;&lt;br /&gt;
&lt;br /&gt;
      sumDamage += damage * weight;&lt;br /&gt;
      damageWeighted[damage] = probability;&lt;br /&gt;
      scatterData.push({ x: damage, y: probability });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    const scatterDataLength = scatterData.length;&lt;br /&gt;
&lt;br /&gt;
    if (!scatterDataLength) {&lt;br /&gt;
      delete scatterDataByType[damageTypeName];&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    possibleDamageCount += possibleDamageCountTemp;&lt;br /&gt;
    uniqueDamageCount += scatterDataLength;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (minDamage === Infinity) {&lt;br /&gt;
    minDamage = 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  attackValues.possibleDamageCount = possibleDamageCount;&lt;br /&gt;
&lt;br /&gt;
  return [&lt;br /&gt;
    sumDamage / totalCardinal,&lt;br /&gt;
    minDamage,&lt;br /&gt;
    maxDamage,&lt;br /&gt;
    scatterDataByType,&lt;br /&gt;
    uniqueDamageCount,&lt;br /&gt;
  ];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function aggregateDamage(scatterData, maxPoints) {&lt;br /&gt;
  var dataLength = scatterData.length;&lt;br /&gt;
  var remainingData = dataLength;&lt;br /&gt;
  var aggregateScatterData = [];&lt;br /&gt;
&lt;br /&gt;
  for (var groupIndex = 0; groupIndex &amp;lt; maxPoints; groupIndex++) {&lt;br /&gt;
    var groupLength = Math.floor(remainingData / (maxPoints - groupIndex));&lt;br /&gt;
    var startIndex = dataLength - remainingData;&lt;br /&gt;
    var aggregateDamage = 0;&lt;br /&gt;
    var aggregateProbability = 0;&lt;br /&gt;
&lt;br /&gt;
    for (var index = startIndex; index &amp;lt; startIndex + groupLength; index++) {&lt;br /&gt;
      var { x: damage, y: probability } = scatterData[index];&lt;br /&gt;
      aggregateDamage += damage * probability;&lt;br /&gt;
      aggregateProbability += probability;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    aggregateScatterData.push({&lt;br /&gt;
      x: aggregateDamage / aggregateProbability,&lt;br /&gt;
      y: aggregateProbability,&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    remainingData -= groupLength;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return aggregateScatterData;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addToDamageChart(battle, scatterDataByType) {&lt;br /&gt;
  const { chart, datasetsStyle, maxPoints, reduceChartPointsContainer } =&lt;br /&gt;
    battle.damageChart;&lt;br /&gt;
  const isReducePointsChecked = battle.reduceChartPoints.checked;&lt;br /&gt;
  const datasets = chart.data.datasets;&lt;br /&gt;
&lt;br /&gt;
  let isFirstDataset = true;&lt;br /&gt;
&lt;br /&gt;
  datasets.length = 0;&lt;br /&gt;
&lt;br /&gt;
  for (let index = 0; index &amp;lt; datasetsStyle.length; index++) {&lt;br /&gt;
    const dataset = copyObject(datasetsStyle[index]);&lt;br /&gt;
&lt;br /&gt;
    if (!scatterDataByType.hasOwnProperty(dataset.name)) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    const scatterData = scatterDataByType[dataset.name];&lt;br /&gt;
    const canBeReduced = scatterData.length &amp;gt; 2 * maxPoints;&lt;br /&gt;
&lt;br /&gt;
    dataset.hidden = !isFirstDataset;&lt;br /&gt;
    dataset.canBeReduced = canBeReduced;&lt;br /&gt;
&lt;br /&gt;
    if (canBeReduced &amp;amp;&amp;amp; isReducePointsChecked) {&lt;br /&gt;
      dataset.data = aggregateDamage(scatterData, maxPoints);&lt;br /&gt;
    } else {&lt;br /&gt;
      dataset.data = scatterData;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isFirstDataset) {&lt;br /&gt;
      isFirstDataset = false;&lt;br /&gt;
&lt;br /&gt;
      if (canBeReduced) {&lt;br /&gt;
        showElement(reduceChartPointsContainer);&lt;br /&gt;
&lt;br /&gt;
        if (!isReducePointsChecked) {&lt;br /&gt;
          handleChartAnimations(chart, false);&lt;br /&gt;
        }&lt;br /&gt;
      } else {&lt;br /&gt;
        hideElement(reduceChartPointsContainer);&lt;br /&gt;
        handleChartAnimations(chart, true);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    datasets.push(dataset);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  chart.data.missPercentage = scatterDataByType.miss;&lt;br /&gt;
  chart.update();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addToBonusVariationChart(&lt;br /&gt;
  damageByBonus,&lt;br /&gt;
  augmentationByBonus,&lt;br /&gt;
  xLabel,&lt;br /&gt;
  chart&lt;br /&gt;
) {&lt;br /&gt;
  chart.data.datasets[0].data = damageByBonus;&lt;br /&gt;
  chart.data.datasets[1].data = augmentationByBonus;&lt;br /&gt;
  chart.options.scales.x.title.text = xLabel;&lt;br /&gt;
  chart.update();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleChartAnimations(chart, addAnimations) {&lt;br /&gt;
  chart.options.animation = addAnimations;&lt;br /&gt;
  chart.options.animations.colors = addAnimations;&lt;br /&gt;
  chart.options.animations.x = addAnimations;&lt;br /&gt;
  chart.options.transitions.active.animation.duration = addAnimations * 1000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateDamageChartDescription(battle, uniqueDamageCount) {&lt;br /&gt;
  const {&lt;br /&gt;
    chartDescriptionContainer,&lt;br /&gt;
    uniqueDamageCounters,&lt;br /&gt;
    numberFormats: { default: defaultFormat },&lt;br /&gt;
  } = battle;&lt;br /&gt;
&lt;br /&gt;
  if (uniqueDamageCount &amp;gt; 1) {&lt;br /&gt;
    uniqueDamageCounters.forEach(function (element) {&lt;br /&gt;
      element.textContent = defaultFormat.format(uniqueDamageCount);&lt;br /&gt;
    });&lt;br /&gt;
    showElement(chartDescriptionContainer);&lt;br /&gt;
  } else {&lt;br /&gt;
    hideElement(chartDescriptionContainer);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getMonsterName(monsterVnum) {&lt;br /&gt;
  var monsterAttributes = monsterData[monsterVnum];&lt;br /&gt;
  return monsterAttributes[monsterAttributes.length - 1];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getTranslatedMonsterName(monsterVnum) {&lt;br /&gt;
  return translation.monsters[monsterVnum];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterClass(selectedRace, classChoice, selectValueIsChanged = false) {&lt;br /&gt;
  for (var radioNode of classChoice) {&lt;br /&gt;
    var radioGrandParent = radioNode.parentElement.parentElement;&lt;br /&gt;
&lt;br /&gt;
    if (radioNode.getAttribute(&amp;quot;data-race&amp;quot;) === selectedRace) {&lt;br /&gt;
      if (!selectValueIsChanged) {&lt;br /&gt;
        radioNode.checked = true;&lt;br /&gt;
        selectValueIsChanged = true;&lt;br /&gt;
      }&lt;br /&gt;
      showElement(radioGrandParent);&lt;br /&gt;
    } else {&lt;br /&gt;
      hideElement(radioGrandParent);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterWeapon(&lt;br /&gt;
  selectedRace,&lt;br /&gt;
  weaponElement,&lt;br /&gt;
  weaponCategory,&lt;br /&gt;
  allowedWeaponsPerRace,&lt;br /&gt;
  selectValueIsChanged = false&lt;br /&gt;
) {&lt;br /&gt;
  var allowedWeapons = allowedWeaponsPerRace[selectedRace];&lt;br /&gt;
&lt;br /&gt;
  if (!selectValueIsChanged) {&lt;br /&gt;
    var weaponType = createWeapon(weaponElement.value).type;&lt;br /&gt;
&lt;br /&gt;
    if (!isValueInArray(weaponType, allowedWeapons)) {&lt;br /&gt;
      weaponElement.value = 0;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var children = weaponCategory.children;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; children.length; index++) {&lt;br /&gt;
    var child = children[index];&lt;br /&gt;
&lt;br /&gt;
    if (isValueInArray(index, allowedWeapons)) {&lt;br /&gt;
      showElement(child);&lt;br /&gt;
    } else {&lt;br /&gt;
      hideElement(child);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function changePolymorphValues(characterCreation, monsterVnum, monsterImage) {&lt;br /&gt;
  var { polymorphMonster, polymorphMonsterImage } = characterCreation;&lt;br /&gt;
&lt;br /&gt;
  polymorphMonster.value = monsterVnum;&lt;br /&gt;
  polymorphMonsterImage.value = monsterImage;&lt;br /&gt;
&lt;br /&gt;
  polymorphMonster.dispatchEvent(newChangeEvent());&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function resetImageFromWiki(image) {&lt;br /&gt;
  image.removeAttribute(&amp;quot;srcset&amp;quot;);&lt;br /&gt;
  image.removeAttribute(&amp;quot;data-file-width&amp;quot;);&lt;br /&gt;
  image.removeAttribute(&amp;quot;data-file-height&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleImageFromWiki(image, newSrc) {&lt;br /&gt;
  image.src = newSrc;&lt;br /&gt;
  image.alt = newSrc.split(&amp;quot;/&amp;quot;).pop();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handlePolymorphDisplay(characters, monsterVnum, monsterSrc) {&lt;br /&gt;
  var { translateMonsters, polymorphDisplay } = characters;&lt;br /&gt;
  var oldImage = polymorphDisplay.firstChild;&lt;br /&gt;
  var oldLink = oldImage.nextElementSibling;&lt;br /&gt;
  var monsterName = getMonsterName(monsterVnum);&lt;br /&gt;
  var displayName = translateMonsters&lt;br /&gt;
    ? getTranslatedMonsterName(monsterVnum)&lt;br /&gt;
    : monsterName;&lt;br /&gt;
  var newLink = createWikiLink(monsterName, displayName);&lt;br /&gt;
&lt;br /&gt;
  resetImageFromWiki(oldImage);&lt;br /&gt;
  handleImageFromWiki(oldImage, monsterSrc);&lt;br /&gt;
&lt;br /&gt;
  polymorphDisplay.replaceChild(newLink, oldLink);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createWikiLink(pageName, displayName) {&lt;br /&gt;
  var wikiLink = document.createElement(&amp;quot;a&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  wikiLink.href = mw.util.getUrl(pageName);&lt;br /&gt;
  wikiLink.title = pageName;&lt;br /&gt;
  wikiLink.textContent = displayName || pageName;&lt;br /&gt;
&lt;br /&gt;
  return wikiLink;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSelectedWeapon(weaponCategory) {&lt;br /&gt;
  return weaponCategory.querySelector(&amp;quot;input[type='radio']:checked&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleWeaponDisplay(&lt;br /&gt;
  weaponCategory,&lt;br /&gt;
  weaponDisplay,&lt;br /&gt;
  weaponVnum,&lt;br /&gt;
  newWeapon&lt;br /&gt;
) {&lt;br /&gt;
  var newWeapon = newWeapon || getSelectedWeapon(weaponCategory);&lt;br /&gt;
&lt;br /&gt;
  var newImage = newWeapon.nextElementSibling;&lt;br /&gt;
  var newText = document.createElement(&amp;quot;span&amp;quot;);&lt;br /&gt;
  var oldImage = weaponDisplay.firstChild;&lt;br /&gt;
  var oldText = oldImage.nextElementSibling;&lt;br /&gt;
  var weaponTooltip = newImage.nextElementSibling;&lt;br /&gt;
  var originalWeaponName = weaponTooltip.dataset.o;&lt;br /&gt;
  var weaponName = weaponTooltip.textContent;&lt;br /&gt;
&lt;br /&gt;
  if (weaponVnum == 0) {&lt;br /&gt;
    newText.textContent = weaponName;&lt;br /&gt;
  } else {&lt;br /&gt;
    var weaponLink = createWikiLink(originalWeaponName, weaponName);&lt;br /&gt;
    newText.appendChild(weaponLink);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  weaponDisplay.replaceChild(newImage.cloneNode(), oldImage);&lt;br /&gt;
  weaponDisplay.replaceChild(newText, oldText);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterUpgrade(&lt;br /&gt;
  weaponUpgrade,&lt;br /&gt;
  weaponVnum,&lt;br /&gt;
  randomAttackValue,&lt;br /&gt;
  randomMagicAttackValue&lt;br /&gt;
) {&lt;br /&gt;
  var weapon = createWeapon(weaponVnum);&lt;br /&gt;
  var currentUpgrade = Number(weaponUpgrade.value);&lt;br /&gt;
  var weaponUpgradeChildren = weaponUpgrade.children;&lt;br /&gt;
&lt;br /&gt;
  if (weapon.isSerpent) {&lt;br /&gt;
    showElement(randomAttackValue);&lt;br /&gt;
&lt;br /&gt;
    if (weapon.isMagic) {&lt;br /&gt;
      showElement(randomMagicAttackValue);&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    hideElement(randomAttackValue);&lt;br /&gt;
    hideElement(randomMagicAttackValue);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (weapon.maxUpgrade &amp;lt; 1) {&lt;br /&gt;
    hideElement(weaponUpgrade.parentElement);&lt;br /&gt;
  } else {&lt;br /&gt;
    showElement(weaponUpgrade.parentElement);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (var upgrade = 0; upgrade &amp;lt;= weapon.maxUpgrade; upgrade++) {&lt;br /&gt;
    showElement(weaponUpgradeChildren[upgrade]);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (&lt;br /&gt;
    var upgrade = weapon.maxUpgrade + 1;&lt;br /&gt;
    upgrade &amp;lt; weaponUpgradeChildren.length;&lt;br /&gt;
    upgrade++&lt;br /&gt;
  ) {&lt;br /&gt;
    hideElement(weaponUpgradeChildren[upgrade]);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (currentUpgrade &amp;gt; weapon.maxUpgrade) {&lt;br /&gt;
    weaponUpgrade.value = weapon.maxUpgrade;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterCheckbox(checkbox, element) {&lt;br /&gt;
  if (checkbox.checked) {&lt;br /&gt;
    showElement(element);&lt;br /&gt;
  } else {&lt;br /&gt;
    hideElement(element);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterSkills(selectedClass, skillElementsToFilter) {&lt;br /&gt;
  for (var element of skillElementsToFilter) {&lt;br /&gt;
    if (isValueInArray(selectedClass, element.dataset.class)) {&lt;br /&gt;
      showElement(element);&lt;br /&gt;
    } else {&lt;br /&gt;
      hideElement(element);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterForm(characters, battle) {&lt;br /&gt;
  var { saveButton, characterCreation, toggleSiblings } = characters;&lt;br /&gt;
  var allowedWeaponsPerRace = battle.constants.allowedWeaponsPerRace;&lt;br /&gt;
  var battleChoice = battle.battleChoice;&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;change&amp;quot;, function (event) {&lt;br /&gt;
    var target = event.target;&lt;br /&gt;
    var targetName = target.name;&lt;br /&gt;
&lt;br /&gt;
    saveButtonOrange(saveButton);&lt;br /&gt;
    characters.unsavedChanges = true;&lt;br /&gt;
&lt;br /&gt;
    switch (targetName) {&lt;br /&gt;
      case &amp;quot;race&amp;quot;:&lt;br /&gt;
        var selectedRace = target.value;&lt;br /&gt;
        var classChoice = characterCreation.class;&lt;br /&gt;
        var weaponElement = characterCreation.weapon;&lt;br /&gt;
&lt;br /&gt;
        filterClass(selectedRace, classChoice);&lt;br /&gt;
        filterWeapon(&lt;br /&gt;
          selectedRace,&lt;br /&gt;
          weaponElement,&lt;br /&gt;
          characters.weaponCategory,&lt;br /&gt;
          allowedWeaponsPerRace&lt;br /&gt;
        );&lt;br /&gt;
        handleWeaponDisplay(&lt;br /&gt;
          characters.weaponCategory,&lt;br /&gt;
          characters.weaponDisplay,&lt;br /&gt;
          weaponElement.value&lt;br /&gt;
        );&lt;br /&gt;
        filterUpgrade(&lt;br /&gt;
          characterCreation.weaponUpgrade,&lt;br /&gt;
          weaponElement.value,&lt;br /&gt;
          characters.randomAttackValue,&lt;br /&gt;
          characters.randomMagicAttackValue&lt;br /&gt;
        );&lt;br /&gt;
        filterSkills(classChoice.value, characters.skillElementsToFilter);&lt;br /&gt;
        handleBonusVariationUpdate(&lt;br /&gt;
          characterCreation,&lt;br /&gt;
          characters.bonusVariation,&lt;br /&gt;
          true&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        battleChoice.resetAttackType = true;&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;class&amp;quot;:&lt;br /&gt;
        filterSkills(target.value, characters.skillElementsToFilter);&lt;br /&gt;
        handleBonusVariationUpdate(&lt;br /&gt;
          characterCreation,&lt;br /&gt;
          characters.bonusVariation,&lt;br /&gt;
          true&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        battleChoice.resetAttackType = true;&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;weapon&amp;quot;:&lt;br /&gt;
        var weaponElement = characterCreation.weapon;&lt;br /&gt;
&lt;br /&gt;
        handleWeaponDisplay(&lt;br /&gt;
          characters.weaponCategory,&lt;br /&gt;
          characters.weaponDisplay,&lt;br /&gt;
          weaponElement.value,&lt;br /&gt;
          target&lt;br /&gt;
        );&lt;br /&gt;
        filterUpgrade(&lt;br /&gt;
          characterCreation.weaponUpgrade,&lt;br /&gt;
          target.value,&lt;br /&gt;
          characters.randomAttackValue,&lt;br /&gt;
          characters.randomMagicAttackValue&lt;br /&gt;
        );&lt;br /&gt;
        handleBonusVariationUpdate(&lt;br /&gt;
          characterCreation,&lt;br /&gt;
          characters.bonusVariation&lt;br /&gt;
        );&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;isRiding&amp;quot;:&lt;br /&gt;
        battleChoice.resetAttackType = true;&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;isPolymorph&amp;quot;:&lt;br /&gt;
        battleChoice.resetAttackType = true;&lt;br /&gt;
        break;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (toggleSiblings.hasOwnProperty(targetName)) {&lt;br /&gt;
      filterCheckbox(target, toggleSiblings[targetName]);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      targetName.startsWith(&amp;quot;attackSkill&amp;quot;) ||&lt;br /&gt;
      targetName.startsWith(&amp;quot;horseSkill&amp;quot;)&lt;br /&gt;
    ) {&lt;br /&gt;
      battleChoice.resetAttackType = true;&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addUniquePseudo(characterDataObject, savedCharactersPseudo) {&lt;br /&gt;
  var characterPseudo = String(characterDataObject.name);&lt;br /&gt;
  var originalPseudo = characterPseudo;&lt;br /&gt;
  var count = 0;&lt;br /&gt;
&lt;br /&gt;
  var regex = /(.*)(\d)$/;&lt;br /&gt;
  var match = characterPseudo.match(regex);&lt;br /&gt;
&lt;br /&gt;
  if (match) {&lt;br /&gt;
    originalPseudo = match[1];&lt;br /&gt;
    count = match[2];&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  while (isValueInArray(characterPseudo, savedCharactersPseudo)) {&lt;br /&gt;
    characterPseudo = originalPseudo + count;&lt;br /&gt;
    count++;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  characterDataObject.name = characterPseudo;&lt;br /&gt;
  return [characterDataObject, characterPseudo];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function convertToNumber(value) {&lt;br /&gt;
  var valueNumber = Number(value);&lt;br /&gt;
  return isNaN(valueNumber) ? value : valueNumber;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getLocalStorageValue(key, defaultValue) {&lt;br /&gt;
  var storedValue = localStorage.getItem(key);&lt;br /&gt;
&lt;br /&gt;
  if (storedValue) {&lt;br /&gt;
    return JSON.parse(storedValue);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return defaultValue;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSavedCharacters() {&lt;br /&gt;
  return getLocalStorageValue(&amp;quot;mt2-calc.characters.saved&amp;quot;, {});&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSavedMonsters() {&lt;br /&gt;
  return getLocalStorageValue(&amp;quot;mt2-calc.monsters.saved&amp;quot;, {});&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSavedFights() {&lt;br /&gt;
  return getLocalStorageValue(&amp;quot;mt2-calc.fights.saved&amp;quot;, []);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getLastLang() {&lt;br /&gt;
  return getLocalStorageValue(&amp;quot;mt2-calc.language.last-used&amp;quot;, &amp;quot;&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveToLocalStorage(key, value) {&lt;br /&gt;
  localStorage.setItem(key, JSON.stringify(value));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateSavedCharacters(savedCharacters) {&lt;br /&gt;
  saveToLocalStorage(&amp;quot;mt2-calc.characters.saved&amp;quot;, savedCharacters);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateSavedMonsters(savedMonsters) {&lt;br /&gt;
  saveToLocalStorage(&amp;quot;mt2-calc.monsters.saved&amp;quot;, savedMonsters);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateSavedFights(savedFights) {&lt;br /&gt;
  saveToLocalStorage(&amp;quot;mt2-calc.fights.saved&amp;quot;, savedFights);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateLastLang(lang) {&lt;br /&gt;
  saveToLocalStorage(&amp;quot;mt2-calc.language.last-used&amp;quot;, lang);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveCharacter(&lt;br /&gt;
  savedCharacters,&lt;br /&gt;
  characterCreation,&lt;br /&gt;
  battle,&lt;br /&gt;
  newCharacter,&lt;br /&gt;
  characterDataObject&lt;br /&gt;
) {&lt;br /&gt;
  if (!characterDataObject) {&lt;br /&gt;
    var characterData = new FormData(characterCreation);&lt;br /&gt;
    var characterDataObject = {};&lt;br /&gt;
&lt;br /&gt;
    characterData.forEach(function (value, key) {&lt;br /&gt;
      characterDataObject[key] = convertToNumber(value);&lt;br /&gt;
    });&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var characterPseudo = characterDataObject.name;&lt;br /&gt;
  var { battleChoice } = battle;&lt;br /&gt;
&lt;br /&gt;
  savedCharacters[characterPseudo] = characterDataObject;&lt;br /&gt;
  updateSavedCharacters(savedCharacters);&lt;br /&gt;
&lt;br /&gt;
  if (newCharacter) {&lt;br /&gt;
    addBattleChoice(battleChoice, characterPseudo, characterDataObject);&lt;br /&gt;
  } else {&lt;br /&gt;
    updateBattleChoiceImage(&lt;br /&gt;
      battleChoice,&lt;br /&gt;
      characterPseudo,&lt;br /&gt;
      characterDataObject.race&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (battleChoice.resetAttackType) {&lt;br /&gt;
    if (isCharacterSelected(characterPseudo, battleChoice.attacker.selected)) {&lt;br /&gt;
      filterAttackTypeSelectionCharacter(&lt;br /&gt;
        characterDataObject,&lt;br /&gt;
        battleChoice.attackType&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
    battleChoice.resetAttackType = false;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveButtonGreen(saveButton) {&lt;br /&gt;
  saveButton.classList.remove(&amp;quot;unsaved-character&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveButtonOrange(saveButton) {&lt;br /&gt;
  saveButton.classList.add(&amp;quot;unsaved-character&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function characterCreationListener(characters, battle) {&lt;br /&gt;
  var { characterCreation, saveButton, weaponCategory } = characters;&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;submit&amp;quot;, handleSubmitForm);&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;invalid&amp;quot;, handleInvalidInput, true);&lt;br /&gt;
  document.addEventListener(&amp;quot;keydown&amp;quot;, handleSaveShortcut);&lt;br /&gt;
  weaponCategory.addEventListener(&amp;quot;mouseover&amp;quot;, handleTooltipOverflow);&lt;br /&gt;
&lt;br /&gt;
  function handleSubmitForm(event) {&lt;br /&gt;
    event.preventDefault();&lt;br /&gt;
&lt;br /&gt;
    if (characters.unsavedChanges) {&lt;br /&gt;
      saveCharacter(characters.savedCharacters, characterCreation, battle);&lt;br /&gt;
      saveButtonGreen(saveButton);&lt;br /&gt;
      characters.unsavedChanges = false;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function handleInvalidInput(event) {&lt;br /&gt;
    var target = event.target;&lt;br /&gt;
&lt;br /&gt;
    if (target.checkVisibility()) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var autoCorrectInput = target.closest(&amp;quot;.auto-correct-input&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      autoCorrectInput &amp;amp;&amp;amp;&lt;br /&gt;
      autoCorrectInput.classList.contains(&amp;quot;tabber-noactive&amp;quot;)&lt;br /&gt;
    ) {&lt;br /&gt;
      target.value = target.defaultValue;&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    openTargetTab(target);&lt;br /&gt;
    openTargetCollapsible(target);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function handleSaveShortcut(event) {&lt;br /&gt;
    if (event.ctrlKey &amp;amp;&amp;amp; event.key === &amp;quot;s&amp;quot;) {&lt;br /&gt;
      event.preventDefault();&lt;br /&gt;
      saveButton.click();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function handleTooltipOverflow(event) {&lt;br /&gt;
    var label = event.target.closest(&amp;quot;label&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (label) {&lt;br /&gt;
      var tooltip = label.lastChild;&lt;br /&gt;
&lt;br /&gt;
      if (tooltip.classList.contains(&amp;quot;popContenu&amp;quot;)) {&lt;br /&gt;
        var tooltipRect = tooltip.getBoundingClientRect();&lt;br /&gt;
        var modalRect = weaponCategory.getBoundingClientRect();&lt;br /&gt;
&lt;br /&gt;
        if (tooltipRect.right &amp;gt; modalRect.right) {&lt;br /&gt;
          tooltip.style.left = &amp;quot;-100%&amp;quot;;&lt;br /&gt;
        } else if (tooltipRect.left &amp;lt; modalRect.left) {&lt;br /&gt;
          tooltip.style.left = &amp;quot;200%&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function downloadData(content, type, filename) {&lt;br /&gt;
  var link = document.createElement(&amp;quot;a&amp;quot;);&lt;br /&gt;
  var blob = new Blob([content], { type: type });&lt;br /&gt;
  var blobURL = URL.createObjectURL(blob);&lt;br /&gt;
&lt;br /&gt;
  link.href = blobURL;&lt;br /&gt;
  link.download = filename;&lt;br /&gt;
  document.body.appendChild(link);&lt;br /&gt;
&lt;br /&gt;
  link.click();&lt;br /&gt;
  document.body.removeChild(link);&lt;br /&gt;
  URL.revokeObjectURL(blobURL);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function uploadCharacter(&lt;br /&gt;
  selectedFiles,&lt;br /&gt;
  characters,&lt;br /&gt;
  characterTemplate,&lt;br /&gt;
  charactersContainer,&lt;br /&gt;
  battle&lt;br /&gt;
) {&lt;br /&gt;
  var selectFilesLength = selectedFiles.length;&lt;br /&gt;
  var defaultPseudo = characters.defaultText.pseudo;&lt;br /&gt;
&lt;br /&gt;
  for (var fileIndex = 0; fileIndex &amp;lt; selectFilesLength; fileIndex++) {&lt;br /&gt;
    var selectedFile = selectedFiles[fileIndex];&lt;br /&gt;
&lt;br /&gt;
    if (selectedFile.type === &amp;quot;text/plain&amp;quot;) {&lt;br /&gt;
      var reader = new FileReader();&lt;br /&gt;
      reader.onload = function (e) {&lt;br /&gt;
        var fileContent = e.target.result;&lt;br /&gt;
        try {&lt;br /&gt;
          var characterDataObject = JSON.parse(fileContent);&lt;br /&gt;
&lt;br /&gt;
          if (characterDataObject.hasOwnProperty(&amp;quot;name&amp;quot;)) {&lt;br /&gt;
            var characterPseudo = String(characterDataObject.name);&lt;br /&gt;
&lt;br /&gt;
            hideElement(characters.characterCreation);&lt;br /&gt;
            characterPseudo = validPseudo(characterPseudo, defaultPseudo);&lt;br /&gt;
&lt;br /&gt;
            [characterDataObject, characterPseudo] = addUniquePseudo(&lt;br /&gt;
              characterDataObject,&lt;br /&gt;
              Object.keys(characters.savedCharacters)&lt;br /&gt;
            );&lt;br /&gt;
            var selectedCharacter = handleNewCharacter(&lt;br /&gt;
              characters,&lt;br /&gt;
              characterTemplate,&lt;br /&gt;
              charactersContainer,&lt;br /&gt;
              battle,&lt;br /&gt;
              characterPseudo&lt;br /&gt;
            )[0];&lt;br /&gt;
&lt;br /&gt;
            if (selectFilesLength === 1) {&lt;br /&gt;
              updateForm(&lt;br /&gt;
                characterDataObject,&lt;br /&gt;
                characters.characterCreation,&lt;br /&gt;
                characters,&lt;br /&gt;
                selectedCharacter,&lt;br /&gt;
                battle&lt;br /&gt;
              );&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            saveCharacter(&lt;br /&gt;
              characters.savedCharacters,&lt;br /&gt;
              characters.characterCreation,&lt;br /&gt;
              battle,&lt;br /&gt;
              true,&lt;br /&gt;
              characterDataObject&lt;br /&gt;
            );&lt;br /&gt;
          }&lt;br /&gt;
        } catch (error) {&lt;br /&gt;
          console.warn(error);&lt;br /&gt;
          if (error.name === &amp;quot;TypeError&amp;quot;) {&lt;br /&gt;
            // delete the character&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
      };&lt;br /&gt;
      reader.readAsText(selectedFile);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleUploadCharacter(&lt;br /&gt;
  characters,&lt;br /&gt;
  characterTemplate,&lt;br /&gt;
  charactersContainer,&lt;br /&gt;
  battle&lt;br /&gt;
) {&lt;br /&gt;
  var characterInput = characters.characterInput;&lt;br /&gt;
  var dropZone = characters.dropZone;&lt;br /&gt;
&lt;br /&gt;
  characterInput.accept = &amp;quot;.txt&amp;quot;;&lt;br /&gt;
  characterInput.multiple = true;&lt;br /&gt;
  dropZone.setAttribute(&amp;quot;tabindex&amp;quot;, &amp;quot;0&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  dropZone.addEventListener(&amp;quot;click&amp;quot;, function () {&lt;br /&gt;
    characterInput.click();&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  dropZone.addEventListener(&amp;quot;dragover&amp;quot;, function (event) {&lt;br /&gt;
    event.preventDefault();&lt;br /&gt;
    dropZone.classList.add(&amp;quot;drop-zone--dragover&amp;quot;);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  [&amp;quot;dragleave&amp;quot;, &amp;quot;dragend&amp;quot;].forEach(function (type) {&lt;br /&gt;
    dropZone.addEventListener(type, function () {&lt;br /&gt;
      dropZone.classList.remove(&amp;quot;drop-zone--dragover&amp;quot;);&lt;br /&gt;
    });&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  dropZone.addEventListener(&amp;quot;drop&amp;quot;, function (event) {&lt;br /&gt;
    event.preventDefault();&lt;br /&gt;
    uploadCharacter(&lt;br /&gt;
      event.dataTransfer.files,&lt;br /&gt;
      characters,&lt;br /&gt;
      characterTemplate,&lt;br /&gt;
      charactersContainer,&lt;br /&gt;
      battle&lt;br /&gt;
    );&lt;br /&gt;
    dropZone.classList.remove(&amp;quot;drop-zone--dragover&amp;quot;);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  characterInput.addEventListener(&amp;quot;change&amp;quot;, function (event) {&lt;br /&gt;
    uploadCharacter(&lt;br /&gt;
      event.target.files,&lt;br /&gt;
      characters,&lt;br /&gt;
      characterTemplate,&lt;br /&gt;
      charactersContainer,&lt;br /&gt;
      battle&lt;br /&gt;
    );&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function deleteCharacter(characters, pseudo, element, battle) {&lt;br /&gt;
  delete characters.savedCharacters[pseudo];&lt;br /&gt;
  element.remove();&lt;br /&gt;
&lt;br /&gt;
  updateSavedCharacters(characters.savedCharacters);&lt;br /&gt;
  removeBattleChoice(battle.battleChoice, pseudo, &amp;quot;character&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (&lt;br /&gt;
    !Object.keys(characters.savedCharacters).length ||&lt;br /&gt;
    characters.characterCreation.name.value === pseudo&lt;br /&gt;
  ) {&lt;br /&gt;
    saveButtonGreen(characters.saveButton);&lt;br /&gt;
    characters.unsavedChanges = false;&lt;br /&gt;
    hideElement(characters.characterCreation);&lt;br /&gt;
    showElement(characters.characterCreation.previousElementSibling);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function deleteMonster(characters, battle, monsterVnum) {&lt;br /&gt;
  var monsterElements = characters.monsterElements;&lt;br /&gt;
  var monsterType = characters.savedMonsters[monsterVnum].category;&lt;br /&gt;
&lt;br /&gt;
  if (monsterElements.hasOwnProperty(monsterVnum)) {&lt;br /&gt;
    monsterElements[monsterVnum].remove();&lt;br /&gt;
    delete monsterElements[monsterVnum];&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  delete characters.savedMonsters[monsterVnum];&lt;br /&gt;
&lt;br /&gt;
  updateSavedMonsters(characters.savedMonsters);&lt;br /&gt;
  removeBattleChoice(battle.battleChoice, monsterVnum, monsterType);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleStyle(characters, selectedElement) {&lt;br /&gt;
  var currentCharacter = characters.currentCharacter;&lt;br /&gt;
&lt;br /&gt;
  if (currentCharacter) {&lt;br /&gt;
    currentCharacter.classList.remove(&amp;quot;selected-character&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  selectedElement.classList.add(&amp;quot;selected-character&amp;quot;);&lt;br /&gt;
  characters.currentCharacter = selectedElement;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateForm(&lt;br /&gt;
  formData,&lt;br /&gt;
  characterCreation,&lt;br /&gt;
  characters,&lt;br /&gt;
  selectedElement,&lt;br /&gt;
  battle&lt;br /&gt;
) {&lt;br /&gt;
  saveButtonGreen(characters.saveButton);&lt;br /&gt;
  hideElement(characterCreation.previousElementSibling);&lt;br /&gt;
  showElement(characterCreation);&lt;br /&gt;
  handleStyle(characters, selectedElement);&lt;br /&gt;
&lt;br /&gt;
  characterCreation.reset();&lt;br /&gt;
&lt;br /&gt;
  for (var [name, value] of Object.entries(formData)) {&lt;br /&gt;
    var formElement = characterCreation[name];&lt;br /&gt;
&lt;br /&gt;
    if (!formElement) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (formElement.type === &amp;quot;checkbox&amp;quot;) {&lt;br /&gt;
      if (isChecked(value)) {&lt;br /&gt;
        formElement.checked = true;&lt;br /&gt;
      }&lt;br /&gt;
    } else {&lt;br /&gt;
      formElement.value = value;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  var selectedRace = characterCreation.race.value;&lt;br /&gt;
  var classChoice = characterCreation.class;&lt;br /&gt;
  var weaponElement = characterCreation.weapon;&lt;br /&gt;
&lt;br /&gt;
  filterClass(selectedRace, classChoice, true);&lt;br /&gt;
  filterWeapon(&lt;br /&gt;
    selectedRace,&lt;br /&gt;
    weaponElement,&lt;br /&gt;
    characters.weaponCategory,&lt;br /&gt;
    battle.constants.allowedWeaponsPerRace,&lt;br /&gt;
    true&lt;br /&gt;
  );&lt;br /&gt;
  handlePolymorphDisplay(&lt;br /&gt;
    characters,&lt;br /&gt;
    characterCreation.polymorphMonster.value,&lt;br /&gt;
    characterCreation.polymorphMonsterImage.value&lt;br /&gt;
  );&lt;br /&gt;
  handleWeaponDisplay(&lt;br /&gt;
    characters.weaponCategory,&lt;br /&gt;
    characters.weaponDisplay,&lt;br /&gt;
    weaponElement.value&lt;br /&gt;
  );&lt;br /&gt;
  filterUpgrade(&lt;br /&gt;
    characterCreation.weaponUpgrade,&lt;br /&gt;
    weaponElement.value,&lt;br /&gt;
    characters.randomAttackValue,&lt;br /&gt;
    characters.randomMagicAttackValue&lt;br /&gt;
  );&lt;br /&gt;
  for (var [targetName, sibling] of Object.entries(characters.toggleSiblings)) {&lt;br /&gt;
    filterCheckbox(characterCreation[targetName], sibling);&lt;br /&gt;
  }&lt;br /&gt;
  filterSkills(classChoice.value, characters.skillElementsToFilter);&lt;br /&gt;
  handleBonusVariationUpdate(characterCreation, characters.bonusVariation);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleClickOnCharacter(&lt;br /&gt;
  spanInput,&lt;br /&gt;
  target,&lt;br /&gt;
  characters,&lt;br /&gt;
  characterElement,&lt;br /&gt;
  battle,&lt;br /&gt;
  edition&lt;br /&gt;
) {&lt;br /&gt;
  var displayedPseudo = characters.characterCreation.name.value;&lt;br /&gt;
  var pseudo = spanInput.dataset.name;&lt;br /&gt;
  var { unsavedWarning, deleteWarning } = characters.defaultText;&lt;br /&gt;
&lt;br /&gt;
  if (edition) {&lt;br /&gt;
    if (!characters.unsavedChanges) {&lt;br /&gt;
      updateForm(&lt;br /&gt;
        characters.savedCharacters[pseudo],&lt;br /&gt;
        characters.characterCreation,&lt;br /&gt;
        characters,&lt;br /&gt;
        characterElement,&lt;br /&gt;
        battle&lt;br /&gt;
      );&lt;br /&gt;
    } else if (displayedPseudo === pseudo) {&lt;br /&gt;
      // pass&lt;br /&gt;
    } else {&lt;br /&gt;
      var result = confirm(unsavedWarning);&lt;br /&gt;
&lt;br /&gt;
      if (result) {&lt;br /&gt;
        updateForm(&lt;br /&gt;
          characters.savedCharacters[pseudo],&lt;br /&gt;
          characters.characterCreation,&lt;br /&gt;
          characters,&lt;br /&gt;
          characterElement,&lt;br /&gt;
          battle&lt;br /&gt;
        );&lt;br /&gt;
        characters.unsavedChanges = false;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    if (target.tagName === &amp;quot;path&amp;quot;) {&lt;br /&gt;
      target = target.parentElement;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    switch (target.dataset.icon) {&lt;br /&gt;
      case &amp;quot;duplicate&amp;quot;:&lt;br /&gt;
        if (!characters.unsavedChanges) {&lt;br /&gt;
          addNewCharacter(&lt;br /&gt;
            characters,&lt;br /&gt;
            characters.newCharacterTemplate,&lt;br /&gt;
            characters.charactersContainer,&lt;br /&gt;
            battle,&lt;br /&gt;
            pseudo&lt;br /&gt;
          );&lt;br /&gt;
        } else {&lt;br /&gt;
          var result = confirm(unsavedWarning);&lt;br /&gt;
&lt;br /&gt;
          if (result) {&lt;br /&gt;
            addNewCharacter(&lt;br /&gt;
              characters,&lt;br /&gt;
              characters.newCharacterTemplate,&lt;br /&gt;
              characters.charactersContainer,&lt;br /&gt;
              battle,&lt;br /&gt;
              pseudo&lt;br /&gt;
            );&lt;br /&gt;
            saveButtonGreen(characters.saveButton);&lt;br /&gt;
            characters.unsavedChanges = false;&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
        break;&lt;br /&gt;
&lt;br /&gt;
      case &amp;quot;download&amp;quot;:&lt;br /&gt;
        var character = characters.savedCharacters[pseudo];&lt;br /&gt;
        downloadData(&lt;br /&gt;
          JSON.stringify(character),&lt;br /&gt;
          &amp;quot;text/plain&amp;quot;,&lt;br /&gt;
          character.name + &amp;quot;.txt&amp;quot;&lt;br /&gt;
        );&lt;br /&gt;
        break;&lt;br /&gt;
&lt;br /&gt;
      case &amp;quot;delete&amp;quot;:&lt;br /&gt;
        var result = confirm(deleteWarning.replace(&amp;quot;[[]]&amp;quot;, pseudo));&lt;br /&gt;
        if (result) {&lt;br /&gt;
          deleteCharacter(characters, pseudo, characterElement, battle);&lt;br /&gt;
        }&lt;br /&gt;
        break;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleNewCharacter(&lt;br /&gt;
  characters,&lt;br /&gt;
  characterTemplate,&lt;br /&gt;
  charactersContainer,&lt;br /&gt;
  battle,&lt;br /&gt;
  pseudo&lt;br /&gt;
) {&lt;br /&gt;
  var newCharacterTemplate = characterTemplate.cloneNode(true);&lt;br /&gt;
  var spanInput = newCharacterTemplate.querySelector(&amp;quot;span.input&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  newCharacterTemplate.setAttribute(&amp;quot;tabindex&amp;quot;, &amp;quot;0&amp;quot;);&lt;br /&gt;
  charactersContainer.appendChild(newCharacterTemplate);&lt;br /&gt;
&lt;br /&gt;
  if (pseudo) {&lt;br /&gt;
    spanInput.textContent = pseudo;&lt;br /&gt;
    spanInput.setAttribute(&amp;quot;data-name&amp;quot;, pseudo);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  newCharacterTemplate.addEventListener(&amp;quot;click&amp;quot;, function (event) {&lt;br /&gt;
    var target = event.target;&lt;br /&gt;
&lt;br /&gt;
    if (target.tagName === &amp;quot;path&amp;quot; || target.tagName === &amp;quot;svg&amp;quot;) {&lt;br /&gt;
      handleClickOnCharacter(&lt;br /&gt;
        spanInput,&lt;br /&gt;
        target,&lt;br /&gt;
        characters,&lt;br /&gt;
        newCharacterTemplate,&lt;br /&gt;
        battle&lt;br /&gt;
      );&lt;br /&gt;
    } else {&lt;br /&gt;
      handleClickOnCharacter(&lt;br /&gt;
        spanInput,&lt;br /&gt;
        null,&lt;br /&gt;
        characters,&lt;br /&gt;
        newCharacterTemplate,&lt;br /&gt;
        battle,&lt;br /&gt;
        true&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  newCharacterTemplate.addEventListener(&amp;quot;keydown&amp;quot;, function (event) {&lt;br /&gt;
    if (event.keyCode === 13) {&lt;br /&gt;
      event.target.click();&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  return [newCharacterTemplate, spanInput];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function validPseudo(pseudo, defaultPseudo) {&lt;br /&gt;
  var newPseudo = pseudoFormat(pseudo);&lt;br /&gt;
&lt;br /&gt;
  if (!newPseudo) {&lt;br /&gt;
    return pseudoFormat(defaultPseudo);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return newPseudo;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addNewCharacter(&lt;br /&gt;
  characters,&lt;br /&gt;
  characterTemplate,&lt;br /&gt;
  charactersContainer,&lt;br /&gt;
  battle,&lt;br /&gt;
  pseudoToDuplicate&lt;br /&gt;
) {&lt;br /&gt;
  function editAndSetCharacterPseudoInput(selectedCharacter, spanInput) {&lt;br /&gt;
    var maxPseudoLength = 20;&lt;br /&gt;
    var defaultPseudo = characters.defaultText.pseudo;&lt;br /&gt;
&lt;br /&gt;
    var selection = window.getSelection();&lt;br /&gt;
    var range = document.createRange();&lt;br /&gt;
&lt;br /&gt;
    if (pseudoToDuplicate) {&lt;br /&gt;
      spanInput.textContent = pseudoToDuplicate;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    spanInput.contentEditable = true;&lt;br /&gt;
    spanInput.focus();&lt;br /&gt;
    range.selectNodeContents(spanInput);&lt;br /&gt;
    selection.removeAllRanges();&lt;br /&gt;
    selection.addRange(range);&lt;br /&gt;
&lt;br /&gt;
    function pseudoValidation() {&lt;br /&gt;
      var characterPseudo = validPseudo(spanInput.textContent, defaultPseudo);&lt;br /&gt;
      var characterDataObject = { name: characterPseudo };&lt;br /&gt;
&lt;br /&gt;
      if (pseudoToDuplicate) {&lt;br /&gt;
        characterDataObject = copyObject(&lt;br /&gt;
          characters.savedCharacters[pseudoToDuplicate]&lt;br /&gt;
        );&lt;br /&gt;
        characterDataObject.name = characterPseudo;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      [characterDataObject, characterPseudo] = addUniquePseudo(&lt;br /&gt;
        characterDataObject,&lt;br /&gt;
        Object.keys(characters.savedCharacters)&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      selection.removeAllRanges();&lt;br /&gt;
      spanInput.contentEditable = false;&lt;br /&gt;
      spanInput.textContent = characterPseudo;&lt;br /&gt;
      spanInput.setAttribute(&amp;quot;data-name&amp;quot;, characterPseudo);&lt;br /&gt;
&lt;br /&gt;
      updateForm(&lt;br /&gt;
        characterDataObject,&lt;br /&gt;
        characters.characterCreation,&lt;br /&gt;
        characters,&lt;br /&gt;
        selectedCharacter,&lt;br /&gt;
        battle&lt;br /&gt;
      );&lt;br /&gt;
      saveCharacter(&lt;br /&gt;
        characters.savedCharacters,&lt;br /&gt;
        characters.characterCreation,&lt;br /&gt;
        battle,&lt;br /&gt;
        true&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handleMaxLength(event) {&lt;br /&gt;
      if (spanInput.textContent.length &amp;gt; maxPseudoLength) {&lt;br /&gt;
        spanInput.textContent = spanInput.textContent.slice(0, maxPseudoLength);&lt;br /&gt;
        range.setStart(spanInput.childNodes[0], maxPseudoLength);&lt;br /&gt;
        selection.removeAllRanges();&lt;br /&gt;
        selection.addRange(range);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handleBlur() {&lt;br /&gt;
      spanInput.removeEventListener(&amp;quot;blur&amp;quot;, handleBlur);&lt;br /&gt;
      spanInput.removeEventListener(&amp;quot;input&amp;quot;, handleMaxLength);&lt;br /&gt;
      pseudoValidation();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handleKeyDown(event) {&lt;br /&gt;
      if (event.key === &amp;quot;Enter&amp;quot;) {&lt;br /&gt;
        event.preventDefault();&lt;br /&gt;
&lt;br /&gt;
        spanInput.removeEventListener(&amp;quot;keydown&amp;quot;, handleKeyDown);&lt;br /&gt;
        spanInput.removeEventListener(&amp;quot;blur&amp;quot;, handleBlur);&lt;br /&gt;
        spanInput.removeEventListener(&amp;quot;input&amp;quot;, handleMaxLength);&lt;br /&gt;
&lt;br /&gt;
        pseudoValidation();&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    spanInput.addEventListener(&amp;quot;input&amp;quot;, handleMaxLength);&lt;br /&gt;
    spanInput.addEventListener(&amp;quot;keydown&amp;quot;, handleKeyDown);&lt;br /&gt;
    spanInput.addEventListener(&amp;quot;blur&amp;quot;, handleBlur);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  hideElement(characters.characterCreation);&lt;br /&gt;
  var [selectedCharacter, spanInput] = handleNewCharacter(&lt;br /&gt;
    characters,&lt;br /&gt;
    characterTemplate,&lt;br /&gt;
    charactersContainer,&lt;br /&gt;
    battle&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  editAndSetCharacterPseudoInput(selectedCharacter, spanInput);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleFocus() {&lt;br /&gt;
  var tooltipLinks = document.querySelectorAll(&amp;quot;div.tooltip a&amp;quot;);&lt;br /&gt;
  tooltipLinks.forEach(function (link) {&lt;br /&gt;
    link.setAttribute(&amp;quot;tabindex&amp;quot;, -1);&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function resetBonusVariation(bonusVariation) {&lt;br /&gt;
  function resetInput(input) {&lt;br /&gt;
    input.removeAttribute(&amp;quot;min&amp;quot;);&lt;br /&gt;
    input.removeAttribute(&amp;quot;max&amp;quot;);&lt;br /&gt;
    input.defaultValue = 0;&lt;br /&gt;
    input.value = input.defaultValue;&lt;br /&gt;
  }&lt;br /&gt;
  var { minValue, maxValue, checkbox, container, disabledText, selectedText } =&lt;br /&gt;
    bonusVariation;&lt;br /&gt;
&lt;br /&gt;
  resetInput(minValue);&lt;br /&gt;
  resetInput(maxValue);&lt;br /&gt;
  showElement(disabledText);&lt;br /&gt;
  hideElement(selectedText);&lt;br /&gt;
  hideElement(container);&lt;br /&gt;
  checkbox.checked = false;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleBonusVariationUpdate(&lt;br /&gt;
  characterCreation,&lt;br /&gt;
  bonusVariation,&lt;br /&gt;
  resetSkill&lt;br /&gt;
) {&lt;br /&gt;
  var selectedBonus = characterCreation.bonusVariation.value;&lt;br /&gt;
  var displayName = characterCreation.bonusVariationName.value;&lt;br /&gt;
&lt;br /&gt;
  if (&lt;br /&gt;
    resetSkill &amp;amp;&amp;amp;&lt;br /&gt;
    (selectedBonus.startsWith(&amp;quot;attackSkill&amp;quot;) ||&lt;br /&gt;
      selectedBonus.startsWith(&amp;quot;horseSkill&amp;quot;) ||&lt;br /&gt;
      selectedBonus.startsWith(&amp;quot;skillBonus&amp;quot;))&lt;br /&gt;
  ) {&lt;br /&gt;
    resetBonusVariation(bonusVariation);&lt;br /&gt;
    return;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (&lt;br /&gt;
    characterCreation.hasOwnProperty(selectedBonus) &amp;amp;&amp;amp;&lt;br /&gt;
    selectedBonus != 0 &amp;amp;&amp;amp;&lt;br /&gt;
    displayName != 0&lt;br /&gt;
  ) {&lt;br /&gt;
    handleBonusVariation(&lt;br /&gt;
      characterCreation[selectedBonus],&lt;br /&gt;
      bonusVariation,&lt;br /&gt;
      displayName&lt;br /&gt;
    );&lt;br /&gt;
  } else {&lt;br /&gt;
    resetBonusVariation(bonusVariation);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getTargetContent(targetParent, targetName, isSkill) {&lt;br /&gt;
  var targetContent = &amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  if (targetParent.children.length &amp;lt;= 1) {&lt;br /&gt;
    targetContent = targetParent.textContent;&lt;br /&gt;
  } else if (targetName === &amp;quot;weaponUpgrade&amp;quot;) {&lt;br /&gt;
    targetContent = targetParent.children[1].textContent;&lt;br /&gt;
  } else if (targetName === &amp;quot;level&amp;quot;) {&lt;br /&gt;
    targetContent = targetParent.textContent.replace(&amp;quot;Lv&amp;quot;, &amp;quot;&amp;quot;).trim();&lt;br /&gt;
  } else if (isSkill) {&lt;br /&gt;
    var container = targetParent.children[1];&lt;br /&gt;
&lt;br /&gt;
    for (var index = 0; index &amp;lt; container.children.length; index++) {&lt;br /&gt;
      var element = container.children[index];&lt;br /&gt;
&lt;br /&gt;
      if (element.checkVisibility()) {&lt;br /&gt;
        targetContent += element.textContent;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    for (var index = 1; index &amp;lt; targetParent.children.length; index++) {&lt;br /&gt;
      var element = targetParent.children[index];&lt;br /&gt;
&lt;br /&gt;
      if (element.checkVisibility()) {&lt;br /&gt;
        targetContent += element.textContent;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return targetContent.trim();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleBonusVariation(target, bonusVariation, displayName) {&lt;br /&gt;
  var {&lt;br /&gt;
    minValue,&lt;br /&gt;
    maxValue,&lt;br /&gt;
    checkbox,&lt;br /&gt;
    container,&lt;br /&gt;
    disabledText,&lt;br /&gt;
    selectedText,&lt;br /&gt;
    displaySpan,&lt;br /&gt;
  } = bonusVariation;&lt;br /&gt;
&lt;br /&gt;
  var {&lt;br /&gt;
    min: targetMin,&lt;br /&gt;
    max: targetMax,&lt;br /&gt;
    name: targetName,&lt;br /&gt;
    value: targetValue,&lt;br /&gt;
    parentElement: targetParent,&lt;br /&gt;
    tagName,&lt;br /&gt;
  } = target;&lt;br /&gt;
&lt;br /&gt;
  targetMin = Number(targetMin);&lt;br /&gt;
  targetMax = Number(targetMax);&lt;br /&gt;
  targetValue = Number(targetValue);&lt;br /&gt;
&lt;br /&gt;
  var isSkill = tagName === &amp;quot;SELECT&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  if (isSkill) {&lt;br /&gt;
    var options = target.options;&lt;br /&gt;
&lt;br /&gt;
    targetMin = options[0].value;&lt;br /&gt;
    targetMax = options[options.length - 1].value;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  minValue.min = targetMin;&lt;br /&gt;
  minValue.max = targetMax;&lt;br /&gt;
  minValue.defaultValue = targetMin;&lt;br /&gt;
&lt;br /&gt;
  maxValue.min = targetMin;&lt;br /&gt;
  maxValue.max = targetMax;&lt;br /&gt;
  maxValue.defaultValue = targetMin;&lt;br /&gt;
&lt;br /&gt;
  hideElement(disabledText);&lt;br /&gt;
  showElement(selectedText);&lt;br /&gt;
&lt;br /&gt;
  if (displayName) {&lt;br /&gt;
    minValue.value = Math.min(Math.max(minValue.value, targetMin), targetMax);&lt;br /&gt;
    maxValue.value = Math.max(Math.min(maxValue.value, targetMax), targetMin);&lt;br /&gt;
&lt;br /&gt;
    displaySpan.textContent = displayName;&lt;br /&gt;
  } else {&lt;br /&gt;
    var { input, inputName, tabButton } = bonusVariation;&lt;br /&gt;
    var targetContent = getTargetContent(targetParent, targetName, isSkill);&lt;br /&gt;
&lt;br /&gt;
    input.value = targetName;&lt;br /&gt;
    inputName.value = targetContent;&lt;br /&gt;
    displaySpan.textContent = targetContent;&lt;br /&gt;
&lt;br /&gt;
    minValue.value = Math.max(targetValue - 10, targetMin);&lt;br /&gt;
    maxValue.value = Math.min(targetValue + 10, targetMax);&lt;br /&gt;
&lt;br /&gt;
    showElement(container);&lt;br /&gt;
    checkbox.checked = true;&lt;br /&gt;
&lt;br /&gt;
    tabButton.click();&lt;br /&gt;
    tabButton.scrollIntoView(true);&lt;br /&gt;
&lt;br /&gt;
    input.dispatchEvent(newChangeEvent());&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function characterManagement(characters, battle) {&lt;br /&gt;
  var {&lt;br /&gt;
    newCharacterTemplate: characterTemplate,&lt;br /&gt;
    charactersContainer,&lt;br /&gt;
    addNewCharacterButton,&lt;br /&gt;
    saveButton,&lt;br /&gt;
    characterCreation,&lt;br /&gt;
    bonusVariation,&lt;br /&gt;
    defaultText: { unsavedWarning },&lt;br /&gt;
  } = characters;&lt;br /&gt;
&lt;br /&gt;
  Object.keys(characters.savedCharacters).forEach(function (pseudo) {&lt;br /&gt;
    handleNewCharacter(&lt;br /&gt;
      characters,&lt;br /&gt;
      characterTemplate,&lt;br /&gt;
      charactersContainer,&lt;br /&gt;
      battle,&lt;br /&gt;
      pseudo&lt;br /&gt;
    );&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  addNewCharacterButton.addEventListener(&amp;quot;click&amp;quot;, function (event) {&lt;br /&gt;
    if (!characters.unsavedChanges) {&lt;br /&gt;
      addNewCharacter(&lt;br /&gt;
        characters,&lt;br /&gt;
        characterTemplate,&lt;br /&gt;
        charactersContainer,&lt;br /&gt;
        battle&lt;br /&gt;
      );&lt;br /&gt;
    } else {&lt;br /&gt;
      var result = confirm(unsavedWarning);&lt;br /&gt;
&lt;br /&gt;
      if (result) {&lt;br /&gt;
        addNewCharacter(&lt;br /&gt;
          characters,&lt;br /&gt;
          characterTemplate,&lt;br /&gt;
          charactersContainer,&lt;br /&gt;
          battle&lt;br /&gt;
        );&lt;br /&gt;
        saveButtonGreen(saveButton);&lt;br /&gt;
        characters.unsavedChanges = false;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  handleUploadCharacter(&lt;br /&gt;
    characters,&lt;br /&gt;
    characterTemplate,&lt;br /&gt;
    charactersContainer,&lt;br /&gt;
    battle&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  function handleLongPress(target) {&lt;br /&gt;
    if (target.tagName !== &amp;quot;INPUT&amp;quot; &amp;amp;&amp;amp; target.tagName !== &amp;quot;SELECT&amp;quot;) {&lt;br /&gt;
      target = target.querySelector(&amp;quot;input&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      !target ||&lt;br /&gt;
      (target.type !== &amp;quot;number&amp;quot; &amp;amp;&amp;amp;&lt;br /&gt;
        !target.classList.contains(&amp;quot;skill-select&amp;quot;) &amp;amp;&amp;amp;&lt;br /&gt;
        target.name !== &amp;quot;weaponUpgrade&amp;quot;) ||&lt;br /&gt;
      target.classList.contains(&amp;quot;disabled-variation&amp;quot;)&lt;br /&gt;
    ) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    handleBonusVariation(target, bonusVariation, null);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;click&amp;quot;, function (event) {&lt;br /&gt;
    if (event.shiftKey || event.ctrlKey) {&lt;br /&gt;
      handleLongPress(event.target);&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  var longPressTimer;&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;touchstart&amp;quot;, function (event) {&lt;br /&gt;
    longPressTimer = setTimeout(function () {&lt;br /&gt;
      handleLongPress(event.target);&lt;br /&gt;
    }, 800);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;touchend&amp;quot;, function () {&lt;br /&gt;
    clearTimeout(longPressTimer);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;touchmove&amp;quot;, function () {&lt;br /&gt;
    clearTimeout(longPressTimer);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  filterForm(characters, battle);&lt;br /&gt;
  characterCreationListener(characters, battle);&lt;br /&gt;
  handleFocus();&lt;br /&gt;
&lt;br /&gt;
  window.addEventListener(&amp;quot;beforeunload&amp;quot;, function (event) {&lt;br /&gt;
    if (characters.unsavedChanges) {&lt;br /&gt;
      event.preventDefault();&lt;br /&gt;
      return &amp;quot;&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addMonsterElement(characters, battle, monsterVnum, iframeInfo) {&lt;br /&gt;
  var { monsterTemplate, monstersContainer } = characters;&lt;br /&gt;
  var monsterElement = monsterTemplate.cloneNode(true);&lt;br /&gt;
  var spanInput = monsterElement.querySelector(&amp;quot;span.input&amp;quot;);&lt;br /&gt;
  var deleteSvg = monsterElement.querySelector(&amp;quot;svg&amp;quot;);&lt;br /&gt;
  var monsterName = getMonsterName(monsterVnum);&lt;br /&gt;
  var displayName = characters.translateMonsters&lt;br /&gt;
    ? getTranslatedMonsterName(monsterVnum)&lt;br /&gt;
    : monsterName;&lt;br /&gt;
  var link = createWikiLink(monsterName, displayName);&lt;br /&gt;
&lt;br /&gt;
  monsterElement.setAttribute(&amp;quot;tabindex&amp;quot;, &amp;quot;0&amp;quot;);&lt;br /&gt;
  spanInput.appendChild(link);&lt;br /&gt;
  monstersContainer.appendChild(monsterElement);&lt;br /&gt;
  characters.monsterElements[monsterVnum] = monsterElement;&lt;br /&gt;
&lt;br /&gt;
  deleteSvg.addEventListener(&amp;quot;click&amp;quot;, function () {&lt;br /&gt;
    var monster = characters.savedMonsters[monsterVnum];&lt;br /&gt;
    iframeInfo[monster.category].shouldBeUpdated = true;&lt;br /&gt;
&lt;br /&gt;
    deleteMonster(characters, battle, monsterVnum);&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addNewMonster(&lt;br /&gt;
  characters,&lt;br /&gt;
  battle,&lt;br /&gt;
  monsterVnum,&lt;br /&gt;
  monsterImage,&lt;br /&gt;
  iframeInfo,&lt;br /&gt;
  category&lt;br /&gt;
) {&lt;br /&gt;
  if (isValueInArray(monsterVnum, Object.keys(characters.savedMonsters)))&lt;br /&gt;
    return;&lt;br /&gt;
&lt;br /&gt;
  var newMonster = {&lt;br /&gt;
    image: monsterImage,&lt;br /&gt;
    category: category,&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  characters.savedMonsters[monsterVnum] = newMonster;&lt;br /&gt;
&lt;br /&gt;
  addMonsterElement(characters, battle, monsterVnum, iframeInfo);&lt;br /&gt;
  updateSavedMonsters(characters.savedMonsters);&lt;br /&gt;
  addBattleChoice(battle.battleChoice, monsterVnum, newMonster, true);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function translateiFrame(iframeDoc) {&lt;br /&gt;
  const filterName = iframeDoc.getElementById(&amp;quot;filter-name&amp;quot;);&lt;br /&gt;
  const { general, special } = translation;&lt;br /&gt;
  const translatedPlaceholder = special.placeholder;&lt;br /&gt;
&lt;br /&gt;
  if (filterName &amp;amp;&amp;amp; translatedPlaceholder) {&lt;br /&gt;
    filterName.placeholder = translatedPlaceholder;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (const element of iframeDoc.querySelectorAll(&amp;quot;[data-t]&amp;quot;)) {&lt;br /&gt;
    const translateText = general[element.dataset.t];&lt;br /&gt;
&lt;br /&gt;
    if (translateText) {&lt;br /&gt;
      element.textContent = translateText;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function translateMonsterCard(card, cardNameElement, monsterVnum) {&lt;br /&gt;
  const mapping = translation.mapping;&lt;br /&gt;
  const levelElement = card.querySelector(&amp;quot;[data-level]&amp;quot;);&lt;br /&gt;
  const typeElement = card.querySelector(&amp;quot;[data-type] a&amp;quot;);&lt;br /&gt;
  const damageElements = card.querySelectorAll(&amp;quot;[data-damage] a&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  cardNameElement.textContent = getTranslatedMonsterName(monsterVnum);&lt;br /&gt;
&lt;br /&gt;
  levelElement.textContent = levelElement.textContent.replace(&lt;br /&gt;
    &amp;quot;Boss&amp;quot;,&lt;br /&gt;
    translation.special.boss&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  if (typeElement) {&lt;br /&gt;
    typeElement.textContent = mapping[typeElement.textContent];&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  damageElements.forEach((damageElement) =&amp;gt; {&lt;br /&gt;
    damageElement.textContent = mapping[damageElement.textContent];&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addButtonsToCardsAndTranslate(&lt;br /&gt;
  characters,&lt;br /&gt;
  iframeDoc,&lt;br /&gt;
  iframeInfo,&lt;br /&gt;
  category&lt;br /&gt;
) {&lt;br /&gt;
  const buttonTemplates = characters.monsterButtonTemplates.children[0];&lt;br /&gt;
  const cardToEdit = iframeDoc.getElementById(&amp;quot;cards-container&amp;quot;).children;&lt;br /&gt;
  const { nameToVnum } = iframeInfo;&lt;br /&gt;
  const vnumToButtons = iframeInfo[category].vnumToButtons;&lt;br /&gt;
  const translateMonsters = characters.translateMonsters;&lt;br /&gt;
&lt;br /&gt;
  for (let cardIndex = 0; cardIndex &amp;lt; cardToEdit.length; cardIndex++) {&lt;br /&gt;
    const card = cardToEdit[cardIndex];&lt;br /&gt;
    const cardNameElement = card.querySelector(&amp;quot;[data-name]&amp;quot;).firstChild;&lt;br /&gt;
    const buttonTemplatesClone = buttonTemplates.cloneNode(true);&lt;br /&gt;
    const cardName = cardNameElement.title.replace(/\s/g, &amp;quot; &amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (!nameToVnum.hasOwnProperty(cardName)) {&lt;br /&gt;
      hideElement(card);&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    const monsterVnum = nameToVnum[cardName];&lt;br /&gt;
&lt;br /&gt;
    buttonTemplatesClone.dataset.monsterId = monsterVnum;&lt;br /&gt;
    card.lastElementChild.appendChild(buttonTemplatesClone);&lt;br /&gt;
    vnumToButtons[monsterVnum] = buttonTemplatesClone.children;&lt;br /&gt;
&lt;br /&gt;
    if (translateMonsters) {&lt;br /&gt;
      translateMonsterCard(card, cardNameElement, monsterVnum);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (translateMonsters) {&lt;br /&gt;
    translateiFrame(iframeDoc);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateiFrameButtons(characters, iframeInfo, category) {&lt;br /&gt;
  var addedMonsters = Object.keys(characters.savedMonsters);&lt;br /&gt;
  var { currentiFrameIsMonster } = iframeInfo;&lt;br /&gt;
  var vnumToButtons = iframeInfo[category].vnumToButtons;&lt;br /&gt;
  var isPolymorphModal = category === &amp;quot;monster&amp;quot; &amp;amp;&amp;amp; !currentiFrameIsMonster;&lt;br /&gt;
&lt;br /&gt;
  for (var monsterVnum in vnumToButtons) {&lt;br /&gt;
    var [addButton, deleteButton, selectButton] = vnumToButtons[monsterVnum];&lt;br /&gt;
&lt;br /&gt;
    if (isPolymorphModal) {&lt;br /&gt;
      hideElement(addButton);&lt;br /&gt;
      hideElement(deleteButton);&lt;br /&gt;
      showElement(selectButton);&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isValueInArray(monsterVnum, addedMonsters)) {&lt;br /&gt;
      hideElement(addButton);&lt;br /&gt;
      showElement(deleteButton);&lt;br /&gt;
      hideElement(selectButton);&lt;br /&gt;
    } else {&lt;br /&gt;
      showElement(addButton);&lt;br /&gt;
      hideElement(deleteButton);&lt;br /&gt;
      hideElement(selectButton);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  iframeInfo.lastiFrameIsMonster = currentiFrameIsMonster;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getMonsterImage(buttonsContainer) {&lt;br /&gt;
  var elder = buttonsContainer.parentElement.firstElementChild;&lt;br /&gt;
  var image = elder.querySelector(&amp;quot;img&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (image) {&lt;br /&gt;
    return image.getAttribute(&amp;quot;src&amp;quot;) || &amp;quot;&amp;quot;;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return &amp;quot;&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleiFrame(iframeInfo, category) {&lt;br /&gt;
  var { characters, battle } = iframeInfo;&lt;br /&gt;
  var iframeInfoCategory = iframeInfo[category];&lt;br /&gt;
  var { iframe, pageName, vnumToButtons } = iframeInfoCategory;&lt;br /&gt;
  var loadingAnimation = iframeInfoCategory.iframe.previousElementSibling;&lt;br /&gt;
&lt;br /&gt;
  iframe.src = mw.util.getUrl(pageName);&lt;br /&gt;
&lt;br /&gt;
  window.addEventListener(&amp;quot;message&amp;quot;, function (event) {&lt;br /&gt;
    if (&lt;br /&gt;
      event.origin !== window.origin ||&lt;br /&gt;
      event.data?.type !== &amp;quot;filterReady&amp;quot; ||&lt;br /&gt;
      event.data.category !== category&lt;br /&gt;
    ) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
    var iframeDoc = this.contentDocument || this.contentWindow.document;&lt;br /&gt;
    var htmlElement = iframeDoc.documentElement;&lt;br /&gt;
    var iframeBody = iframeDoc.body;&lt;br /&gt;
    var content = iframeDoc.getElementById(&amp;quot;show-after-loading&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    htmlElement.setAttribute(&amp;quot;lang&amp;quot;, characters.currentLanguage);&lt;br /&gt;
    iframeBody.firstElementChild.replaceWith(content);&lt;br /&gt;
&lt;br /&gt;
    iframeBody.style.background = &amp;quot;transparent&amp;quot;;&lt;br /&gt;
    iframeBody.style.paddingRight = &amp;quot;10px&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    addButtonsToCardsAndTranslate(characters, iframeDoc, iframeInfo, category);&lt;br /&gt;
    updateiFrameButtons(characters, iframeInfo, category);&lt;br /&gt;
&lt;br /&gt;
    iframeInfoCategory.loadIsFinished = true;&lt;br /&gt;
&lt;br /&gt;
    hideElement(loadingAnimation);&lt;br /&gt;
    showElement(iframe);&lt;br /&gt;
&lt;br /&gt;
    iframeDoc.addEventListener(&amp;quot;click&amp;quot;, handleButtonClick);&lt;br /&gt;
&lt;br /&gt;
    function handleButtonClick(event) {&lt;br /&gt;
      var target = event.target;&lt;br /&gt;
      var link = target.closest(&amp;quot;a&amp;quot;);&lt;br /&gt;
      var buttonsContainer = target.closest(&amp;quot;.handle-monster&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
      if (link) {&lt;br /&gt;
        event.preventDefault();&lt;br /&gt;
        window.open(link.href, &amp;quot;_blank&amp;quot;);&lt;br /&gt;
      } else if (buttonsContainer) {&lt;br /&gt;
        var { monsterId: monsterVnum } = buttonsContainer.dataset;&lt;br /&gt;
&lt;br /&gt;
        // polymorph iframe&lt;br /&gt;
        if (category === &amp;quot;monster&amp;quot; &amp;amp;&amp;amp; !iframeInfo.currentiFrameIsMonster) {&lt;br /&gt;
          var monsterImage = getMonsterImage(buttonsContainer);&lt;br /&gt;
          changePolymorphValues(&lt;br /&gt;
            characters.characterCreation,&lt;br /&gt;
            monsterVnum,&lt;br /&gt;
            monsterImage&lt;br /&gt;
          );&lt;br /&gt;
          handlePolymorphDisplay(characters, monsterVnum, monsterImage);&lt;br /&gt;
          iframe.dispatchEvent(newChangeEvent());&lt;br /&gt;
        } else {&lt;br /&gt;
          var addedMonsters = Object.keys(characters.savedMonsters);&lt;br /&gt;
          var [addButton, deleteButton] = vnumToButtons[monsterVnum];&lt;br /&gt;
&lt;br /&gt;
          if (isValueInArray(monsterVnum, addedMonsters)) {&lt;br /&gt;
            deleteMonster(characters, battle, monsterVnum);&lt;br /&gt;
            showElement(addButton);&lt;br /&gt;
            hideElement(deleteButton);&lt;br /&gt;
          } else {&lt;br /&gt;
            var monsterImage = getMonsterImage(buttonsContainer);&lt;br /&gt;
            addNewMonster(&lt;br /&gt;
              characters,&lt;br /&gt;
              battle,&lt;br /&gt;
              monsterVnum,&lt;br /&gt;
              monsterImage,&lt;br /&gt;
              iframeInfo,&lt;br /&gt;
              category&lt;br /&gt;
            );&lt;br /&gt;
            hideElement(addButton);&lt;br /&gt;
            showElement(deleteButton);&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getNameToVnumMapping() {&lt;br /&gt;
  var nameToVnum = {};&lt;br /&gt;
&lt;br /&gt;
  for (var monsterVnum in monsterData) {&lt;br /&gt;
    nameToVnum[monsterData[monsterVnum][monsterData[monsterVnum].length - 1]] =&lt;br /&gt;
      monsterVnum;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return nameToVnum;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function monsterManagement(characters, battle) {&lt;br /&gt;
  var { monsteriFrame, stoneiFrame } = characters;&lt;br /&gt;
  var monsterVnums = Object.keys(monsterData);&lt;br /&gt;
&lt;br /&gt;
  var iframeInfo = {&lt;br /&gt;
    lastiFrameIsMonster: false,&lt;br /&gt;
    currentiFrameIsMonster: false,&lt;br /&gt;
    characters: characters,&lt;br /&gt;
    battle: battle,&lt;br /&gt;
    nameToVnum: getNameToVnumMapping(),&lt;br /&gt;
    monster: {&lt;br /&gt;
      isLoaded: false,&lt;br /&gt;
      loadIsFinished: false,&lt;br /&gt;
      shouldBeUpdated: false,&lt;br /&gt;
      vnumToButtons: {},&lt;br /&gt;
      pageName: &amp;quot;Monstres&amp;quot;,&lt;br /&gt;
      iframe: monsteriFrame,&lt;br /&gt;
    },&lt;br /&gt;
    stone: {&lt;br /&gt;
      isLoaded: false,&lt;br /&gt;
      loadIsFinished: false,&lt;br /&gt;
      shouldBeUpdated: false,&lt;br /&gt;
      vnumToButtons: {},&lt;br /&gt;
      pageName: &amp;quot;Pierres Metin&amp;quot;,&lt;br /&gt;
      iframe: stoneiFrame,&lt;br /&gt;
    },&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  document.addEventListener(&amp;quot;modalOpen&amp;quot;, function (event) {&lt;br /&gt;
    var modalName = event.detail.name;&lt;br /&gt;
&lt;br /&gt;
    if (modalName === &amp;quot;monster&amp;quot; || modalName === &amp;quot;stone&amp;quot;) {&lt;br /&gt;
      handleModal(event.target, modalName);&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  function handleModal(target, modalName) {&lt;br /&gt;
    var iframeInfoCategory = iframeInfo[modalName];&lt;br /&gt;
&lt;br /&gt;
    if (modalName === &amp;quot;monster&amp;quot;) {&lt;br /&gt;
      var isMonsteriFrame = target.id === &amp;quot;add-new-monster&amp;quot;;&lt;br /&gt;
      iframeInfo.currentiFrameIsMonster = isMonsteriFrame;&lt;br /&gt;
&lt;br /&gt;
      if (&lt;br /&gt;
        iframeInfoCategory.loadIsFinished &amp;amp;&amp;amp;&lt;br /&gt;
        ((isMonsteriFrame &amp;amp;&amp;amp; !iframeInfo.lastiFrameIsMonster) ||&lt;br /&gt;
          (!isMonsteriFrame &amp;amp;&amp;amp; iframeInfo.lastiFrameIsMonster))&lt;br /&gt;
      ) {&lt;br /&gt;
        iframeInfoCategory.shouldBeUpdated = true;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!iframeInfoCategory.isLoaded) {&lt;br /&gt;
      handleiFrame(iframeInfo, modalName);&lt;br /&gt;
      iframeInfoCategory.isLoaded = true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      iframeInfoCategory.loadIsFinished &amp;amp;&amp;amp;&lt;br /&gt;
      iframeInfoCategory.shouldBeUpdated&lt;br /&gt;
    ) {&lt;br /&gt;
      updateiFrameButtons(characters, iframeInfo, modalName);&lt;br /&gt;
      iframeInfoCategory.shouldBeUpdated = false;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  Object.keys(characters.savedMonsters)&lt;br /&gt;
    .slice()&lt;br /&gt;
    .forEach(function (monsterVnum) {&lt;br /&gt;
      if (isValueInArray(monsterVnum, monsterVnums)) {&lt;br /&gt;
        addMonsterElement(characters, battle, monsterVnum, iframeInfo);&lt;br /&gt;
      } else {&lt;br /&gt;
        deleteMonster(characters, battle, monsterVnum);&lt;br /&gt;
      }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function hideAttackType(container, input, attackType) {&lt;br /&gt;
  hideElement(container);&lt;br /&gt;
&lt;br /&gt;
  if (input.checked) {&lt;br /&gt;
    var defaultInput = attackType.defaultInput;&lt;br /&gt;
&lt;br /&gt;
    input.checked = false;&lt;br /&gt;
    defaultInput.checked = true;&lt;br /&gt;
    defaultInput.dispatchEvent(newChangeEvent());&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterAttackTypeSelectionCharacter(attacker, attackType) {&lt;br /&gt;
  var attackerClass = attacker.class;&lt;br /&gt;
  var attackerIsNotPolymorph = !isPolymorph(attacker);&lt;br /&gt;
  var { elements: attackTypeElements } = attackType;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; attackTypeElements.length; index++) {&lt;br /&gt;
    var { container, input, inputClass, inputValue } =&lt;br /&gt;
      attackTypeElements[index];&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      attackerIsNotPolymorph &amp;amp;&amp;amp;&lt;br /&gt;
      attacker[inputValue] &amp;amp;&amp;amp;&lt;br /&gt;
      (attackerClass === inputClass ||&lt;br /&gt;
        (inputValue.startsWith(&amp;quot;horseSkill&amp;quot;) &amp;amp;&amp;amp;&lt;br /&gt;
          isRiding(attacker) &amp;amp;&amp;amp;&lt;br /&gt;
          (!inputClass || isValueInArray(attackerClass, inputClass))))&lt;br /&gt;
    ) {&lt;br /&gt;
      showElement(container);&lt;br /&gt;
    } else {&lt;br /&gt;
      hideAttackType(container, input, attackType);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterAttackTypeSelectionMonster(attackType) {&lt;br /&gt;
  var attackTypeElements = attackType.elements;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; attackTypeElements.length; index++) {&lt;br /&gt;
    var { container, input } = attackTypeElements[index];&lt;br /&gt;
    hideAttackType(container, input, attackType);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function removeBattleElement(battleChoice, nameOrVnum, category, type) {&lt;br /&gt;
  var elements = battleChoice[category][type].elements;&lt;br /&gt;
&lt;br /&gt;
  if (elements.hasOwnProperty(nameOrVnum)) {&lt;br /&gt;
    elements[nameOrVnum].container.remove();&lt;br /&gt;
    delete elements[nameOrVnum];&lt;br /&gt;
    battleChoice[category][type].count--;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function removeBattleChoice(battleChoice, nameOrVnum, type) {&lt;br /&gt;
  battleChoice.categories.forEach(function (category) {&lt;br /&gt;
    if (category === &amp;quot;attacker&amp;quot; &amp;amp;&amp;amp; type === &amp;quot;stone&amp;quot;) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
    var selected = battleChoice[category].selected;&lt;br /&gt;
&lt;br /&gt;
    if (selected) {&lt;br /&gt;
      var { type: selectedType, nameOrVnum: selectedNameOrVnum } =&lt;br /&gt;
        parseTypeAndName(selected);&lt;br /&gt;
&lt;br /&gt;
      if (nameOrVnum === selectedNameOrVnum &amp;amp;&amp;amp; type === selectedType) {&lt;br /&gt;
        resetBattleChoiceButton(battleChoice, category);&lt;br /&gt;
        battleChoice[category].selected = null;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    removeBattleElement(battleChoice, nameOrVnum, category, type);&lt;br /&gt;
    updateBattleChoiceText(battleChoice, category, type);&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addBattleElement(&lt;br /&gt;
  battleChoice,&lt;br /&gt;
  pseudoOrVnum,&lt;br /&gt;
  characterOrMonster,&lt;br /&gt;
  category,&lt;br /&gt;
  isMonster&lt;br /&gt;
) {&lt;br /&gt;
  var { template, raceToImage, translateMonsters } = battleChoice;&lt;br /&gt;
  var battleChoiceCategory = battleChoice[category];&lt;br /&gt;
  var templateClone = template.cloneNode(true);&lt;br /&gt;
  var label = templateClone.firstElementChild;&lt;br /&gt;
  var [input, image, span] = label.children;&lt;br /&gt;
  var imageSrc;&lt;br /&gt;
  var name;&lt;br /&gt;
  var type;&lt;br /&gt;
&lt;br /&gt;
  if (isMonster) {&lt;br /&gt;
    type = characterOrMonster.category;&lt;br /&gt;
&lt;br /&gt;
    if (type === &amp;quot;stone&amp;quot; &amp;amp;&amp;amp; category === &amp;quot;attacker&amp;quot;) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
    imageSrc = characterOrMonster.image;&lt;br /&gt;
    name = translateMonsters&lt;br /&gt;
      ? getTranslatedMonsterName(pseudoOrVnum)&lt;br /&gt;
      : getMonsterName(pseudoOrVnum);&lt;br /&gt;
  } else {&lt;br /&gt;
    type = &amp;quot;character&amp;quot;;&lt;br /&gt;
    imageSrc = raceToImage[characterOrMonster.race];&lt;br /&gt;
    name = pseudoOrVnum;&lt;br /&gt;
    label.classList.add(&amp;quot;notranslate&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var value = type + &amp;quot;-&amp;quot; + pseudoOrVnum;&lt;br /&gt;
  var id = category + &amp;quot;-&amp;quot; + value;&lt;br /&gt;
  var currentBattleChoice = battleChoiceCategory[type];&lt;br /&gt;
&lt;br /&gt;
  label.setAttribute(&amp;quot;for&amp;quot;, id);&lt;br /&gt;
  input.value = value;&lt;br /&gt;
  input.id = id;&lt;br /&gt;
  input.name = category;&lt;br /&gt;
  span.textContent = name;&lt;br /&gt;
&lt;br /&gt;
  handleImageFromWiki(image, imageSrc);&lt;br /&gt;
&lt;br /&gt;
  currentBattleChoice.container.appendChild(templateClone);&lt;br /&gt;
  currentBattleChoice.count++;&lt;br /&gt;
  currentBattleChoice.elements[pseudoOrVnum] = {&lt;br /&gt;
    container: templateClone,&lt;br /&gt;
    image: image,&lt;br /&gt;
    name: name,&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  updateBattleChoiceText(battleChoice, category, type);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addBattleChoice(&lt;br /&gt;
  battleChoice,&lt;br /&gt;
  pseudoOrVnum,&lt;br /&gt;
  characterOrMonster,&lt;br /&gt;
  isMonster = false&lt;br /&gt;
) {&lt;br /&gt;
  addBattleElement(&lt;br /&gt;
    battleChoice,&lt;br /&gt;
    pseudoOrVnum,&lt;br /&gt;
    characterOrMonster,&lt;br /&gt;
    &amp;quot;attacker&amp;quot;,&lt;br /&gt;
    isMonster&lt;br /&gt;
  );&lt;br /&gt;
  addBattleElement(&lt;br /&gt;
    battleChoice,&lt;br /&gt;
    pseudoOrVnum,&lt;br /&gt;
    characterOrMonster,&lt;br /&gt;
    &amp;quot;victim&amp;quot;,&lt;br /&gt;
    isMonster&lt;br /&gt;
  );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateBattleChoiceImage(battleChoice, characterName, newRace) {&lt;br /&gt;
  var imageSrc = battleChoice.raceToImage[newRace];&lt;br /&gt;
&lt;br /&gt;
  battleChoice.categories.forEach(function (category) {&lt;br /&gt;
    handleImageFromWiki(&lt;br /&gt;
      battleChoice[category].character.elements[characterName].image,&lt;br /&gt;
      imageSrc&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    var selected = battleChoice[category].selected;&lt;br /&gt;
&lt;br /&gt;
    if (isCharacterSelected(characterName, selected)) {&lt;br /&gt;
      updateBattleChoiceButton(battleChoice, category, selected);&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateBattleChoiceText(battleChoice, category, type) {&lt;br /&gt;
  var { count, container } = battleChoice[category][type];&lt;br /&gt;
  var parentContainer = container.parentElement;&lt;br /&gt;
&lt;br /&gt;
  if (count === 0) {&lt;br /&gt;
    hideElement(parentContainer);&lt;br /&gt;
    showElement(parentContainer.nextElementSibling);&lt;br /&gt;
  } else if (count === 1) {&lt;br /&gt;
    showElement(parentContainer);&lt;br /&gt;
    hideElement(parentContainer.nextElementSibling);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateBattleChoice(characters, battleChoice) {&lt;br /&gt;
  var templateImage = battleChoice.template.querySelector(&amp;quot;img&amp;quot;);&lt;br /&gt;
  var attackerImage = battleChoice.attacker.buttonContent.querySelector(&amp;quot;img&amp;quot;);&lt;br /&gt;
  var victimImage = battleChoice.victim.buttonContent.querySelector(&amp;quot;img&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  resetImageFromWiki(templateImage);&lt;br /&gt;
  resetImageFromWiki(attackerImage);&lt;br /&gt;
  resetImageFromWiki(victimImage);&lt;br /&gt;
&lt;br /&gt;
  for (var [pseudo, character] of Object.entries(characters.savedCharacters)) {&lt;br /&gt;
    addBattleChoice(battleChoice, pseudo, character);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (var [vnum, monster] of Object.entries(characters.savedMonsters)) {&lt;br /&gt;
    addBattleChoice(battleChoice, vnum, monster, true);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateBattleChoiceButton(battleChoice, category, data) {&lt;br /&gt;
  var battleChoiceCategory = battleChoice[category];&lt;br /&gt;
  var { defaultButtonContent, buttonContent } = battleChoiceCategory;&lt;br /&gt;
  var [buttonImage, buttonSpan] = buttonContent.firstElementChild.children;&lt;br /&gt;
  var { type, nameOrVnum } = parseTypeAndName(data);&lt;br /&gt;
  var { name, image } = battleChoiceCategory[type].elements[nameOrVnum];&lt;br /&gt;
&lt;br /&gt;
  hideElement(defaultButtonContent);&lt;br /&gt;
  showElement(buttonContent);&lt;br /&gt;
&lt;br /&gt;
  buttonSpan.textContent = name;&lt;br /&gt;
  buttonImage.src = image.src;&lt;br /&gt;
  battleChoiceCategory.selected = data;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function resetBattleChoiceButton(battleChoice, category) {&lt;br /&gt;
  var { defaultButtonContent, buttonContent } = battleChoice[category];&lt;br /&gt;
&lt;br /&gt;
  showElement(defaultButtonContent);&lt;br /&gt;
  hideElement(buttonContent);&lt;br /&gt;
&lt;br /&gt;
  if (category === &amp;quot;attacker&amp;quot;) {&lt;br /&gt;
    filterAttackTypeSelectionMonster(battleChoice.attackType);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isPC(character) {&lt;br /&gt;
  if (character.race === 0 || character.race === 1) {&lt;br /&gt;
    return false;&lt;br /&gt;
  }&lt;br /&gt;
  return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isBoss(character) {&lt;br /&gt;
  return character.race === 0 &amp;amp;&amp;amp; character.rank &amp;gt;= 5;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isStone(character) {&lt;br /&gt;
  return character.race === 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isMeleeAttacker(monster) {&lt;br /&gt;
  return monster.attack == 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isRangeAttacker(monster) {&lt;br /&gt;
  return monster.attack == 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isMagicAttacker(monster) {&lt;br /&gt;
  return monster.attack == 2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isMagicClass(character) {&lt;br /&gt;
  return character.race === &amp;quot;shaman&amp;quot; || character.class === &amp;quot;black_magic&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isDispell(character, skillId) {&lt;br /&gt;
  return character.class === &amp;quot;weaponary&amp;quot; &amp;amp;&amp;amp; skillId === 6;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isPolymorph(character) {&lt;br /&gt;
  return isChecked(character.isPolymorph);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isRiding(character) {&lt;br /&gt;
  return isChecked(character.isRiding);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isBow(weaponType) {&lt;br /&gt;
  return weaponType === 2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcAttackFactor(attacker, victim) {&lt;br /&gt;
  function calcCoeffK(dex, level) {&lt;br /&gt;
    return Math.min(90, Math.floor((2 * dex + level) / 3));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var K1 = calcCoeffK(attacker.polymorphDex, attacker.level);&lt;br /&gt;
  var K2 = calcCoeffK(victim.polymorphDex, attacker.level);&lt;br /&gt;
&lt;br /&gt;
  var AR = (K1 + 210) / 300;&lt;br /&gt;
  var ER = (((2 * K2 + 5) / (K2 + 95)) * 3) / 10;&lt;br /&gt;
&lt;br /&gt;
  return truncateNumber(AR - ER, 8);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcMainAttackValue(attacker) {&lt;br /&gt;
  var leadership = 0;&lt;br /&gt;
  var weaponGrowth = 0;&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker)) {&lt;br /&gt;
    weaponGrowth = attacker.weapon.growth;&lt;br /&gt;
    leadership = attacker.leadership;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return 2 * (attacker.level + weaponGrowth) + leadership;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcStatAttackValue(character) {&lt;br /&gt;
  switch (character.race) {&lt;br /&gt;
    case &amp;quot;warrior&amp;quot;:&lt;br /&gt;
    case &amp;quot;sura&amp;quot;:&lt;br /&gt;
      return 2 * character.str;&lt;br /&gt;
    case &amp;quot;ninja&amp;quot;:&lt;br /&gt;
      return Math.floor((1 / 4) * (character.str + 7 * character.dex));&lt;br /&gt;
    case &amp;quot;shaman&amp;quot;:&lt;br /&gt;
      return Math.floor((1 / 3) * (5 * character.int + character.dex));&lt;br /&gt;
    case &amp;quot;lycan&amp;quot;:&lt;br /&gt;
      return character.vit + 2 * character.dex;&lt;br /&gt;
    default:&lt;br /&gt;
      return 2 * character.str;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcPvpCriticalAttackRange(minAttackValue, maxAttackValue, growth) {&lt;br /&gt;
  return Array.from(&lt;br /&gt;
    { length: maxAttackValue - minAttackValue + 1 },&lt;br /&gt;
    (_, index) =&amp;gt; (minAttackValue + growth + index) * 2&lt;br /&gt;
  );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcSecondaryAttackValue(attacker, isPlayerVsPlayer) {&lt;br /&gt;
  let attackValueOther = 0;&lt;br /&gt;
&lt;br /&gt;
  let minAttackValue = 0;&lt;br /&gt;
  let maxAttackValue = 0;&lt;br /&gt;
&lt;br /&gt;
  let minAttackValueSlash = 0;&lt;br /&gt;
  let maxAttackValueSlash = 0;&lt;br /&gt;
&lt;br /&gt;
  let type, isSerpent, growth;&lt;br /&gt;
&lt;br /&gt;
  let criticalAttackRange;&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker)) {&lt;br /&gt;
    ({ type, isSerpent, minAttackValue, maxAttackValue, growth } =&lt;br /&gt;
      attacker.weapon);&lt;br /&gt;
&lt;br /&gt;
    if (isSerpent) {&lt;br /&gt;
      minAttackValue = Math.max(0, attacker.minAttackValueRandom - growth);&lt;br /&gt;
      maxAttackValue = Math.max(&lt;br /&gt;
        minAttackValue,&lt;br /&gt;
        attacker.maxAttackValueRandom - growth&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    minAttackValueSlash = Math.min(&lt;br /&gt;
      attacker.minAttackValueSlash,&lt;br /&gt;
      attacker.maxAttackValueSlash&lt;br /&gt;
    );&lt;br /&gt;
    maxAttackValueSlash = Math.max(&lt;br /&gt;
      attacker.minAttackValueSlash,&lt;br /&gt;
      attacker.maxAttackValueSlash&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    attackValueOther += attacker.attackValue;&lt;br /&gt;
&lt;br /&gt;
    if (isBow(type) &amp;amp;&amp;amp; !isPolymorph(attacker)) {&lt;br /&gt;
      attackValueOther += 25;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isPlayerVsPlayer) {&lt;br /&gt;
      criticalAttackRange = calcPvpCriticalAttackRange(&lt;br /&gt;
        minAttackValue,&lt;br /&gt;
        maxAttackValue,&lt;br /&gt;
        growth&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    minAttackValue = attacker.minAttackValue;&lt;br /&gt;
    maxAttackValue = attacker.maxAttackValue;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  minAttackValue += attacker.minAttackValuePolymorph;&lt;br /&gt;
  maxAttackValue += attacker.maxAttackValuePolymorph;&lt;br /&gt;
&lt;br /&gt;
  attackValueOther += attacker.statAttackValue;&lt;br /&gt;
  attackValueOther += attacker.horseAttackValue;&lt;br /&gt;
&lt;br /&gt;
  const weaponInterval = maxAttackValue - minAttackValue + 1;&lt;br /&gt;
  const slashInterval = maxAttackValueSlash - minAttackValueSlash + 1;&lt;br /&gt;
&lt;br /&gt;
  const totalCardinal = weaponInterval * slashInterval * 1_000_000;&lt;br /&gt;
  const minInterval = Math.min(weaponInterval, slashInterval);&lt;br /&gt;
&lt;br /&gt;
  minAttackValue += minAttackValueSlash;&lt;br /&gt;
  maxAttackValue += maxAttackValueSlash;&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    minAttackValue: minAttackValue,&lt;br /&gt;
    maxAttackValue: maxAttackValue,&lt;br /&gt;
    attackValueOther: attackValueOther,&lt;br /&gt;
    totalCardinal: totalCardinal,&lt;br /&gt;
    weights: calcWeights(minAttackValue, maxAttackValue, minInterval),&lt;br /&gt;
    possibleDamageCount: maxAttackValue - minAttackValue + 1,&lt;br /&gt;
    criticalAttackRange: criticalAttackRange,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcMagicAttackValue(attacker, isPlayerVsPlayer) {&lt;br /&gt;
  let minMagicAttackValueSlash = 0;&lt;br /&gt;
  let maxMagicAttackValueSlash = 0;&lt;br /&gt;
&lt;br /&gt;
  let criticalAttackRange;&lt;br /&gt;
&lt;br /&gt;
  let {&lt;br /&gt;
    isSerpent,&lt;br /&gt;
    minMagicAttackValue,&lt;br /&gt;
    maxMagicAttackValue,&lt;br /&gt;
    minAttackValue,&lt;br /&gt;
    maxAttackValue,&lt;br /&gt;
    growth,&lt;br /&gt;
  } = attacker.weapon;&lt;br /&gt;
&lt;br /&gt;
  if (isSerpent) {&lt;br /&gt;
    minMagicAttackValue = Math.max(0, attacker.minMagicAttackValueRandom);&lt;br /&gt;
    maxMagicAttackValue = Math.max(&lt;br /&gt;
      minMagicAttackValue,&lt;br /&gt;
      attacker.maxMagicAttackValueRandom&lt;br /&gt;
    );&lt;br /&gt;
    minAttackValue = Math.max(0, attacker.minAttackValueRandom - growth);&lt;br /&gt;
    maxAttackValue = Math.max(&lt;br /&gt;
      minAttackValue,&lt;br /&gt;
      attacker.maxAttackValueRandom - growth&lt;br /&gt;
    );&lt;br /&gt;
  } else {&lt;br /&gt;
    minMagicAttackValue += growth;&lt;br /&gt;
    maxMagicAttackValue += growth;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (isPlayerVsPlayer) {&lt;br /&gt;
    criticalAttackRange = calcPvpCriticalAttackRange(&lt;br /&gt;
      minAttackValue,&lt;br /&gt;
      maxAttackValue,&lt;br /&gt;
      growth&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  minMagicAttackValueSlash = Math.min(&lt;br /&gt;
    attacker.minMagicAttackValueSlash,&lt;br /&gt;
    attacker.maxMagicAttackValueSlash&lt;br /&gt;
  );&lt;br /&gt;
  maxMagicAttackValueSlash = Math.max(&lt;br /&gt;
    attacker.minMagicAttackValueSlash,&lt;br /&gt;
    attacker.maxMagicAttackValueSlash&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  const weaponInterval = maxMagicAttackValue - minMagicAttackValue + 1;&lt;br /&gt;
  const slashInterval = maxMagicAttackValueSlash - minMagicAttackValueSlash + 1;&lt;br /&gt;
&lt;br /&gt;
  const totalCardinal = weaponInterval * slashInterval * 1_000_000;&lt;br /&gt;
  const minInterval = Math.min(weaponInterval, slashInterval);&lt;br /&gt;
&lt;br /&gt;
  minMagicAttackValue += minMagicAttackValueSlash;&lt;br /&gt;
  maxMagicAttackValue += maxMagicAttackValueSlash;&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    minMagicAttackValue: minMagicAttackValue,&lt;br /&gt;
    maxMagicAttackValue: maxMagicAttackValue,&lt;br /&gt;
    magicAttackValueAugmentation: getMagicAttackValueAugmentation(&lt;br /&gt;
      minMagicAttackValue,&lt;br /&gt;
      maxMagicAttackValue,&lt;br /&gt;
      attacker.magicAttackValue&lt;br /&gt;
    ),&lt;br /&gt;
    totalCardinal: totalCardinal,&lt;br /&gt;
    weights: calcWeights(minMagicAttackValue, maxMagicAttackValue, minInterval),&lt;br /&gt;
    possibleDamageCount: maxMagicAttackValue - minMagicAttackValue + 1,&lt;br /&gt;
    criticalAttackRange: criticalAttackRange,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getPolymorphPower(polymorphPoint, polymorphPowerTable) {&lt;br /&gt;
  return polymorphPowerTable[polymorphPoint];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSkillPower(skillPoint, skillPowerTable) {&lt;br /&gt;
  return skillPowerTable[skillPoint];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getMarriageBonusValue(character, marriageTable, itemName) {&lt;br /&gt;
  let index;&lt;br /&gt;
  const lovePoint = character.lovePoint;&lt;br /&gt;
&lt;br /&gt;
  if (lovePoint &amp;lt; 65) {&lt;br /&gt;
    index = 0;&lt;br /&gt;
  } else if (lovePoint &amp;lt; 80) {&lt;br /&gt;
    index = 1;&lt;br /&gt;
  } else if (lovePoint &amp;lt; 100) {&lt;br /&gt;
    index = 2;&lt;br /&gt;
  } else {&lt;br /&gt;
    index = 3;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return marriageTable[itemName][index];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcDamageWithPrimaryBonuses(damage, bonusValues) {&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.attackValueCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  damage += bonusValues.attackValueMarriage;&lt;br /&gt;
&lt;br /&gt;
  damage = Math.floor(&lt;br /&gt;
    (damage * bonusValues.monsterResistanceMarriageCoeff) / 100&lt;br /&gt;
  );&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.monsterResistanceCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  damage += Math.floor((damage * bonusValues.typeBonusCoeff) / 100);&lt;br /&gt;
  damage +=&lt;br /&gt;
    Math.floor((damage * bonusValues.raceBonusCoeff) / 100) -&lt;br /&gt;
    Math.floor((damage * bonusValues.raceResistanceCoeff) / 100);&lt;br /&gt;
  damage += Math.floor((damage * bonusValues.stoneBonusCoeff) / 100);&lt;br /&gt;
  damage += Math.floor((damage * bonusValues.monsterBonusCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  const elementBonusCoeff = bonusValues.elementBonusCoeff;&lt;br /&gt;
&lt;br /&gt;
  damage +=&lt;br /&gt;
    Math.trunc((damage * elementBonusCoeff[0]) / 10000) +&lt;br /&gt;
    Math.trunc((damage * elementBonusCoeff[1]) / 10000) +&lt;br /&gt;
    Math.trunc((damage * elementBonusCoeff[2]) / 10000) +&lt;br /&gt;
    Math.trunc((damage * elementBonusCoeff[3]) / 10000) +&lt;br /&gt;
    Math.trunc((damage * elementBonusCoeff[4]) / 10000) +&lt;br /&gt;
    Math.trunc((damage * elementBonusCoeff[5]) / 10000);&lt;br /&gt;
&lt;br /&gt;
  damage = Math.floor(damage * bonusValues.damageMultiplier);&lt;br /&gt;
&lt;br /&gt;
  return damage;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcFinalDamage(&lt;br /&gt;
  finalDamage,&lt;br /&gt;
  minPiercingDamage,&lt;br /&gt;
  tempDamage,&lt;br /&gt;
  bonusValues,&lt;br /&gt;
  criticalAttackRange,&lt;br /&gt;
  damageByType&lt;br /&gt;
) {&lt;br /&gt;
  for (let criticalIndex = 0; criticalIndex &amp;lt; 2; criticalIndex++) {&lt;br /&gt;
    if (bonusValues.skipCriticalStep[criticalIndex]) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
    let beforeCriticalDamage = finalDamage;&lt;br /&gt;
    let damageValues = criticalIndex&lt;br /&gt;
      ? criticalAttackRange || [finalDamage]&lt;br /&gt;
      : [0];&lt;br /&gt;
&lt;br /&gt;
    for (let index = 0, len = damageValues.length; index &amp;lt; len; index++) {&lt;br /&gt;
      let afterCriticalDamage = beforeCriticalDamage + damageValues[index];&lt;br /&gt;
&lt;br /&gt;
      for (let piercingIndex = 0; piercingIndex &amp;lt; 2; piercingIndex++) {&lt;br /&gt;
        if (bonusValues.skipPiercingStep[piercingIndex]) {&lt;br /&gt;
          continue;&lt;br /&gt;
        }&lt;br /&gt;
        let damage = afterCriticalDamage;&lt;br /&gt;
&lt;br /&gt;
        if (piercingIndex) {&lt;br /&gt;
          damage += bonusValues.defenseBoost + Math.min(0, minPiercingDamage);&lt;br /&gt;
          damage += Math.floor(&lt;br /&gt;
            (tempDamage * bonusValues.extraPiercingHitCoeff) / 1000&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        damage = Math.floor((damage * bonusValues.averageDamageCoeff) / 100);&lt;br /&gt;
        damage = Math.floor(&lt;br /&gt;
          (damage * bonusValues.averageDamageResistanceCoeff) / 100&lt;br /&gt;
        );&lt;br /&gt;
        damage = Math.floor((damage * bonusValues.skillDamageCoeff) / 100);&lt;br /&gt;
        damage = Math.floor(&lt;br /&gt;
          (damage * bonusValues.skillDamageResistanceCoeff) / 100&lt;br /&gt;
        );&lt;br /&gt;
        damage = Math.floor((damage * bonusValues.rankBonusCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
        if (bonusValues.useDarkProtection) {&lt;br /&gt;
          const { darkProtectionPoint, darkProtectionSp } = bonusValues;&lt;br /&gt;
&lt;br /&gt;
          const damageReduction = Math.floor(damage / 3);&lt;br /&gt;
          const spAbsorption = Math.floor(&lt;br /&gt;
            (damageReduction * darkProtectionPoint) / 100&lt;br /&gt;
          );&lt;br /&gt;
&lt;br /&gt;
          if (spAbsorption &amp;lt;= darkProtectionSp) {&lt;br /&gt;
            damage -= damageReduction;&lt;br /&gt;
          } else {&lt;br /&gt;
            damage -= Math.floor(&lt;br /&gt;
              (darkProtectionSp * 100) / darkProtectionPoint&lt;br /&gt;
            );&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        damage = Math.max(0, damage + bonusValues.defensePercent);&lt;br /&gt;
        damage += Math.min(&lt;br /&gt;
          300,&lt;br /&gt;
          Math.floor((damage * bonusValues.damageBonusCoeff) / 100)&lt;br /&gt;
        );&lt;br /&gt;
        damage = Math.floor((damage * bonusValues.empireMalusCoeff) / 10);&lt;br /&gt;
        damage = Math.floor((damage * bonusValues.sungMaStrBonusCoeff) / 10000);&lt;br /&gt;
        damage -= Math.floor(damage * bonusValues.sungmaStrMalusCoeff);&lt;br /&gt;
&lt;br /&gt;
        damage = Math.floor(&lt;br /&gt;
          (damage * bonusValues.whiteDragonElixirCoeff) / 100&lt;br /&gt;
        );&lt;br /&gt;
        damage = Math.floor(&lt;br /&gt;
          (damage * bonusValues.steelDragonElixirCoeff) / 100&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        damageByType[criticalIndex + 2 * piercingIndex].push(damage);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveFinalDamage(&lt;br /&gt;
  damage,&lt;br /&gt;
  minPiercingDamage,&lt;br /&gt;
  damageWithPrimaryBonuses,&lt;br /&gt;
  bonusValues,&lt;br /&gt;
  criticalAttackRange,&lt;br /&gt;
  damageByType&lt;br /&gt;
) {&lt;br /&gt;
  damage = Math.floor(damage * bonusValues.magicResistanceCoeff);&lt;br /&gt;
  damage = Math.trunc((damage * bonusValues.weaponDefenseCoeff) / 100);&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.tigerStrengthCoeff) / 100);&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.berserkBonusCoeff) / 100);&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.fearBonusCoeff) / 100);&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.blessingBonusCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  calcFinalDamage(&lt;br /&gt;
    damage,&lt;br /&gt;
    minPiercingDamage,&lt;br /&gt;
    damageWithPrimaryBonuses,&lt;br /&gt;
    bonusValues,&lt;br /&gt;
    criticalAttackRange,&lt;br /&gt;
    damageByType&lt;br /&gt;
  );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveFinalSkillDamage(&lt;br /&gt;
  damage,&lt;br /&gt;
  minPiercingDamage,&lt;br /&gt;
  bonusValues,&lt;br /&gt;
  criticalAttackRange,&lt;br /&gt;
  damageByType&lt;br /&gt;
) {&lt;br /&gt;
  damage = Math.floor(damage * bonusValues.magicResistanceCoeff);&lt;br /&gt;
  damage = Math.trunc((damage * bonusValues.weaponDefenseCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  damage -= bonusValues.defense;&lt;br /&gt;
&lt;br /&gt;
  damage = floorMultiplication(damage, bonusValues.skillWardCoeff);&lt;br /&gt;
  damage = floorMultiplication(damage, bonusValues.skillBonusCoeff);&lt;br /&gt;
&lt;br /&gt;
  const tempDamage = Math.floor(&lt;br /&gt;
    (damage * bonusValues.skillBonusByBonusCoeff) / 100&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  damage = Math.floor(&lt;br /&gt;
    (tempDamage * bonusValues.magicAttackValueCoeff) / 100 + 0.5&lt;br /&gt;
  );&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.tigerStrengthCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  calcFinalDamage(&lt;br /&gt;
    damage,&lt;br /&gt;
    minPiercingDamage,&lt;br /&gt;
    tempDamage,&lt;br /&gt;
    bonusValues,&lt;br /&gt;
    criticalAttackRange,&lt;br /&gt;
    damageByType&lt;br /&gt;
  );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function computePolymorphPoint(attacker, victim, polymorphPowerTable) {&lt;br /&gt;
  attacker.polymorphDex = attacker.dex;&lt;br /&gt;
  victim.polymorphDex = victim.dex;&lt;br /&gt;
&lt;br /&gt;
  attacker.minAttackValuePolymorph = 0;&lt;br /&gt;
  attacker.maxAttackValuePolymorph = 0;&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker) &amp;amp;&amp;amp; isPolymorph(attacker)) {&lt;br /&gt;
    var polymorphPowerPct =&lt;br /&gt;
      getPolymorphPower(attacker.polymorphPoint, polymorphPowerTable) / 100;&lt;br /&gt;
    var polymorphMonster = createMonster(&lt;br /&gt;
      attacker.polymorphMonster,&lt;br /&gt;
      null,&lt;br /&gt;
      null,&lt;br /&gt;
      true&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    var polymorphStr = floorMultiplication(&lt;br /&gt;
      polymorphPowerPct,&lt;br /&gt;
      polymorphMonster.str&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    attacker.polymorphDex += floorMultiplication(&lt;br /&gt;
      polymorphPowerPct,&lt;br /&gt;
      polymorphMonster.dex&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    attacker.minAttackValuePolymorph = floorMultiplication(&lt;br /&gt;
      polymorphPowerPct,&lt;br /&gt;
      polymorphMonster.minAttackValue&lt;br /&gt;
    );&lt;br /&gt;
    attacker.maxAttackValuePolymorph = floorMultiplication(&lt;br /&gt;
      polymorphPowerPct,&lt;br /&gt;
      polymorphMonster.maxAttackValue&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    if (!attacker.weapon) {&lt;br /&gt;
      attacker.maxAttackValuePolymorph += 1;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    attacker.attackValue = 0;&lt;br /&gt;
&lt;br /&gt;
    if (isMagicClass(attacker)) {&lt;br /&gt;
      attacker.statAttackValue = 2 * (polymorphStr + attacker.int);&lt;br /&gt;
    } else {&lt;br /&gt;
      attacker.statAttackValue = 2 * (polymorphStr + attacker.str);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function computeHorse(attacker) {&lt;br /&gt;
  attacker.horseAttackValue = 0;&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker) &amp;amp;&amp;amp; isRiding(attacker) &amp;amp;&amp;amp; !isPolymorph(attacker)) {&lt;br /&gt;
    var horseConstant = 30;&lt;br /&gt;
&lt;br /&gt;
    if (attacker.class === &amp;quot;weaponary&amp;quot;) {&lt;br /&gt;
      horseConstant = 60;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    attacker.horseAttackValue = floorMultiplication(&lt;br /&gt;
      2 * attacker.level + attacker.statAttackValue,&lt;br /&gt;
      attacker.horsePoint / horseConstant&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getRankBonus(attacker) {&lt;br /&gt;
  if (!isChecked(attacker.lowRank)) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  switch (attacker.rank) {&lt;br /&gt;
    case &amp;quot;aggressive&amp;quot;:&lt;br /&gt;
      return 1;&lt;br /&gt;
    case &amp;quot;fraudulent&amp;quot;:&lt;br /&gt;
      return 2;&lt;br /&gt;
    case &amp;quot;malicious&amp;quot;:&lt;br /&gt;
      return 3;&lt;br /&gt;
    case &amp;quot;cruel&amp;quot;:&lt;br /&gt;
      return 5;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcElementCoeffPvP(elementBonus, mapping, attacker, victim) {&lt;br /&gt;
  var minElementMalus = 0;&lt;br /&gt;
  var maxDifference = 0;&lt;br /&gt;
  var savedElementDifferences = [];&lt;br /&gt;
  var elementBonusIndex = 0;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; elementBonus.length; index++) {&lt;br /&gt;
    if (!attacker[mapping.elementBonus[index]]) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var elementDifference =&lt;br /&gt;
      attacker[mapping.elementBonus[index]] -&lt;br /&gt;
      victim[mapping.elementResistance[index]];&lt;br /&gt;
&lt;br /&gt;
    if (elementDifference &amp;gt;= 0) {&lt;br /&gt;
      elementBonus[elementBonusIndex] = 10 * elementDifference;&lt;br /&gt;
      minElementMalus -= elementDifference;&lt;br /&gt;
      maxDifference = Math.max(maxDifference, elementDifference);&lt;br /&gt;
      elementBonusIndex++;&lt;br /&gt;
    } else {&lt;br /&gt;
      savedElementDifferences.push(elementDifference);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (!savedElementDifferences.length) {&lt;br /&gt;
    return;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  minElementMalus += maxDifference;&lt;br /&gt;
  savedElementDifferences.sort(compareNumbers);&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; savedElementDifferences.length; index++) {&lt;br /&gt;
    var elementDifference = savedElementDifferences[index];&lt;br /&gt;
&lt;br /&gt;
    elementBonus[elementBonusIndex + index] =&lt;br /&gt;
      10 * Math.max(minElementMalus, elementDifference);&lt;br /&gt;
&lt;br /&gt;
    minElementMalus = Math.min(&lt;br /&gt;
      0,&lt;br /&gt;
      Math.max(minElementMalus, minElementMalus - elementDifference)&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcCriticalHitChance(criticalHitPercentage) {&lt;br /&gt;
  if (criticalHitPercentage &amp;lt;= 9) {&lt;br /&gt;
    return Math.floor((criticalHitPercentage + 5) / 5);&lt;br /&gt;
  }&lt;br /&gt;
  return Math.floor((criticalHitPercentage + 5) / 6);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcCriticalSkillChance(criticalHitPercentage) {&lt;br /&gt;
  if (criticalHitPercentage === 0) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  } else if (criticalHitPercentage &amp;lt;= 9) {&lt;br /&gt;
    return Math.floor((criticalHitPercentage + 7) / 3);&lt;br /&gt;
  }&lt;br /&gt;
  return Math.floor((criticalHitPercentage + 5) / 3);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcPiercingSkillChance(piercingHitPercentage) {&lt;br /&gt;
  if (piercingHitPercentage &amp;lt;= 9) {&lt;br /&gt;
    return Math.floor(piercingHitPercentage / 2);&lt;br /&gt;
  }&lt;br /&gt;
  return 5 + Math.floor((piercingHitPercentage - 10) / 4);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function magicResistanceToCoeff(magicResistance) {&lt;br /&gt;
  if (magicResistance) {&lt;br /&gt;
    return 2000 / (6 * magicResistance + 1000) - 1;&lt;br /&gt;
  }&lt;br /&gt;
  return 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createBattleValues(attacker, victim, battle, skillType) {&lt;br /&gt;
  var {&lt;br /&gt;
    mapping,&lt;br /&gt;
    constants: { polymorphPowerTable, skillPowerTable, marriageTable },&lt;br /&gt;
  } = battle;&lt;br /&gt;
  var calcAttackValues;&lt;br /&gt;
&lt;br /&gt;
  var missPercentage = 0;&lt;br /&gt;
  var attackValueMeleeMagic = 0;&lt;br /&gt;
  var attackValueMarriage = 0;&lt;br /&gt;
  var monsterResistanceMarriage = 0;&lt;br /&gt;
  var monsterResistance = 0;&lt;br /&gt;
  var typeBonus = 0;&lt;br /&gt;
  var raceBonus = 0;&lt;br /&gt;
  var raceResistance = 0;&lt;br /&gt;
  var stoneBonus = 0;&lt;br /&gt;
  var monsterBonus = 0;&lt;br /&gt;
  var elementBonus = [0, 0, 0, 0, 0, 0]; // fire, ice, lightning, earth, darkness, wind, order doesn't matter&lt;br /&gt;
  var defenseMarriage = 0;&lt;br /&gt;
  var damageMultiplier = 1;&lt;br /&gt;
  var useDamage = 1;&lt;br /&gt;
  var defense = victim.defense;&lt;br /&gt;
  var defenseBoost = defense;&lt;br /&gt;
  var magicResistance = 0;&lt;br /&gt;
  var weaponDefense = 0;&lt;br /&gt;
  var tigerStrength = 0;&lt;br /&gt;
  var berserkBonus = 0;&lt;br /&gt;
  var blessingBonus = 0;&lt;br /&gt;
  var fearBonus = 0;&lt;br /&gt;
  var magicAttackValueMeleeMagic = 0;&lt;br /&gt;
  var criticalHitPercentage = attacker.criticalHit;&lt;br /&gt;
  var isPlayerVsPlayer = false;&lt;br /&gt;
  var piercingHitPercentage = attacker.piercingHit;&lt;br /&gt;
  var extraPiercingHitPercentage = Math.max(0, piercingHitPercentage - 100);&lt;br /&gt;
  var averageDamage = 0;&lt;br /&gt;
  var averageDamageResistance = 0;&lt;br /&gt;
  var skillDamage = 0;&lt;br /&gt;
  var skillDamageResistance = 0;&lt;br /&gt;
  var rankBonus = 0;&lt;br /&gt;
  var useDarkProtection = false;&lt;br /&gt;
  var darkProtectionPoint = 0;&lt;br /&gt;
  var defensePercent = 0;&lt;br /&gt;
  var damageBonus = 0;&lt;br /&gt;
  var empireMalus = 0;&lt;br /&gt;
  var sungMaStrBonus = 0;&lt;br /&gt;
  var sungmaStrMalus = 0;&lt;br /&gt;
  var whiteDragonElixir = 0;&lt;br /&gt;
  var steelDragonElixir = 0;&lt;br /&gt;
&lt;br /&gt;
  attacker.statAttackValue = calcStatAttackValue(attacker);&lt;br /&gt;
&lt;br /&gt;
  computePolymorphPoint(attacker, victim, polymorphPowerTable);&lt;br /&gt;
  computeHorse(attacker);&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker)) {&lt;br /&gt;
    if (weaponData.hasOwnProperty(attacker.weapon)) {&lt;br /&gt;
      attacker.weapon = createWeapon(attacker.weapon);&lt;br /&gt;
    } else {&lt;br /&gt;
      attacker.weapon = createWeapon(0);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    attacker.weapon.getValues(attacker.weaponUpgrade);&lt;br /&gt;
&lt;br /&gt;
    attackValueMeleeMagic =&lt;br /&gt;
      attacker.attackValuePercent + Math.min(100, attacker.attackMeleeMagic);&lt;br /&gt;
&lt;br /&gt;
    var weaponType = attacker.weapon.type;&lt;br /&gt;
&lt;br /&gt;
    if (skillType &amp;amp;&amp;amp; attacker.class === &amp;quot;archery&amp;quot;) {&lt;br /&gt;
      if (weaponType !== 2) {&lt;br /&gt;
        useDamage = 0;&lt;br /&gt;
        weaponType = 2;&lt;br /&gt;
      }&lt;br /&gt;
      defense = 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var weaponDefenseName = mapping.defenseWeapon[weaponType];&lt;br /&gt;
    var weaponDefenseBreakName = mapping.breakWeapon[weaponType];&lt;br /&gt;
&lt;br /&gt;
    if (victim.hasOwnProperty(weaponDefenseName)) {&lt;br /&gt;
      weaponDefense = victim[weaponDefenseName];&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isChecked(attacker.whiteDragonElixir)) {&lt;br /&gt;
      whiteDragonElixir = 10;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isPC(victim)) {&lt;br /&gt;
      isPlayerVsPlayer = true;&lt;br /&gt;
&lt;br /&gt;
      if (!skillType) {&lt;br /&gt;
        if (weaponType === 2 &amp;amp;&amp;amp; !isPolymorph(attacker)) {&lt;br /&gt;
          missPercentage = victim.arrowBlock;&lt;br /&gt;
        } else {&lt;br /&gt;
          missPercentage = victim.meleeBlock;&lt;br /&gt;
        }&lt;br /&gt;
        missPercentage +=&lt;br /&gt;
          victim.meleeArrowBlock -&lt;br /&gt;
          (missPercentage * victim.meleeArrowBlock) / 100;&lt;br /&gt;
&lt;br /&gt;
        criticalHitPercentage = calcCriticalHitChance(criticalHitPercentage);&lt;br /&gt;
        berserkBonus = calcBerserkBonus(skillPowerTable, victim);&lt;br /&gt;
        blessingBonus = calcBlessingBonus(skillPowerTable, victim);&lt;br /&gt;
        fearBonus = calcFearBonus(skillPowerTable, victim);&lt;br /&gt;
        averageDamageResistance = victim.averageDamageResistance;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      typeBonus = Math.max(1, attacker.humanBonus - victim.humanResistance);&lt;br /&gt;
      raceBonus = attacker[mapping.raceBonus[victim.race]];&lt;br /&gt;
      raceResistance = victim[mapping.raceResistance[attacker.race]];&lt;br /&gt;
&lt;br /&gt;
      calcElementCoeffPvP(elementBonus, mapping, attacker, victim);&lt;br /&gt;
&lt;br /&gt;
      if (weaponType !== 2 &amp;amp;&amp;amp; attacker.hasOwnProperty(weaponDefenseBreakName)) {&lt;br /&gt;
        weaponDefense -= attacker[weaponDefenseBreakName];&lt;br /&gt;
      }&lt;br /&gt;
    } else {&lt;br /&gt;
      if (isChecked(attacker.isMarried)) {&lt;br /&gt;
        if (isChecked(attacker.loveNecklace)) {&lt;br /&gt;
          attackValueMarriage = getMarriageBonusValue(&lt;br /&gt;
            attacker,&lt;br /&gt;
            marriageTable,&lt;br /&gt;
            &amp;quot;loveNecklace&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isChecked(attacker.loveEarrings)) {&lt;br /&gt;
          criticalHitPercentage += getMarriageBonusValue(&lt;br /&gt;
            attacker,&lt;br /&gt;
            marriageTable,&lt;br /&gt;
            &amp;quot;loveEarrings&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isChecked(attacker.harmonyEarrings)) {&lt;br /&gt;
          piercingHitPercentage += getMarriageBonusValue(&lt;br /&gt;
            attacker,&lt;br /&gt;
            marriageTable,&lt;br /&gt;
            &amp;quot;harmonyEarrings&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (isChecked(attacker.tigerStrength)) {&lt;br /&gt;
        tigerStrength = 40;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      for (var index = 0; index &amp;lt; elementBonus.length; index++) {&lt;br /&gt;
        var elementBonusName = mapping.elementBonus[index];&lt;br /&gt;
        var elementResistanceName = mapping.elementResistance[index];&lt;br /&gt;
&lt;br /&gt;
        if (attacker[elementBonusName] &amp;amp;&amp;amp; victim[elementBonusName]) {&lt;br /&gt;
          elementBonus[index] =&lt;br /&gt;
            50 * (attacker[elementBonusName] - victim[elementResistanceName]);&lt;br /&gt;
        } else {&lt;br /&gt;
          elementBonus[index] = 5 * attacker[elementBonusName];&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      var victimType = victim.type;&lt;br /&gt;
&lt;br /&gt;
      if (victimType !== -1) {&lt;br /&gt;
        typeBonus = attacker[mapping.typeFlag[victimType]];&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      monsterBonus = attacker.monsterBonus;&lt;br /&gt;
&lt;br /&gt;
      if (isStone(victim)) {&lt;br /&gt;
        stoneBonus = attacker.stoneBonus;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (isBoss(victim)) {&lt;br /&gt;
        if (skillType) {&lt;br /&gt;
          skillDamage += attacker.skillBossDamage;&lt;br /&gt;
        } else {&lt;br /&gt;
          averageDamage += attacker.bossDamage;&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (isChecked(attacker.onYohara)) {&lt;br /&gt;
        var sungmaStrDifference = attacker.sungmaStr - attacker.sungmaStrMalus;&lt;br /&gt;
&lt;br /&gt;
        if (sungmaStrDifference &amp;gt;= 0) {&lt;br /&gt;
          sungMaStrBonus = sungmaStrDifference;&lt;br /&gt;
        } else {&lt;br /&gt;
          sungmaStrMalus = 0.5;&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (skillType) {&lt;br /&gt;
      skillDamage += attacker.skillDamage;&lt;br /&gt;
    } else {&lt;br /&gt;
      averageDamage += attacker.averageDamage;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    rankBonus = getRankBonus(attacker);&lt;br /&gt;
    damageBonus = attacker.damageBonus;&lt;br /&gt;
&lt;br /&gt;
    if (isChecked(attacker.empireMalus)) {&lt;br /&gt;
      empireMalus = 1;&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    if (isPC(victim)) {&lt;br /&gt;
      if (isChecked(victim.isMarried)) {&lt;br /&gt;
        if (isChecked(victim.harmonyBracelet)) {&lt;br /&gt;
          monsterResistanceMarriage = getMarriageBonusValue(&lt;br /&gt;
            victim,&lt;br /&gt;
            marriageTable,&lt;br /&gt;
            &amp;quot;harmonyBracelet&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isChecked(victim.harmonyNecklace) &amp;amp;&amp;amp; !skillType) {&lt;br /&gt;
          defenseMarriage = getMarriageBonusValue(&lt;br /&gt;
            victim,&lt;br /&gt;
            marriageTable,&lt;br /&gt;
            &amp;quot;harmonyNecklace&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      monsterResistance = victim.monsterResistance;&lt;br /&gt;
&lt;br /&gt;
      for (var index = 0; index &amp;lt; elementBonus.length; index++) {&lt;br /&gt;
        var elementBonusName = mapping.elementBonus[index];&lt;br /&gt;
        var elementResistanceName = mapping.elementResistance[index];&lt;br /&gt;
&lt;br /&gt;
        if (attacker[elementBonusName]) {&lt;br /&gt;
          elementBonus[index] =&lt;br /&gt;
            80 * (attacker[elementBonusName] - victim[elementResistanceName]);&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (!skillType) {&lt;br /&gt;
        if (isMeleeAttacker(attacker)) {&lt;br /&gt;
          missPercentage = victim.meleeBlock;&lt;br /&gt;
          averageDamageResistance = victim.averageDamageResistance;&lt;br /&gt;
          berserkBonus = calcBerserkBonus(skillPowerTable, victim);&lt;br /&gt;
          blessingBonus = calcBlessingBonus(skillPowerTable, victim);&lt;br /&gt;
          fearBonus = calcFearBonus(skillPowerTable, victim);&lt;br /&gt;
        } else if (isRangeAttacker(attacker)) {&lt;br /&gt;
          missPercentage = victim.arrowBlock;&lt;br /&gt;
          weaponDefense = victim.arrowDefense;&lt;br /&gt;
          averageDamageResistance = victim.averageDamageResistance;&lt;br /&gt;
          berserkBonus = calcBerserkBonus(skillPowerTable, victim);&lt;br /&gt;
          blessingBonus = calcBlessingBonus(skillPowerTable, victim);&lt;br /&gt;
          fearBonus = calcFearBonus(skillPowerTable, victim);&lt;br /&gt;
        } else if (isMagicAttacker(attacker)) {&lt;br /&gt;
          missPercentage = victim.arrowBlock;&lt;br /&gt;
          skillDamageResistance = victim.skillDamageResistance;&lt;br /&gt;
          magicResistance = victim.magicResistance;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        missPercentage +=&lt;br /&gt;
          victim.meleeArrowBlock -&lt;br /&gt;
          (missPercentage * victim.meleeArrowBlock) / 100;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    typeBonus = 1;&lt;br /&gt;
    damageMultiplier = attacker.damageMultiplier;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillType) {&lt;br /&gt;
    criticalHitPercentage = calcCriticalSkillChance(criticalHitPercentage);&lt;br /&gt;
    piercingHitPercentage = calcPiercingSkillChance(piercingHitPercentage);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (isPC(victim)) {&lt;br /&gt;
    if (!skillType &amp;amp;&amp;amp; isChecked(victim.biologist70)) {&lt;br /&gt;
      defenseBoost = Math.floor((defenseBoost * 110) / 100);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    criticalHitPercentage = Math.max(&lt;br /&gt;
      0,&lt;br /&gt;
      criticalHitPercentage - victim.criticalHitResistance&lt;br /&gt;
    );&lt;br /&gt;
    piercingHitPercentage = Math.max(&lt;br /&gt;
      0,&lt;br /&gt;
      piercingHitPercentage - victim.piercingHitResistance&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    if (skillType) {&lt;br /&gt;
      skillDamageResistance = victim.skillDamageResistance;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      victim.useDarkProtection &amp;amp;&amp;amp;&lt;br /&gt;
      victim.class === &amp;quot;black_magic&amp;quot; &amp;amp;&amp;amp;&lt;br /&gt;
      victim.skillDarkProtection&lt;br /&gt;
    ) {&lt;br /&gt;
      useDarkProtection = true;&lt;br /&gt;
      darkProtectionPoint = calcDarkProtectionPoint(skillPowerTable, victim);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isMagicClass(victim)) {&lt;br /&gt;
      defensePercent = (-2 * victim.magicDefense * victim.defensePercent) / 100;&lt;br /&gt;
    } else {&lt;br /&gt;
      defensePercent = (-2 * defenseBoost * victim.defensePercent) / 100;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isChecked(victim.steelDragonElixir)) {&lt;br /&gt;
      steelDragonElixir = 10;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillType === &amp;quot;magic&amp;quot;) {&lt;br /&gt;
    attackValueMeleeMagic = 0;&lt;br /&gt;
    magicAttackValueMeleeMagic =&lt;br /&gt;
      attacker.attackMagic + Math.min(100, attacker.attackMeleeMagic);&lt;br /&gt;
    attackValueMarriage = 0;&lt;br /&gt;
    defense = 0;&lt;br /&gt;
    if (isDispell(attacker, 6)) {&lt;br /&gt;
      typeBonus = 0;&lt;br /&gt;
      raceBonus = 0;&lt;br /&gt;
      raceResistance = 0;&lt;br /&gt;
      stoneBonus = 0;&lt;br /&gt;
      monsterBonus = 0;&lt;br /&gt;
      for (var index = 0; index &amp;lt; elementBonus.length; index++) {&lt;br /&gt;
        elementBonus[index] = 0;&lt;br /&gt;
      }&lt;br /&gt;
    } else {&lt;br /&gt;
      magicResistance = victim.magicResistance;&lt;br /&gt;
    }&lt;br /&gt;
    weaponDefense = 0;&lt;br /&gt;
    calcAttackValues = calcMagicAttackValue;&lt;br /&gt;
  } else {&lt;br /&gt;
    calcAttackValues = calcSecondaryAttackValue;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  missPercentage = Math.min(100, missPercentage);&lt;br /&gt;
  criticalHitPercentage = Math.min(criticalHitPercentage, 100);&lt;br /&gt;
  piercingHitPercentage = Math.min(piercingHitPercentage, 100);&lt;br /&gt;
&lt;br /&gt;
  const bonusValues = {&lt;br /&gt;
    missPercentage: missPercentage,&lt;br /&gt;
    skipCriticalStep: [&lt;br /&gt;
      !Boolean(100 - criticalHitPercentage),&lt;br /&gt;
      !Boolean(criticalHitPercentage),&lt;br /&gt;
    ],&lt;br /&gt;
    skipPiercingStep: [&lt;br /&gt;
      !Boolean(100 - piercingHitPercentage),&lt;br /&gt;
      !Boolean(piercingHitPercentage),&lt;br /&gt;
    ],&lt;br /&gt;
    weaponBonusCoeff: 1,&lt;br /&gt;
    attackValueCoeff: 100 + attackValueMeleeMagic,&lt;br /&gt;
    attackValueMarriage: attackValueMarriage,&lt;br /&gt;
    monsterResistanceMarriageCoeff: 100 - monsterResistanceMarriage,&lt;br /&gt;
    monsterResistanceCoeff: 100 - monsterResistance,&lt;br /&gt;
    typeBonusCoeff: typeBonus,&lt;br /&gt;
    raceBonusCoeff: raceBonus,&lt;br /&gt;
    raceResistanceCoeff: raceResistance,&lt;br /&gt;
    stoneBonusCoeff: stoneBonus,&lt;br /&gt;
    monsterBonusCoeff: monsterBonus,&lt;br /&gt;
    elementBonusCoeff: elementBonus,&lt;br /&gt;
    damageMultiplier: damageMultiplier,&lt;br /&gt;
    useDamage: useDamage,&lt;br /&gt;
    defense: defense,&lt;br /&gt;
    defenseBoost: defenseBoost,&lt;br /&gt;
    defenseMarriage: defenseMarriage,&lt;br /&gt;
    tigerStrengthCoeff: 100 + tigerStrength,&lt;br /&gt;
    magicResistanceCoeff: magicResistanceToCoeff(magicResistance),&lt;br /&gt;
    weaponDefenseCoeff: 100 - weaponDefense,&lt;br /&gt;
    berserkBonusCoeff: 100 + berserkBonus,&lt;br /&gt;
    blessingBonusCoeff: 100 - blessingBonus,&lt;br /&gt;
    fearBonusCoeff: 100 - fearBonus,&lt;br /&gt;
    magicAttackValueCoeff: 100 + magicAttackValueMeleeMagic,&lt;br /&gt;
    extraPiercingHitCoeff: 5 * extraPiercingHitPercentage,&lt;br /&gt;
    averageDamageCoeff: 100 + averageDamage,&lt;br /&gt;
    averageDamageResistanceCoeff: 100 - Math.min(99, averageDamageResistance),&lt;br /&gt;
    skillDamageCoeff: 100 + skillDamage,&lt;br /&gt;
    skillDamageResistanceCoeff: 100 - Math.min(99, skillDamageResistance),&lt;br /&gt;
    useDarkProtection: useDarkProtection,&lt;br /&gt;
    darkProtectionPoint: darkProtectionPoint,&lt;br /&gt;
    darkProtectionSp: victim.darkProtectionSp,&lt;br /&gt;
    rankBonusCoeff: 100 + rankBonus,&lt;br /&gt;
    defensePercent: Math.floor(defensePercent),&lt;br /&gt;
    damageBonusCoeff: Math.min(20, damageBonus),&lt;br /&gt;
    empireMalusCoeff: 10 - empireMalus,&lt;br /&gt;
    sungMaStrBonusCoeff: 10000 + sungMaStrBonus,&lt;br /&gt;
    sungmaStrMalusCoeff: sungmaStrMalus,&lt;br /&gt;
    whiteDragonElixirCoeff: 100 + whiteDragonElixir,&lt;br /&gt;
    steelDragonElixirCoeff: 100 - steelDragonElixir,&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  const damageTypeWeights = [&lt;br /&gt;
    (100 - criticalHitPercentage) *&lt;br /&gt;
      (100 - piercingHitPercentage) *&lt;br /&gt;
      (100 - missPercentage),&lt;br /&gt;
    criticalHitPercentage *&lt;br /&gt;
      (100 - piercingHitPercentage) *&lt;br /&gt;
      (100 - missPercentage),&lt;br /&gt;
    (100 - criticalHitPercentage) *&lt;br /&gt;
      piercingHitPercentage *&lt;br /&gt;
      (100 - missPercentage),&lt;br /&gt;
    criticalHitPercentage * piercingHitPercentage * (100 - missPercentage),&lt;br /&gt;
  ];&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    attacker: attacker,&lt;br /&gt;
    victim: victim,&lt;br /&gt;
    attackFactor: calcAttackFactor(attacker, victim),&lt;br /&gt;
    mainAttackValue: calcMainAttackValue(attacker),&lt;br /&gt;
    attackValues: calcAttackValues(attacker, isPlayerVsPlayer),&lt;br /&gt;
    bonusValues: bonusValues,&lt;br /&gt;
    damageTypeWeights: damageTypeWeights,&lt;br /&gt;
    attackTypeMapping: mapping.attackType,&lt;br /&gt;
    damageWeightedByType: {&lt;br /&gt;
      normalHit: {},&lt;br /&gt;
      criticalHit: {},&lt;br /&gt;
      piercingHit: {},&lt;br /&gt;
      criticalPiercingHit: {},&lt;br /&gt;
    },&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateBattleValues(battleValues, skillFormula, skillInfo) {&lt;br /&gt;
  var weaponBonus = 0;&lt;br /&gt;
  var skillWard = 0;&lt;br /&gt;
  var skillBonus = 0;&lt;br /&gt;
  var skillBonusByBonus = 0;&lt;br /&gt;
  var { attacker: attacker, bonusValues: bonusValues } = battleValues;&lt;br /&gt;
  var {&lt;br /&gt;
    range: [minVariation, maxVariation],&lt;br /&gt;
  } = skillInfo;&lt;br /&gt;
  var variationLength = maxVariation - minVariation + 1;&lt;br /&gt;
&lt;br /&gt;
  if (skillInfo.hasOwnProperty(&amp;quot;weaponBonus&amp;quot;)) {&lt;br /&gt;
    var [weaponType, weaponBonusValue] = skillInfo.weaponBonus;&lt;br /&gt;
&lt;br /&gt;
    if (weaponType === attacker.weapon.type) {&lt;br /&gt;
      weaponBonus = weaponBonusValue;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillInfo.skillBonus) {&lt;br /&gt;
    skillBonus = skillInfo.skillBonus;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillInfo.skillWard) {&lt;br /&gt;
    skillWard = skillInfo.skillWard;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillInfo.skillBonusByBonus) {&lt;br /&gt;
    skillBonusByBonus = skillInfo.skillBonusByBonus;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillInfo.removeWeaponReduction) {&lt;br /&gt;
    bonusValues.weaponDefenseCoeff = 100;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  bonusValues.weaponBonusCoeff = 100 + weaponBonus;&lt;br /&gt;
  bonusValues.skillWardCoeff = 1 - skillWard / 100;&lt;br /&gt;
  bonusValues.skillBonusCoeff = 1 + skillBonus / 100;&lt;br /&gt;
  bonusValues.skillBonusByBonusCoeff = 100 + skillBonusByBonus;&lt;br /&gt;
&lt;br /&gt;
  battleValues.skillFormula = skillFormula;&lt;br /&gt;
  battleValues.skillRange = skillInfo.range;&lt;br /&gt;
  battleValues.attackValues.totalCardinal *= variationLength;&lt;br /&gt;
  battleValues.attackValues.possibleDamageCount *= variationLength;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcWeights(minValue, maxValue, minInterval) {&lt;br /&gt;
  var firstWeightLimit = minValue + minInterval - 1;&lt;br /&gt;
  var lastWeightsLimit = maxValue - minInterval + 1;&lt;br /&gt;
  var weights = [];&lt;br /&gt;
&lt;br /&gt;
  for (var value = minValue; value &amp;lt; firstWeightLimit; value++) {&lt;br /&gt;
    weights.push(value - minValue + 1);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (var value = firstWeightLimit; value &amp;lt;= lastWeightsLimit; value++) {&lt;br /&gt;
    weights.push(minInterval);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (var value = lastWeightsLimit + 1; value &amp;lt;= maxValue; value++) {&lt;br /&gt;
    weights.push(maxValue - value + 1);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return weights;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcBerserkBonus(skillPowerTable, victim) {&lt;br /&gt;
  if (!isChecked(victim.useBerserk) || victim.class !== &amp;quot;body&amp;quot;) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var skillPower = getSkillPower(victim.skillBerserk, skillPowerTable);&lt;br /&gt;
&lt;br /&gt;
  if (!skillPower) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var berserkBonus = Math.floor(skillPower * 25);&lt;br /&gt;
&lt;br /&gt;
  return berserkBonus;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcBlessingBonus(skillPowerTable, victim) {&lt;br /&gt;
  if (!isChecked(victim.isBlessed)) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var int = victim.intBlessing;&lt;br /&gt;
  var dex = victim.dexBlessing;&lt;br /&gt;
  var skillPower = getSkillPower(victim.skillBlessing, skillPowerTable);&lt;br /&gt;
&lt;br /&gt;
  if (!skillPower) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var blessingBonus = floorMultiplication(&lt;br /&gt;
    ((int * 0.3 + 5) * (2 * skillPower + 0.5) + 0.3 * dex) / (skillPower + 2.3),&lt;br /&gt;
    1&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  if (victim.class === &amp;quot;dragon&amp;quot; &amp;amp;&amp;amp; isChecked(victim.blessingOnself)) {&lt;br /&gt;
    blessingBonus = floorMultiplication(blessingBonus, 1.1);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return blessingBonus;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcFearBonus(skillPowerTable, victim) {&lt;br /&gt;
  if (!isChecked(victim.useFear) || victim.class !== &amp;quot;weaponary&amp;quot;) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var skillPower = getSkillPower(victim.skillFear, skillPowerTable);&lt;br /&gt;
&lt;br /&gt;
  if (!skillPower) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var fearBonus = 5 + Math.floor(skillPower * 20);&lt;br /&gt;
&lt;br /&gt;
  return fearBonus;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcDarkProtectionPoint(skillPowerTable, victim) {&lt;br /&gt;
  var skillPower = getSkillPower(victim.skillDarkProtection, skillPowerTable);&lt;br /&gt;
&lt;br /&gt;
  return floorMultiplication(100 - victim.int * 0.84 * skillPower, 1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSkillFormula(battle, skillId, battleValues, removeSkillVariation) {&lt;br /&gt;
  var { attacker, victim, attackFactor } = battleValues;&lt;br /&gt;
  var skillPowerTable = battle.constants.skillPowerTable;&lt;br /&gt;
&lt;br /&gt;
  var skillFormula;&lt;br /&gt;
  var skillInfo = { range: [0, 0] };&lt;br /&gt;
&lt;br /&gt;
  var { class: attackerClass, level: lv, vit, str, int, dex } = attacker;&lt;br /&gt;
&lt;br /&gt;
  if (skillId &amp;lt;= 9) {&lt;br /&gt;
    var skillPower = getSkillPower(&lt;br /&gt;
      attacker[&amp;quot;attackSkill&amp;quot; + skillId],&lt;br /&gt;
      skillPowerTable&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    var improvedBySkillBonus = false;&lt;br /&gt;
    var improvedByBonus = false;&lt;br /&gt;
&lt;br /&gt;
    if (attackerClass === &amp;quot;body&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Triple lacération&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.1 * atk + (0.5 * atk + 1.5 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Moulinet à l'épée&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              3 * atk + (0.8 * atk + 5 * str + 3 * dex + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Accélération&lt;br /&gt;
        case 5:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * atk + (atk + dex * 3 + str * 7 + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Volonté de vivre&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              (3 * atk + (atk + 1.5 * str) * skillPower) * 1.07,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          break;&lt;br /&gt;
        // Tremblement de terre&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              3 * atk +&lt;br /&gt;
                (0.9 * atk + variation + 5 * str + 3 * dex + lv) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;mental&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Attaque de l'esprit&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2.3 * atk + (4 * atk + 4 * str + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Attaque de la paume&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2.3 * atk + (3 * atk + 4 * str + 3 * vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Charge&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * atk + (2 * atk + 2 * dex + 2 * vit + 4 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          break;&lt;br /&gt;
        // Coup d'épée&lt;br /&gt;
        case 5:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * atk + (atk + 3 * dex + 5 * str + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Orbe de l'épée&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              (2 * atk + (2 * atk + 2 * dex + 2 * vit + 4 * str) * skillPower) *&lt;br /&gt;
                1.1,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          break;&lt;br /&gt;
        // Tremblement de terre&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              3 * atk +&lt;br /&gt;
                (0.9 * atk + variation + 5 * str + 3 * dex + lv) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;blade_fight&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Embuscade&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk + (1.2 * atk + variation + 4 * dex + 4 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [1, 50];&lt;br /&gt;
          skillInfo.range = [500, 700];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Attaque rapide&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk + (1.6 * atk + variation + 7 * dex + 7 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [1, 35];&lt;br /&gt;
          skillInfo.range = [200, 300];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Dague filante&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * atk + (0.5 * atk + 9 * dex + 7 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Brume empoisonnée&lt;br /&gt;
        case 5:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * lv + (atk + 3 * str + 18 * dex) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Poison insidieux&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              (2 * lv + (atk + 3 * str + 18 * dex) * skillPower) * 1.1,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          break;&lt;br /&gt;
        // Étoiles brillantes&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk + (1.7 * atk + variation + 6 * dex + 5 * lv) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;archery&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Tir à répétition&lt;br /&gt;
        // case 1:&lt;br /&gt;
        //   skillFormula = function (atk) {&lt;br /&gt;
        //     return floorMultiplication(&lt;br /&gt;
        //       atk + 0.2 * atk * Math.floor(2 + 6 * skillPower) + (0.8 * atk + 8 * dex * attackFactor + 2 * int) * skillPower,&lt;br /&gt;
        //       1&lt;br /&gt;
        //     );&lt;br /&gt;
        //   };&lt;br /&gt;
        //   improvedByBonus = true;&lt;br /&gt;
        //   break;&lt;br /&gt;
        // Pluie de flèches&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk + (1.7 * atk + 5 * dex + str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Flèche de feu&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.5 * atk + (2.6 * atk + 0.9 * int + variation) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [100, 300];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Foulée de plume&lt;br /&gt;
        case 4:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              (3 * dex + 200 + 2 * str + 2 * int) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.removeWeaponReduction = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Flèche empoisonnée&lt;br /&gt;
        case 5:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk +&lt;br /&gt;
                (1.4 * atk + variation + 7 * dex + 4 * str + 4 * int) *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [100, 200];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Coup étincelant&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              (atk +&lt;br /&gt;
                (1.2 * atk + variation + 6 * dex + 3 * str + 3 * int) *&lt;br /&gt;
                  skillPower) *&lt;br /&gt;
                1.2,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [100, 200];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Tir tempête&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.9 * atk + (2.6 * atk + variation) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;weaponary&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Toucher brûlant&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk +&lt;br /&gt;
                2 * lv +&lt;br /&gt;
                2 * int +&lt;br /&gt;
                (2 * atk + 4 * str + 14 * int) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Tourbillon du dragon&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.1 * atk +&lt;br /&gt;
                2 * lv +&lt;br /&gt;
                2 * int +&lt;br /&gt;
                (1.5 * atk + str + 12 * int) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Contre-sort&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              40 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                2 * int +&lt;br /&gt;
                (10 * int + 7 * mav + variation) * attackFactor * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [50, 100];&lt;br /&gt;
          break;&lt;br /&gt;
        // Coup démoniaque&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.9 * atk + (2.6 * atk + variation) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;black_magic&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Attaque des ténèbres&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              40 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                2 * int +&lt;br /&gt;
                (13 * int + 6 * mav + variation) * attackFactor * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [50, 100];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Attaque de flammes&lt;br /&gt;
        // case 2:&lt;br /&gt;
        //   skillFormula = function (mav, variation) {&lt;br /&gt;
        //     return floorMultiplication(&lt;br /&gt;
        //       5 * lv + 2 * int + (7 * int + 8 * mav + 4 * str + 2 * vit + variation) * skillPower,&lt;br /&gt;
        //       1&lt;br /&gt;
        //     );&lt;br /&gt;
        //   };&lt;br /&gt;
        //   skillInfo.range = [180, 100];&lt;br /&gt;
        //   improvedByBonus = true;&lt;br /&gt;
        //   break;&lt;br /&gt;
        // Esprit de flammes&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              30 +&lt;br /&gt;
                2 * lv +&lt;br /&gt;
                2 * int +&lt;br /&gt;
                (7 * int + 6 * mav + variation) * attackFactor * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [200, 500];&lt;br /&gt;
          break;&lt;br /&gt;
        // Frappe de l'esprit&lt;br /&gt;
        // case 5:&lt;br /&gt;
        //   skillFormula = function (mav, variation) {&lt;br /&gt;
        //     return floorMultiplication(&lt;br /&gt;
        //       40 + 2 * lv + 2 * int + (2 * vit + 2 * dex + 13 * int + 6 * mav + variation) * attackFactor * skillPower,&lt;br /&gt;
        //       1&lt;br /&gt;
        //     );&lt;br /&gt;
        //   };&lt;br /&gt;
        //   skillInfo.range = [180, 200];&lt;br /&gt;
        //   break;&lt;br /&gt;
        // Orbe des ténèbres&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (mav) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              120 +&lt;br /&gt;
                6 * lv +&lt;br /&gt;
                (5 * vit + 5 * dex + 29 * int + 9 * mav) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Vague mortelle&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              120 +&lt;br /&gt;
                6 * lv +&lt;br /&gt;
                (5 * vit + 5 * dex + 30 * int + variation + 9 * mav) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;dragon&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Talisman volant&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (mav) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              70 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                (18 * int + 7 * str + 5 * mav + 50) * attackFactor * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [4, 10];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Dragon chassant&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (mav) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              60 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                (16 * int + 6 * dex + 6 * mav + 120) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [4, 10];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Rugissement du dragon&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (mav) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              70 +&lt;br /&gt;
                3 * lv +&lt;br /&gt;
                (20 * int + 3 * str + 10 * mav + 100) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [4, 10];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Météore&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              120 +&lt;br /&gt;
                6 * lv +&lt;br /&gt;
                (5 * vit + 5 * dex + 30 * int + variation + 9 * mav) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;heal&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Jet de foudre&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              60 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                (8 * int + 2 * dex + 8 * mav + variation) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [6, 10];&lt;br /&gt;
          skillInfo.range = [5 * int, 15 * int];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Invocation de foudre&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              40 +&lt;br /&gt;
                4 * lv +&lt;br /&gt;
                (13 * int + 2 * str + 10 * mav + variation) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [6, 10];&lt;br /&gt;
          skillInfo.range = [5 * int, 16 * int];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Griffe de foudre&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              50 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                (8 * int + 2 * str + 8 * mav + variation) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 800];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;lycan&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Déchiqueter&lt;br /&gt;
        // case 1:&lt;br /&gt;
        //   skillFormula = function (atk) {&lt;br /&gt;
        //     return floorMultiplication(&lt;br /&gt;
        //       1.1 * atk + (0.3 * atk + 1.5 * str) * skillPower,&lt;br /&gt;
        //       1&lt;br /&gt;
        //     );&lt;br /&gt;
        //   };&lt;br /&gt;
        //   skillInfo.weaponBonus = [5, 54];&lt;br /&gt;
        //   improvedByBonus = true;&lt;br /&gt;
        //   break;&lt;br /&gt;
        // Souffle de loup&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * atk + (atk + 3 * dex + 5 * str + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [5, 35];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Bond de loup&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk + (1.6 * atk + 200 + 7 * dex + 7 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [5, 35];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Griffe de loup&lt;br /&gt;
        case 4:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              3 * atk + (0.8 * atk + 6 * str + 2 * dex + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Tempête cinglante&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.8 * atk +&lt;br /&gt;
                (atk + 6 * dex + variation + 3 * str + lv) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
    if (improvedBySkillBonus) {&lt;br /&gt;
      skillInfo.skillBonus =&lt;br /&gt;
        16 * getSkillPower(attacker.skillBonus, skillPowerTable);&lt;br /&gt;
&lt;br /&gt;
      var skillWardChoice = victim.skillWardChoice;&lt;br /&gt;
&lt;br /&gt;
      if (skillWardChoice &amp;amp;&amp;amp; skillWardChoice === attackerClass) {&lt;br /&gt;
        skillInfo.skillWard =&lt;br /&gt;
          24 * getSkillPower(victim.skillWard, skillPowerTable);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (improvedByBonus) {&lt;br /&gt;
      skillInfo.skillBonusByBonus = attacker[&amp;quot;skillBonus&amp;quot; + skillId];&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (removeSkillVariation) {&lt;br /&gt;
      var averageVariation = (skillInfo.range[0] + skillInfo.range[0]) / 2;&lt;br /&gt;
      skillInfo.range = [averageVariation, averageVariation];&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    var skillPower = getSkillPower(&lt;br /&gt;
      attacker[&amp;quot;horseSkill&amp;quot; + skillId],&lt;br /&gt;
      skillPowerTable&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    switch (skillId) {&lt;br /&gt;
      // Combat équestre&lt;br /&gt;
      case 137:&lt;br /&gt;
        skillFormula = function (atk) {&lt;br /&gt;
          return floorMultiplication(atk + 2 * atk * skillPower, 1);&lt;br /&gt;
        };&lt;br /&gt;
        break;&lt;br /&gt;
      // Charge à cheval&lt;br /&gt;
      case 138:&lt;br /&gt;
        skillFormula = function (atk) {&lt;br /&gt;
          return floorMultiplication(&lt;br /&gt;
            2.4 * (200 + 1.5 * lv) + 600 * skillPower,&lt;br /&gt;
            1&lt;br /&gt;
          );&lt;br /&gt;
        };&lt;br /&gt;
        break;&lt;br /&gt;
      // Vague de Pouvoir&lt;br /&gt;
      case 139:&lt;br /&gt;
        skillFormula = function (atk) {&lt;br /&gt;
          return floorMultiplication(&lt;br /&gt;
            2 * (200 + 1.5 * lv) + 600 * skillPower,&lt;br /&gt;
            1&lt;br /&gt;
          );&lt;br /&gt;
        };&lt;br /&gt;
        break;&lt;br /&gt;
      // Grêle de flèches&lt;br /&gt;
      case 140:&lt;br /&gt;
        skillFormula = function (atk) {&lt;br /&gt;
          return floorMultiplication(atk + 2 * atk * skillPower, 1);&lt;br /&gt;
        };&lt;br /&gt;
        break;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  updateBattleValues(battleValues, skillFormula, skillInfo);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcMagicAttackValueAugmentation(&lt;br /&gt;
  magicAttackValueWeapon,&lt;br /&gt;
  magicAttackValueBonus&lt;br /&gt;
) {&lt;br /&gt;
  if (magicAttackValueBonus) {&lt;br /&gt;
    return Math.max(&lt;br /&gt;
      1,&lt;br /&gt;
      0.0025056 *&lt;br /&gt;
        magicAttackValueBonus ** 0.602338 *&lt;br /&gt;
        magicAttackValueWeapon ** 1.20476&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
  return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getMagicAttackValueAugmentation(&lt;br /&gt;
  minMagicAttackValue,&lt;br /&gt;
  maxMagicAttackValue,&lt;br /&gt;
  magicAttackValueBonus&lt;br /&gt;
) {&lt;br /&gt;
  var magicAttackValueAugmentation = [];&lt;br /&gt;
&lt;br /&gt;
  for (&lt;br /&gt;
    var magicAttackValue = minMagicAttackValue;&lt;br /&gt;
    magicAttackValue &amp;lt;= maxMagicAttackValue;&lt;br /&gt;
    magicAttackValue++&lt;br /&gt;
  ) {&lt;br /&gt;
    magicAttackValueAugmentation.push(&lt;br /&gt;
      calcMagicAttackValueAugmentation(magicAttackValue, magicAttackValueBonus)&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return magicAttackValueAugmentation;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcPhysicalDamage(battleValues) {&lt;br /&gt;
  const {&lt;br /&gt;
    attackFactor,&lt;br /&gt;
    mainAttackValue,&lt;br /&gt;
    attackValues: {&lt;br /&gt;
      minAttackValue,&lt;br /&gt;
      maxAttackValue,&lt;br /&gt;
      attackValueOther,&lt;br /&gt;
      weights,&lt;br /&gt;
      criticalAttackRange,&lt;br /&gt;
    },&lt;br /&gt;
    bonusValues,&lt;br /&gt;
    damageWeightedByType,&lt;br /&gt;
  } = battleValues;&lt;br /&gt;
&lt;br /&gt;
  const savedDamage = {};&lt;br /&gt;
&lt;br /&gt;
  if (bonusValues.missPercentage) {&lt;br /&gt;
    damageWeightedByType.miss = bonusValues.missPercentage / 100;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (&lt;br /&gt;
    let attackValue = minAttackValue;&lt;br /&gt;
    attackValue &amp;lt;= maxAttackValue;&lt;br /&gt;
    attackValue++&lt;br /&gt;
  ) {&lt;br /&gt;
    const weight = weights[attackValue - minAttackValue];&lt;br /&gt;
    const damageByType = [[], [], [], []];&lt;br /&gt;
    const currentDamageInfo = [weight, damageByType];&lt;br /&gt;
&lt;br /&gt;
    const secondaryAttackValue = 2 * attackValue + attackValueOther;&lt;br /&gt;
    const rawDamage =&lt;br /&gt;
      mainAttackValue + floorMultiplication(attackFactor, secondaryAttackValue);&lt;br /&gt;
&lt;br /&gt;
    const damageWithPrimaryBonuses = calcDamageWithPrimaryBonuses(&lt;br /&gt;
      rawDamage,&lt;br /&gt;
      bonusValues&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    const minPiercingDamage =&lt;br /&gt;
      damageWithPrimaryBonuses -&lt;br /&gt;
      bonusValues.defenseBoost -&lt;br /&gt;
      bonusValues.defenseMarriage;&lt;br /&gt;
&lt;br /&gt;
    const damageValues =&lt;br /&gt;
      minPiercingDamage &amp;lt;= 2 ? [1, 2, 3, 4, 5] : [minPiercingDamage];&lt;br /&gt;
&lt;br /&gt;
    for (const damage of damageValues) {&lt;br /&gt;
      saveFinalDamage(&lt;br /&gt;
        damage,&lt;br /&gt;
        minPiercingDamage,&lt;br /&gt;
        damageWithPrimaryBonuses,&lt;br /&gt;
        bonusValues,&lt;br /&gt;
        criticalAttackRange,&lt;br /&gt;
        damageByType&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    savedDamage[attackValue] = currentDamageInfo;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  processSavedDamage(savedDamage, damageWeightedByType, battleValues);&lt;br /&gt;
&lt;br /&gt;
  return damageWeightedByType;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcPhysicalSkillDamage(battleValues) {&lt;br /&gt;
  const {&lt;br /&gt;
    attackFactor,&lt;br /&gt;
    mainAttackValue,&lt;br /&gt;
    attackValues: {&lt;br /&gt;
      minAttackValue,&lt;br /&gt;
      maxAttackValue,&lt;br /&gt;
      attackValueOther,&lt;br /&gt;
      weights,&lt;br /&gt;
      criticalAttackRange,&lt;br /&gt;
    },&lt;br /&gt;
    bonusValues,&lt;br /&gt;
    damageWeightedByType,&lt;br /&gt;
    skillFormula,&lt;br /&gt;
    skillRange: [minVariation, maxVariation],&lt;br /&gt;
  } = battleValues;&lt;br /&gt;
&lt;br /&gt;
  const savedDamage = {};&lt;br /&gt;
&lt;br /&gt;
  for (&lt;br /&gt;
    let attackValue = minAttackValue;&lt;br /&gt;
    attackValue &amp;lt;= maxAttackValue;&lt;br /&gt;
    attackValue++&lt;br /&gt;
  ) {&lt;br /&gt;
    const weight = weights[attackValue - minAttackValue];&lt;br /&gt;
&lt;br /&gt;
    const secondaryAttackValue = 2 * attackValue + attackValueOther;&lt;br /&gt;
    const rawDamage =&lt;br /&gt;
      mainAttackValue + floorMultiplication(attackFactor, secondaryAttackValue);&lt;br /&gt;
&lt;br /&gt;
    const damageWithPrimaryBonuses = calcDamageWithPrimaryBonuses(&lt;br /&gt;
      rawDamage,&lt;br /&gt;
      bonusValues&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    const damageValues =&lt;br /&gt;
      damageWithPrimaryBonuses &amp;lt;= 2&lt;br /&gt;
        ? [1, 2, 3, 4, 5]&lt;br /&gt;
        : [damageWithPrimaryBonuses];&lt;br /&gt;
&lt;br /&gt;
    for (let variation = minVariation; variation &amp;lt;= maxVariation; variation++) {&lt;br /&gt;
      for (const damage of damageValues) {&lt;br /&gt;
        const damageWithFormula = skillFormula(&lt;br /&gt;
          damage * bonusValues.useDamage,&lt;br /&gt;
          variation&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        let damageKey = damageWithFormula;&lt;br /&gt;
&lt;br /&gt;
        if (damageWithPrimaryBonuses &amp;lt; 0) {&lt;br /&gt;
          damageKey = `${damageWithFormula}_${Math.abs(&lt;br /&gt;
            damageWithPrimaryBonuses&lt;br /&gt;
          )}`;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        const entry = savedDamage[damageKey];&lt;br /&gt;
&lt;br /&gt;
        if (entry) {&lt;br /&gt;
          entry[0] += weight;&lt;br /&gt;
          continue;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        const damageByType = [[], [], [], []];&lt;br /&gt;
        const currentDamageInfo = [weight, damageByType];&lt;br /&gt;
&lt;br /&gt;
        const finalDamage = Math.floor(&lt;br /&gt;
          (damageWithFormula * bonusValues.weaponBonusCoeff) / 100&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        saveFinalSkillDamage(&lt;br /&gt;
          finalDamage,&lt;br /&gt;
          damageWithPrimaryBonuses,&lt;br /&gt;
          bonusValues,&lt;br /&gt;
          criticalAttackRange,&lt;br /&gt;
          damageByType&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        savedDamage[damageKey] = currentDamageInfo;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  processSavedDamage(savedDamage, damageWeightedByType, battleValues);&lt;br /&gt;
&lt;br /&gt;
  return damageWeightedByType;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcMagicSkillDamage(battleValues) {&lt;br /&gt;
  const {&lt;br /&gt;
    attackValues: {&lt;br /&gt;
      minMagicAttackValue,&lt;br /&gt;
      maxMagicAttackValue,&lt;br /&gt;
      magicAttackValueAugmentation,&lt;br /&gt;
      weights,&lt;br /&gt;
      criticalAttackRange,&lt;br /&gt;
    },&lt;br /&gt;
    bonusValues,&lt;br /&gt;
    damageWeightedByType,&lt;br /&gt;
    skillFormula,&lt;br /&gt;
    skillRange: [minVariation, maxVariation],&lt;br /&gt;
  } = battleValues;&lt;br /&gt;
&lt;br /&gt;
  const savedDamage = {};&lt;br /&gt;
&lt;br /&gt;
  for (&lt;br /&gt;
    let magicAttackValue = minMagicAttackValue;&lt;br /&gt;
    magicAttackValue &amp;lt;= maxMagicAttackValue;&lt;br /&gt;
    magicAttackValue++&lt;br /&gt;
  ) {&lt;br /&gt;
    const index = magicAttackValue - minMagicAttackValue;&lt;br /&gt;
    const weight = weights[index];&lt;br /&gt;
&lt;br /&gt;
    for (let variation = minVariation; variation &amp;lt;= maxVariation; variation++) {&lt;br /&gt;
      const rawDamage = skillFormula(&lt;br /&gt;
        magicAttackValue + magicAttackValueAugmentation[index],&lt;br /&gt;
        variation&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      const entry = savedDamage[rawDamage];&lt;br /&gt;
&lt;br /&gt;
      if (entry) {&lt;br /&gt;
        entry[0] += weight;&lt;br /&gt;
        continue;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      const damageByType = [[], [], [], []];&lt;br /&gt;
      const currentDamageInfo = [weight, damageByType];&lt;br /&gt;
&lt;br /&gt;
      let damageWithPrimaryBonuses = Math.floor(&lt;br /&gt;
        (rawDamage * bonusValues.weaponBonusCoeff) / 100&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      damageWithPrimaryBonuses = calcDamageWithPrimaryBonuses(&lt;br /&gt;
        damageWithPrimaryBonuses,&lt;br /&gt;
        bonusValues&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      const damageValues =&lt;br /&gt;
        damageWithPrimaryBonuses &amp;lt;= 2&lt;br /&gt;
          ? [1, 2, 3, 4, 5]&lt;br /&gt;
          : [damageWithPrimaryBonuses];&lt;br /&gt;
&lt;br /&gt;
      for (const damage of damageValues) {&lt;br /&gt;
        saveFinalSkillDamage(&lt;br /&gt;
          damage,&lt;br /&gt;
          damageWithPrimaryBonuses,&lt;br /&gt;
          bonusValues,&lt;br /&gt;
          criticalAttackRange,&lt;br /&gt;
          damageByType&lt;br /&gt;
        );&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      savedDamage[rawDamage] = currentDamageInfo;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  processSavedDamage(savedDamage, damageWeightedByType, battleValues);&lt;br /&gt;
&lt;br /&gt;
  return damageWeightedByType;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcDamage(&lt;br /&gt;
  attacker,&lt;br /&gt;
  victim,&lt;br /&gt;
  attackType,&lt;br /&gt;
  battle,&lt;br /&gt;
  removeSkillVariation&lt;br /&gt;
) {&lt;br /&gt;
  var damageCalculator, skillId, skillType;&lt;br /&gt;
&lt;br /&gt;
  if (attackType === &amp;quot;physical&amp;quot;) {&lt;br /&gt;
    damageCalculator = calcPhysicalDamage;&lt;br /&gt;
  } else if (attackType.startsWith(&amp;quot;attackSkill&amp;quot;)) {&lt;br /&gt;
    skillId = Number(attackType.split(&amp;quot;attackSkill&amp;quot;)[1]);&lt;br /&gt;
&lt;br /&gt;
    if (isMagicClass(attacker) || isDispell(attacker, skillId)) {&lt;br /&gt;
      skillType = &amp;quot;magic&amp;quot;;&lt;br /&gt;
      damageCalculator = calcMagicSkillDamage;&lt;br /&gt;
    } else {&lt;br /&gt;
      skillType = &amp;quot;physical&amp;quot;;&lt;br /&gt;
      damageCalculator = calcPhysicalSkillDamage;&lt;br /&gt;
    }&lt;br /&gt;
  } else if (attackType.startsWith(&amp;quot;horseSkill&amp;quot;)) {&lt;br /&gt;
    skillType = &amp;quot;physical&amp;quot;;&lt;br /&gt;
    skillId = Number(attackType.split(&amp;quot;horseSkill&amp;quot;)[1]);&lt;br /&gt;
    damageCalculator = calcPhysicalSkillDamage;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var battleValues = createBattleValues(attacker, victim, battle, skillType);&lt;br /&gt;
&lt;br /&gt;
  if (skillId) {&lt;br /&gt;
    getSkillFormula(battle, skillId, battleValues, removeSkillVariation);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    damageWeightedByType: damageCalculator(battleValues),&lt;br /&gt;
    attackValues: battleValues.attackValues,&lt;br /&gt;
    skillType: skillType,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function damageWithoutVariation(&lt;br /&gt;
  attacker,&lt;br /&gt;
  victim,&lt;br /&gt;
  attackType,&lt;br /&gt;
  battle,&lt;br /&gt;
  characters&lt;br /&gt;
) {&lt;br /&gt;
  var startDamageTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
  var { damageWeightedByType, attackValues, skillType } = calcDamage(&lt;br /&gt;
    attacker,&lt;br /&gt;
    victim,&lt;br /&gt;
    attackType,&lt;br /&gt;
    battle&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  var endDamageTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
  displayResults(&lt;br /&gt;
    attackValues,&lt;br /&gt;
    damageWeightedByType,&lt;br /&gt;
    battle,&lt;br /&gt;
    attacker.name,&lt;br /&gt;
    victim.name&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  var endDisplayTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
  displayFightInfo(&lt;br /&gt;
    attackValues.possibleDamageCount,&lt;br /&gt;
    endDamageTime - startDamageTime,&lt;br /&gt;
    endDisplayTime - endDamageTime,&lt;br /&gt;
    battle&lt;br /&gt;
  );&lt;br /&gt;
  addPotentialErrorInformation(&lt;br /&gt;
    battle.errorInformation,&lt;br /&gt;
    attacker,&lt;br /&gt;
    victim,&lt;br /&gt;
    skillType,&lt;br /&gt;
    characters&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  hideElement(battle.bonusVariationResultContainer);&lt;br /&gt;
  showElement(battle.fightResultTitle);&lt;br /&gt;
  showElement(battle.fightResultContainer);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function damageWithVariation(&lt;br /&gt;
  attacker,&lt;br /&gt;
  victim,&lt;br /&gt;
  attackType,&lt;br /&gt;
  battle,&lt;br /&gt;
  entity,&lt;br /&gt;
  entityVariation&lt;br /&gt;
) {&lt;br /&gt;
  var startTime = performance.now();&lt;br /&gt;
  var damageByBonus = [];&lt;br /&gt;
  var augmentationByBonus = [];&lt;br /&gt;
  var {&lt;br /&gt;
    bonusVariationMinValue: minVariation,&lt;br /&gt;
    bonusVariationMaxValue: maxVariation,&lt;br /&gt;
  } = entity;&lt;br /&gt;
  var step = Math.ceil((maxVariation - minVariation + 1) / 500);&lt;br /&gt;
  var simulationCount = 0;&lt;br /&gt;
  var simulationTime;&lt;br /&gt;
  var firstDamage = 1;&lt;br /&gt;
&lt;br /&gt;
  for (&lt;br /&gt;
    var bonusValue = minVariation;&lt;br /&gt;
    bonusValue &amp;lt;= maxVariation;&lt;br /&gt;
    bonusValue += step&lt;br /&gt;
  ) {&lt;br /&gt;
    entity[entityVariation] = bonusValue;&lt;br /&gt;
&lt;br /&gt;
    var {&lt;br /&gt;
      damageWeightedByType,&lt;br /&gt;
      attackValues: { totalCardinal },&lt;br /&gt;
    } = calcDamage(&lt;br /&gt;
      copyObject(attacker),&lt;br /&gt;
      copyObject(victim),&lt;br /&gt;
      attackType,&lt;br /&gt;
      battle,&lt;br /&gt;
      true&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    var meanDamage = calcMeanDamage(damageWeightedByType, totalCardinal);&lt;br /&gt;
&lt;br /&gt;
    if (bonusValue === minVariation) {&lt;br /&gt;
      firstDamage = Math.max(meanDamage, 1e-3);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    damageByBonus.push({ x: bonusValue, y: meanDamage });&lt;br /&gt;
    augmentationByBonus.push({&lt;br /&gt;
      x: bonusValue,&lt;br /&gt;
      y: meanDamage / firstDamage - 1,&lt;br /&gt;
    });&lt;br /&gt;
    simulationCount++;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var endTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
  battle.damageByBonus = damageByBonus.concat(entityVariation);&lt;br /&gt;
&lt;br /&gt;
  addToBonusVariationChart(&lt;br /&gt;
    damageByBonus,&lt;br /&gt;
    augmentationByBonus,&lt;br /&gt;
    entity.bonusVariationName,&lt;br /&gt;
    battle.bonusVariationChart&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  simulationCount = battle.numberFormats.default.format(simulationCount);&lt;br /&gt;
  simulationTime = battle.numberFormats.second.format(&lt;br /&gt;
    (endTime - startTime) / 1000&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  battle.simulationCounter.textContent = simulationCount;&lt;br /&gt;
  battle.simulationTime.textContent = simulationTime;&lt;br /&gt;
&lt;br /&gt;
  hideElement(battle.fightResultContainer);&lt;br /&gt;
  showElement(battle.fightResultTitle);&lt;br /&gt;
  showElement(battle.bonusVariationResultContainer);&lt;br /&gt;
&lt;br /&gt;
  if (&lt;br /&gt;
    isChecked(attacker.useBonusVariation) &amp;amp;&amp;amp;&lt;br /&gt;
    isChecked(victim.useBonusVariation)&lt;br /&gt;
  ) {&lt;br /&gt;
    showElement(battle.errorInformation[&amp;quot;attacker-victim-variation&amp;quot;]);&lt;br /&gt;
  } else {&lt;br /&gt;
    hideElement(battle.errorInformation[&amp;quot;attacker-victim-variation&amp;quot;]);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function changeMonsterValues(monster, instance, attacker) {&lt;br /&gt;
  switch (instance) {&lt;br /&gt;
    case &amp;quot;SungMahiTower&amp;quot;:&lt;br /&gt;
      var sungMahiFloor = 1;&lt;br /&gt;
      var sungMahiStep = 1;&lt;br /&gt;
      var rawDefense = 120;&lt;br /&gt;
&lt;br /&gt;
      if (isPC(attacker)) {&lt;br /&gt;
        sungMahiFloor = attacker.sungMahiFloor;&lt;br /&gt;
        sungMahiStep = attacker.sungMahiStep;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (monster.rank === 5) {&lt;br /&gt;
        monster.level = 121;&lt;br /&gt;
        monster.dex = 75;&lt;br /&gt;
        rawDefense += 1;&lt;br /&gt;
      } else if (monster.rank === 6) {&lt;br /&gt;
        monster.level = 123;&lt;br /&gt;
        monster.dex = 75;&lt;br /&gt;
        rawDefense += 1;&lt;br /&gt;
      } else {&lt;br /&gt;
        monster.level = 120;&lt;br /&gt;
        monster.dex = 68;&lt;br /&gt;
      }&lt;br /&gt;
      monster.vit = 100;&lt;br /&gt;
      monster.rawDefense = rawDefense + (sungMahiStep - 1) * 6;&lt;br /&gt;
      monster.fistDefense = 0;&lt;br /&gt;
      monster.swordDefense = 0;&lt;br /&gt;
      monster.twoHandedSwordDefense = 0;&lt;br /&gt;
      monster.daggerDefense = 0;&lt;br /&gt;
      monster.bellDefense = 0;&lt;br /&gt;
      monster.fanDefense = 0;&lt;br /&gt;
      monster.arrowDefense = 0;&lt;br /&gt;
      monster.clawDefense = 0;&lt;br /&gt;
      monster.magicResistance = 0;&lt;br /&gt;
      monster.fireResistance = -20;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  // Alastor&lt;br /&gt;
  if (monster.vnum === 6790) {&lt;br /&gt;
    monster.iceResistance = 0;&lt;br /&gt;
    monster.iceBonus = 0;&lt;br /&gt;
    monster.lightningResistance = -10;&lt;br /&gt;
    monster.lightningBonus = 65;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createWeapon(vnum) {&lt;br /&gt;
  var weapon = copyObject(weaponData[vnum]);&lt;br /&gt;
  var serpentVnums = [360, 380, 1210, 2230, 3250, 5200, 6150, 7330];&lt;br /&gt;
  var weaponValues = weapon[1];&lt;br /&gt;
  var isSerpent = isValueInArray(Number(vnum), serpentVnums);&lt;br /&gt;
  var isSpecial = Array.isArray(weaponValues[0]);&lt;br /&gt;
  var isMagic;&lt;br /&gt;
&lt;br /&gt;
  if (isSpecial) {&lt;br /&gt;
    isMagic = weaponValues[0][1] &amp;gt; 0;&lt;br /&gt;
  } else {&lt;br /&gt;
    isMagic = weaponValues[1] &amp;gt; 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    type: weapon[0],&lt;br /&gt;
    maxUpgrade: weapon[2].length - 1,&lt;br /&gt;
    isSerpent: isSerpent,&lt;br /&gt;
    isMagic: isMagic,&lt;br /&gt;
    getValues: function (upgrade) {&lt;br /&gt;
      var currentWeaponValues = weaponValues;&lt;br /&gt;
&lt;br /&gt;
      if (upgrade === undefined) {&lt;br /&gt;
        // rare bug when weaponUpgrade is deleted&lt;br /&gt;
        console.warn(&amp;quot;WeaponUpgrade is missing.&amp;quot;);&lt;br /&gt;
        upgrade = this.maxUpgrade;&lt;br /&gt;
      }&lt;br /&gt;
      upgrade = Math.min(upgrade, this.maxUpgrade);&lt;br /&gt;
&lt;br /&gt;
      if (isSpecial) {&lt;br /&gt;
        currentWeaponValues = weaponValues[upgrade];&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      this.minAttackValue = currentWeaponValues[2];&lt;br /&gt;
      this.maxAttackValue = currentWeaponValues[3];&lt;br /&gt;
      this.minMagicAttackValue = currentWeaponValues[0];&lt;br /&gt;
      this.maxMagicAttackValue = currentWeaponValues[1];&lt;br /&gt;
      this.growth = weapon[2][upgrade];&lt;br /&gt;
    },&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createMonster(&lt;br /&gt;
  monsterVnum,&lt;br /&gt;
  translateMonster,&lt;br /&gt;
  attacker,&lt;br /&gt;
  polymorphMonster&lt;br /&gt;
) {&lt;br /&gt;
  var monsterAttributes = monsterData[monsterVnum];&lt;br /&gt;
&lt;br /&gt;
  var monster = {&lt;br /&gt;
    vnum: Number(monsterVnum),&lt;br /&gt;
    name: translateMonster&lt;br /&gt;
      ? getTranslatedMonsterName(monsterVnum)&lt;br /&gt;
      : monsterAttributes[36],&lt;br /&gt;
    rank: monsterAttributes[0],&lt;br /&gt;
    race: monsterAttributes[1],&lt;br /&gt;
    attack: monsterAttributes[2],&lt;br /&gt;
    level: monsterAttributes[3],&lt;br /&gt;
    type: monsterAttributes[4],&lt;br /&gt;
    str: monsterAttributes[5],&lt;br /&gt;
    dex: monsterAttributes[6],&lt;br /&gt;
    vit: monsterAttributes[7],&lt;br /&gt;
    int: monsterAttributes[8],&lt;br /&gt;
    minAttackValue: monsterAttributes[9],&lt;br /&gt;
    maxAttackValue: monsterAttributes[10],&lt;br /&gt;
    rawDefense: monsterAttributes[11],&lt;br /&gt;
    criticalHit: monsterAttributes[12],&lt;br /&gt;
    piercingHit: monsterAttributes[13],&lt;br /&gt;
    fistDefense: monsterAttributes[14],&lt;br /&gt;
    swordDefense: monsterAttributes[15],&lt;br /&gt;
    twoHandedSwordDefense: monsterAttributes[16],&lt;br /&gt;
    daggerDefense: monsterAttributes[17],&lt;br /&gt;
    bellDefense: monsterAttributes[18],&lt;br /&gt;
    fanDefense: monsterAttributes[19],&lt;br /&gt;
    arrowDefense: monsterAttributes[20],&lt;br /&gt;
    clawDefense: monsterAttributes[21],&lt;br /&gt;
    fireResistance: monsterAttributes[22],&lt;br /&gt;
    lightningResistance: monsterAttributes[23],&lt;br /&gt;
    magicResistance: monsterAttributes[24],&lt;br /&gt;
    windResistance: monsterAttributes[25],&lt;br /&gt;
    lightningBonus: monsterAttributes[26],&lt;br /&gt;
    fireBonus: monsterAttributes[27],&lt;br /&gt;
    iceBonus: monsterAttributes[28],&lt;br /&gt;
    windBonus: monsterAttributes[29],&lt;br /&gt;
    earthBonus: monsterAttributes[30],&lt;br /&gt;
    darknessBonus: monsterAttributes[31],&lt;br /&gt;
    darknessResistance: monsterAttributes[32],&lt;br /&gt;
    iceResistance: monsterAttributes[33],&lt;br /&gt;
    earthResistance: monsterAttributes[34],&lt;br /&gt;
    damageMultiplier: monsterAttributes[35],&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  // monster.instance = 0;&lt;br /&gt;
&lt;br /&gt;
  // if (attacker &amp;amp;&amp;amp; monster.instance === 0) {&lt;br /&gt;
  //   changeMonsterValues(monster, &amp;quot;SungMahiTower&amp;quot;, attacker);&lt;br /&gt;
  // }&lt;br /&gt;
  if (!polymorphMonster) {&lt;br /&gt;
    changeMonsterValues(monster);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  monster.defense = monster.rawDefense + monster.level + monster.vit;&lt;br /&gt;
&lt;br /&gt;
  return monster;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addPotentialErrorInformation(&lt;br /&gt;
  errorInformation,&lt;br /&gt;
  attacker,&lt;br /&gt;
  victim,&lt;br /&gt;
  skillType,&lt;br /&gt;
  characters&lt;br /&gt;
) {&lt;br /&gt;
  for (var error of Object.values(errorInformation)) {&lt;br /&gt;
    hideElement(error);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker)) {&lt;br /&gt;
    if (isRiding(attacker)) {&lt;br /&gt;
      if (attacker.horsePoint === 0) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;horse-level&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
      showElement(errorInformation[&amp;quot;horse-stat&amp;quot;]);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isPolymorph(attacker)) {&lt;br /&gt;
      if (attacker.polymorphPoint === 0) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;polymorph-level&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (&lt;br /&gt;
        (attacker.polymorphPoint &amp;lt;= 39 &amp;amp;&amp;amp; attacker.attackValuePercent &amp;lt;= 199) ||&lt;br /&gt;
        (attacker.polymorphPoint === 40 &amp;amp;&amp;amp; attacker.attackValuePercent &amp;lt;= 299)&lt;br /&gt;
      ) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;polymorph-bonus&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
    if (skillType === &amp;quot;magic&amp;quot;) {&lt;br /&gt;
      if (attacker.magicAttackValue) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;magic-attack-value-bonus&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
      if (victim.magicResistance) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;magic-resistance&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    showElement(errorInformation[&amp;quot;monster-attacker&amp;quot;]);&lt;br /&gt;
    if (isMagicAttacker(attacker) &amp;amp;&amp;amp; victim.magicResistance) {&lt;br /&gt;
      showElement(errorInformation[&amp;quot;magic-resistance&amp;quot;]);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (isPC(victim)) {&lt;br /&gt;
    if (isRiding(victim)) {&lt;br /&gt;
      showElement(errorInformation[&amp;quot;horse-stat&amp;quot;]);&lt;br /&gt;
    }&lt;br /&gt;
    if (isPolymorph(victim)) {&lt;br /&gt;
      if (attacker.polymorphPoint === 0) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;polymorph-level&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
      showElement(errorInformation[&amp;quot;polymorph-defense&amp;quot;]);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (characters.unsavedChanges) {&lt;br /&gt;
    showElement(errorInformation[&amp;quot;save&amp;quot;]);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function reduceChartPointsListener(battle) {&lt;br /&gt;
  var {&lt;br /&gt;
    reduceChartPointsContainer,&lt;br /&gt;
    reduceChartPoints,&lt;br /&gt;
    numberFormats: { second: numberFormat },&lt;br /&gt;
    displayTime,&lt;br /&gt;
  } = battle;&lt;br /&gt;
&lt;br /&gt;
  reduceChartPoints.addEventListener(&amp;quot;change&amp;quot;, function () {&lt;br /&gt;
    reduceChartPoints.disabled = true;&lt;br /&gt;
&lt;br /&gt;
    var startDisplayTime = performance.now();&lt;br /&gt;
    var scatterDataByType = battle.scatterDataByType;&lt;br /&gt;
    var {&lt;br /&gt;
      chart,&lt;br /&gt;
      maxPoints,&lt;br /&gt;
      chart: {&lt;br /&gt;
        data: { datasets },&lt;br /&gt;
      },&lt;br /&gt;
    } = battle.damageChart;&lt;br /&gt;
    var addAnimations = false;&lt;br /&gt;
&lt;br /&gt;
    for (var index = 0; index &amp;lt; datasets.length; index++) {&lt;br /&gt;
      var dataset = datasets[index];&lt;br /&gt;
      var scatterData = scatterDataByType[dataset.name];&lt;br /&gt;
&lt;br /&gt;
      if (dataset.canBeReduced &amp;amp;&amp;amp; reduceChartPoints.checked) {&lt;br /&gt;
        dataset.data = aggregateDamage(scatterData, maxPoints);&lt;br /&gt;
        addAnimations = true;&lt;br /&gt;
      } else {&lt;br /&gt;
        dataset.data = scatterData;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    handleChartAnimations(chart, addAnimations);&lt;br /&gt;
    chart.update();&lt;br /&gt;
&lt;br /&gt;
    displayTime.textContent = numberFormat.format(&lt;br /&gt;
      (performance.now() - startDisplayTime) / 1000&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    setTimeout(function () {&lt;br /&gt;
      reduceChartPoints.disabled = false;&lt;br /&gt;
    }, 1000);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  reduceChartPointsContainer.addEventListener(&amp;quot;pointerup&amp;quot;, function (event) {&lt;br /&gt;
    if (event.pointerType === &amp;quot;mouse&amp;quot;) {&lt;br /&gt;
      if (event.target.closest(&amp;quot;label&amp;quot;)) {&lt;br /&gt;
        return;&lt;br /&gt;
      }&lt;br /&gt;
      reduceChartPoints.click();&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function downloadRawDataListener(battle) {&lt;br /&gt;
  var { downLoadRawData, downLoadRawDataVariation } = battle;&lt;br /&gt;
  var fileType = &amp;quot;text/csv;charset=utf-8;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  downLoadRawData.addEventListener(&amp;quot;click&amp;quot;, function () {&lt;br /&gt;
    var damageWeightedByType = battle.damageWeightedByType;&lt;br /&gt;
    var filename = &amp;quot;raw_damage.csv&amp;quot;;&lt;br /&gt;
    var csvContent = &amp;quot;damage,probabilities,damageType\n&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    for (var damageType in damageWeightedByType) {&lt;br /&gt;
      var damageWeighted = damageWeightedByType[damageType];&lt;br /&gt;
&lt;br /&gt;
      for (var damage in damageWeighted) {&lt;br /&gt;
        csvContent +=&lt;br /&gt;
          damage + &amp;quot;,&amp;quot; + damageWeighted[damage] + &amp;quot;,&amp;quot; + damageType + &amp;quot;\n&amp;quot;;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    downloadData(csvContent, fileType, filename);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  downLoadRawDataVariation.addEventListener(&amp;quot;click&amp;quot;, function () {&lt;br /&gt;
    var damageByBonus = battle.damageByBonus;&lt;br /&gt;
    var damageByBonusLength = damageByBonus.length;&lt;br /&gt;
    var filename = &amp;quot;damage_variation.csv&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    if (!damageByBonusLength) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var csvContent =&lt;br /&gt;
      damageByBonus[damageByBonusLength - 1] + &amp;quot;,averageDamage\n&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    for (var index = 0; index &amp;lt; damageByBonusLength - 1; index++) {&lt;br /&gt;
      var row = damageByBonus[index];&lt;br /&gt;
&lt;br /&gt;
      csvContent += row.x + &amp;quot;,&amp;quot; + row.y + &amp;quot;\n&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    downloadData(csvContent, fileType, filename);&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function displayResults(&lt;br /&gt;
  attackValues,&lt;br /&gt;
  damageWeightedByType,&lt;br /&gt;
  battle,&lt;br /&gt;
  attackerName,&lt;br /&gt;
  victimName&lt;br /&gt;
) {&lt;br /&gt;
  var [meanDamage, minDamage, maxDamage, scatterDataByType, uniqueDamageCount] =&lt;br /&gt;
    prepareDamageData(damageWeightedByType, attackValues);&lt;br /&gt;
&lt;br /&gt;
  addToDamageChart(battle, scatterDataByType);&lt;br /&gt;
  updateDamageChartDescription(battle, uniqueDamageCount);&lt;br /&gt;
  displayFightResults(&lt;br /&gt;
    battle,&lt;br /&gt;
    attackerName,&lt;br /&gt;
    victimName,&lt;br /&gt;
    meanDamage,&lt;br /&gt;
    minDamage,&lt;br /&gt;
    maxDamage&lt;br /&gt;
  );&lt;br /&gt;
  battle.damageWeightedByType = damageWeightedByType;&lt;br /&gt;
  battle.scatterDataByType = scatterDataByType;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function displayFightResults(&lt;br /&gt;
  battle,&lt;br /&gt;
  attackerName,&lt;br /&gt;
  victimName,&lt;br /&gt;
  meanDamage,&lt;br /&gt;
  minDamage,&lt;br /&gt;
  maxDamage&lt;br /&gt;
) {&lt;br /&gt;
  var {&lt;br /&gt;
    tableResultFight,&lt;br /&gt;
    tableResultHistory,&lt;br /&gt;
    savedFights,&lt;br /&gt;
    numberFormats: { default: numberFormat },&lt;br /&gt;
    deleteFightTemplate,&lt;br /&gt;
  } = battle;&lt;br /&gt;
&lt;br /&gt;
  hideElement(tableResultHistory.rows[1]);&lt;br /&gt;
&lt;br /&gt;
  var valuesToDisplay = [&lt;br /&gt;
    attackerName,&lt;br /&gt;
    victimName,&lt;br /&gt;
    battle.battleChoice.attackType.selectedText,&lt;br /&gt;
    meanDamage,&lt;br /&gt;
    minDamage,&lt;br /&gt;
    maxDamage,&lt;br /&gt;
  ];&lt;br /&gt;
&lt;br /&gt;
  savedFights.push(valuesToDisplay);&lt;br /&gt;
  updateSavedFights(savedFights);&lt;br /&gt;
&lt;br /&gt;
  editTableResultRow(tableResultFight.rows[1], valuesToDisplay, numberFormat);&lt;br /&gt;
  addRowToTableResultHistory(&lt;br /&gt;
    tableResultHistory,&lt;br /&gt;
    valuesToDisplay,&lt;br /&gt;
    deleteFightTemplate,&lt;br /&gt;
    numberFormat&lt;br /&gt;
  );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function displayFightInfo(&lt;br /&gt;
  possibleDamageCount,&lt;br /&gt;
  damageTimeDuration,&lt;br /&gt;
  displayTimeDuration,&lt;br /&gt;
  battle&lt;br /&gt;
) {&lt;br /&gt;
  const {&lt;br /&gt;
    damageInfoContainer,&lt;br /&gt;
    numberFormats: { default: defaultFormat, second: secondFormat },&lt;br /&gt;
    possibleDamageCounter,&lt;br /&gt;
    damageTime,&lt;br /&gt;
    displayTime,&lt;br /&gt;
  } = battle;&lt;br /&gt;
&lt;br /&gt;
  if (possibleDamageCount &amp;lt;= 1) {&lt;br /&gt;
    hideElement(damageInfoContainer);&lt;br /&gt;
    return;&lt;br /&gt;
  } else {&lt;br /&gt;
    showElement(damageInfoContainer);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  possibleDamageCount = defaultFormat.format(possibleDamageCount);&lt;br /&gt;
  damageTimeDuration = secondFormat.format(damageTimeDuration / 1000);&lt;br /&gt;
  displayTimeDuration = secondFormat.format(displayTimeDuration / 1000);&lt;br /&gt;
&lt;br /&gt;
  possibleDamageCounter.textContent = possibleDamageCount;&lt;br /&gt;
  damageTime.textContent = damageTimeDuration;&lt;br /&gt;
  displayTime.textContent = displayTimeDuration;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function parseTypeAndName(data) {&lt;br /&gt;
  var [type, nameOrVnum] = splitFirst(data, &amp;quot;-&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    type: type,&lt;br /&gt;
    nameOrVnum: nameOrVnum,&lt;br /&gt;
    isCharacter: type === &amp;quot;character&amp;quot;,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isCharacterSelected(characterName, selected) {&lt;br /&gt;
  if (!selected) {&lt;br /&gt;
    return false;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var { nameOrVnum, isCharacter } = parseTypeAndName(selected);&lt;br /&gt;
&lt;br /&gt;
  return nameOrVnum === characterName &amp;amp;&amp;amp; isCharacter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function useBonusVariationMode(character, variation) {&lt;br /&gt;
  return (&lt;br /&gt;
    isChecked(character.useBonusVariation) &amp;amp;&amp;amp;&lt;br /&gt;
    character.hasOwnProperty(variation) &amp;amp;&amp;amp;&lt;br /&gt;
    character.bonusVariationMinValue &amp;lt; character.bonusVariationMaxValue&lt;br /&gt;
  );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createBattle(characters, battle) {&lt;br /&gt;
  var battleChoice = battle.battleChoice;&lt;br /&gt;
  var battleForm = battleChoice.form;&lt;br /&gt;
  var lastInvalidTime = 0;&lt;br /&gt;
&lt;br /&gt;
  battleForm.addEventListener(&amp;quot;change&amp;quot;, handleBattleFormChange);&lt;br /&gt;
  battleForm.addEventListener(&amp;quot;invalid&amp;quot;, handleBattleFormInvalid, true);&lt;br /&gt;
  battleForm.addEventListener(&amp;quot;submit&amp;quot;, handleBattleFormSubmit);&lt;br /&gt;
&lt;br /&gt;
  function handleBattleFormChange(event) {&lt;br /&gt;
    var target = event.target;&lt;br /&gt;
    var { name: targetName, value: targetValue, type: targetType } = target;&lt;br /&gt;
&lt;br /&gt;
    if (targetType !== &amp;quot;radio&amp;quot;) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (targetName === &amp;quot;attackType&amp;quot;) {&lt;br /&gt;
      battleChoice.attackType.selectedText =&lt;br /&gt;
        target.previousElementSibling.textContent;&lt;br /&gt;
    } else {&lt;br /&gt;
      updateBattleChoiceButton(battleChoice, targetName, targetValue);&lt;br /&gt;
&lt;br /&gt;
      if (targetName === &amp;quot;attacker&amp;quot;) {&lt;br /&gt;
        filterAttackTypeSelection(characters, battleChoice, targetValue);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function handleBattleFormInvalid(event) {&lt;br /&gt;
    var currentTime = Date.now();&lt;br /&gt;
&lt;br /&gt;
    if (currentTime - lastInvalidTime &amp;lt; 100) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    lastInvalidTime = currentTime;&lt;br /&gt;
&lt;br /&gt;
    var target = event.target;&lt;br /&gt;
    var modal = target.closest(&amp;quot;.modal&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (!modal) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var dataModal = modal.dataset.modal;&lt;br /&gt;
&lt;br /&gt;
    if (!dataModal) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var category = dataModal.split(&amp;quot;-&amp;quot;)[0];&lt;br /&gt;
&lt;br /&gt;
    if (isValueInArray(category, battleChoice.categories)) {&lt;br /&gt;
      battleChoice[category].button.click();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function handleBattleFormSubmit(event) {&lt;br /&gt;
    event.preventDefault();&lt;br /&gt;
&lt;br /&gt;
    // auto save&lt;br /&gt;
    if (characters.unsavedChanges) {&lt;br /&gt;
      characters.saveButton.click();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var battleInfo = new FormData(event.target);&lt;br /&gt;
    var attackerData = battleInfo.get(&amp;quot;attacker&amp;quot;);&lt;br /&gt;
    var attackType = battleInfo.get(&amp;quot;attackType&amp;quot;);&lt;br /&gt;
    var victimData = battleInfo.get(&amp;quot;victim&amp;quot;);&lt;br /&gt;
    var attackerVariation;&lt;br /&gt;
    var victimVariation;&lt;br /&gt;
&lt;br /&gt;
    if (!attackerData &amp;amp;&amp;amp; !attackType &amp;amp;&amp;amp; !victimData) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var { nameOrVnum: attackerNameOrVnum, isCharacter: attackerIsPlayer } =&lt;br /&gt;
      parseTypeAndName(attackerData);&lt;br /&gt;
    var { nameOrVnum: victimNameOrVnum, isCharacter: victimIsPlayer } =&lt;br /&gt;
      parseTypeAndName(victimData);&lt;br /&gt;
&lt;br /&gt;
    if (attackerIsPlayer) {&lt;br /&gt;
      var attacker = copyObject(characters.savedCharacters[attackerNameOrVnum]);&lt;br /&gt;
      attackerVariation = attacker.bonusVariation;&lt;br /&gt;
    } else {&lt;br /&gt;
      var attacker = createMonster(&lt;br /&gt;
        attackerNameOrVnum,&lt;br /&gt;
        characters.translateMonsters&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (victimIsPlayer) {&lt;br /&gt;
      var victim = copyObject(characters.savedCharacters[victimNameOrVnum]);&lt;br /&gt;
      victimVariation = victim.bonusVariation;&lt;br /&gt;
    } else {&lt;br /&gt;
      var victim = createMonster(&lt;br /&gt;
        victimNameOrVnum,&lt;br /&gt;
        characters.translateMonsters,&lt;br /&gt;
        attacker&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (useBonusVariationMode(attacker, attackerVariation)) {&lt;br /&gt;
      damageWithVariation(&lt;br /&gt;
        attacker,&lt;br /&gt;
        victim,&lt;br /&gt;
        attackType,&lt;br /&gt;
        battle,&lt;br /&gt;
        attacker,&lt;br /&gt;
        attackerVariation&lt;br /&gt;
      );&lt;br /&gt;
    } else if (useBonusVariationMode(victim, victimVariation)) {&lt;br /&gt;
      damageWithVariation(&lt;br /&gt;
        attacker,&lt;br /&gt;
        victim,&lt;br /&gt;
        attackType,&lt;br /&gt;
        battle,&lt;br /&gt;
        victim,&lt;br /&gt;
        victimVariation&lt;br /&gt;
      );&lt;br /&gt;
    } else {&lt;br /&gt;
      damageWithoutVariation(attacker, victim, attackType, battle, characters);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createMapping() {&lt;br /&gt;
  return {&lt;br /&gt;
    typeFlag: [&lt;br /&gt;
      &amp;quot;animalBonus&amp;quot;, // 0&lt;br /&gt;
      &amp;quot;humanBonus&amp;quot;, // 1&lt;br /&gt;
      &amp;quot;orcBonus&amp;quot;, // 2&lt;br /&gt;
      &amp;quot;mysticBonus&amp;quot;, // 3&lt;br /&gt;
      &amp;quot;undeadBonus&amp;quot;, // 4&lt;br /&gt;
      &amp;quot;insectBonus&amp;quot;, // 5&lt;br /&gt;
      &amp;quot;desertBonus&amp;quot;, // 6&lt;br /&gt;
      &amp;quot;devilBonus&amp;quot;, // 7&lt;br /&gt;
    ],&lt;br /&gt;
    raceBonus: {&lt;br /&gt;
      warrior: &amp;quot;warriorBonus&amp;quot;,&lt;br /&gt;
      sura: &amp;quot;suraBonus&amp;quot;,&lt;br /&gt;
      ninja: &amp;quot;ninjaBonus&amp;quot;,&lt;br /&gt;
      shaman: &amp;quot;shamanBonus&amp;quot;,&lt;br /&gt;
      lycan: &amp;quot;lycanBonus&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    raceResistance: {&lt;br /&gt;
      warrior: &amp;quot;warriorResistance&amp;quot;,&lt;br /&gt;
      sura: &amp;quot;suraResistance&amp;quot;,&lt;br /&gt;
      ninja: &amp;quot;ninjaResistance&amp;quot;,&lt;br /&gt;
      shaman: &amp;quot;shamanResistance&amp;quot;,&lt;br /&gt;
      lycan: &amp;quot;lycanResistance&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    defenseWeapon: [&lt;br /&gt;
      &amp;quot;swordDefense&amp;quot;, // 0&lt;br /&gt;
      &amp;quot;daggerDefense&amp;quot;, // 1&lt;br /&gt;
      &amp;quot;arrowDefense&amp;quot;, // 2&lt;br /&gt;
      &amp;quot;twoHandedSwordDefense&amp;quot;, // 3&lt;br /&gt;
      &amp;quot;bellDefense&amp;quot;, // 4&lt;br /&gt;
      &amp;quot;clawDefense&amp;quot;, // 5&lt;br /&gt;
      &amp;quot;fanDefense&amp;quot;, // 6&lt;br /&gt;
      &amp;quot;swordDefense&amp;quot;, // 7&lt;br /&gt;
      &amp;quot;fistDefense&amp;quot;, // 8&lt;br /&gt;
    ],&lt;br /&gt;
    breakWeapon: [&lt;br /&gt;
      &amp;quot;breakSwordDefense&amp;quot;, // 0&lt;br /&gt;
      &amp;quot;breakDaggerDefense&amp;quot;, // 1&lt;br /&gt;
      &amp;quot;breakArrowDefense&amp;quot;, // 2&lt;br /&gt;
      &amp;quot;breakTwoHandedSwordDefense&amp;quot;, // 3&lt;br /&gt;
      &amp;quot;breakBellDefense&amp;quot;, // 4&lt;br /&gt;
      &amp;quot;breakClawDefense&amp;quot;, // 5&lt;br /&gt;
      &amp;quot;breakFanDefense&amp;quot;, // 6&lt;br /&gt;
      &amp;quot;breakSwordDefense&amp;quot;, // 7&lt;br /&gt;
    ],&lt;br /&gt;
    elementBonus: [&lt;br /&gt;
      &amp;quot;fireBonus&amp;quot;, // 0&lt;br /&gt;
      &amp;quot;iceBonus&amp;quot;, // 1&lt;br /&gt;
      &amp;quot;windBonus&amp;quot;, // 2&lt;br /&gt;
      &amp;quot;lightningBonus&amp;quot;, // 3&lt;br /&gt;
      &amp;quot;earthBonus&amp;quot;, // 4&lt;br /&gt;
      &amp;quot;darknessBonus&amp;quot;, // 5&lt;br /&gt;
    ],&lt;br /&gt;
    elementResistance: [&lt;br /&gt;
      &amp;quot;fireResistance&amp;quot;, // 0&lt;br /&gt;
      &amp;quot;iceResistance&amp;quot;, // 1&lt;br /&gt;
      &amp;quot;windResistance&amp;quot;, // 2&lt;br /&gt;
      &amp;quot;lightningResistance&amp;quot;, // 3&lt;br /&gt;
      &amp;quot;earthResistance&amp;quot;, // 4&lt;br /&gt;
      &amp;quot;darknessResistance&amp;quot;, // 5&lt;br /&gt;
    ],&lt;br /&gt;
    attackType: [&lt;br /&gt;
      &amp;quot;normalHit&amp;quot;,&lt;br /&gt;
      &amp;quot;criticalHit&amp;quot;,&lt;br /&gt;
      &amp;quot;piercingHit&amp;quot;,&lt;br /&gt;
      &amp;quot;criticalPiercingHit&amp;quot;,&lt;br /&gt;
    ],&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createConstants() {&lt;br /&gt;
  var constants = {&lt;br /&gt;
    polymorphPowerTable: [&lt;br /&gt;
      10, 11, 11, 12, 13, 13, 14, 15, 16, 17, 18, 19, 20, 22, 23, 24, 26, 27,&lt;br /&gt;
      29, 31, 33, 35, 37, 39, 41, 44, 46, 49, 52, 55, 59, 62, 66, 70, 74, 79,&lt;br /&gt;
      84, 89, 94, 100, 0,&lt;br /&gt;
    ],&lt;br /&gt;
    skillPowerTable: [&lt;br /&gt;
      0, 0.05, 0.06, 0.08, 0.1, 0.12, 0.14, 0.16, 0.18, 0.2, 0.22, 0.24, 0.26,&lt;br /&gt;
      0.28, 0.3, 0.32, 0.34, 0.36, 0.38, 0.4, 0.5, 0.52, 0.54, 0.56, 0.58, 0.6,&lt;br /&gt;
      0.63, 0.66, 0.69, 0.72, 0.82, 0.85, 0.88, 0.91, 0.94, 0.98, 1.02, 1.06,&lt;br /&gt;
      1.1, 1.15, 1.25,&lt;br /&gt;
    ],&lt;br /&gt;
    marriageTable: {&lt;br /&gt;
      harmonyEarrings: [4, 5, 6, 8],&lt;br /&gt;
      loveEarrings: [4, 5, 6, 8],&lt;br /&gt;
      harmonyBracelet: [4, 5, 6, 8],&lt;br /&gt;
      loveNecklace: [20, 25, 30, 40],&lt;br /&gt;
      harmonyNecklace: [12, 16, 20, 30],&lt;br /&gt;
    },&lt;br /&gt;
    allowedWeaponsPerRace: {&lt;br /&gt;
      warrior: [0, 3, 8],&lt;br /&gt;
      ninja: [0, 1, 2, 8],&lt;br /&gt;
      sura: [0, 7, 8],&lt;br /&gt;
      shaman: [4, 6, 8],&lt;br /&gt;
      lycan: [5, 8],&lt;br /&gt;
    },&lt;br /&gt;
  };&lt;br /&gt;
  return constants;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initResultTableHistory(battle) {&lt;br /&gt;
  var {&lt;br /&gt;
    tableResultHistory,&lt;br /&gt;
    savedFights,&lt;br /&gt;
    deleteFightTemplate,&lt;br /&gt;
    numberFormats: { default: numberFormat },&lt;br /&gt;
  } = battle;&lt;br /&gt;
  var startIndex = 3;&lt;br /&gt;
&lt;br /&gt;
  if (savedFights.length) {&lt;br /&gt;
    hideElement(tableResultHistory.rows[1]);&lt;br /&gt;
&lt;br /&gt;
    for (var savedFight of savedFights) {&lt;br /&gt;
      addRowToTableResultHistory(&lt;br /&gt;
        tableResultHistory,&lt;br /&gt;
        savedFight,&lt;br /&gt;
        deleteFightTemplate,&lt;br /&gt;
        numberFormat&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  tableResultHistory.addEventListener(&amp;quot;click&amp;quot;, function (event) {&lt;br /&gt;
    var deleteButton = event.target.closest(&amp;quot;.svg-icon-delete&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (deleteButton) {&lt;br /&gt;
      var row = deleteButton.closest(&amp;quot;tr&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
      if (row) {&lt;br /&gt;
        savedFights.splice(row.rowIndex - startIndex, 1);&lt;br /&gt;
        updateSavedFights(savedFights);&lt;br /&gt;
&lt;br /&gt;
        row.remove();&lt;br /&gt;
&lt;br /&gt;
        if (tableResultHistory.rows.length === startIndex) {&lt;br /&gt;
          showElement(tableResultHistory.rows[1]);&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initDamageChart(battle, currentLanguage, defaultText) {&lt;br /&gt;
  const { reduceChartPointsContainer, reduceChartPoints } = battle;&lt;br /&gt;
  const { default: defaultFormat, percent: percentFormat } =&lt;br /&gt;
    battle.numberFormats;&lt;br /&gt;
  const customPlugins = {&lt;br /&gt;
    id: &amp;quot;customPlugins&amp;quot;,&lt;br /&gt;
    afterDraw(chart) {&lt;br /&gt;
      const missPercentage = chart.data.missPercentage;&lt;br /&gt;
&lt;br /&gt;
      if (!missPercentage) {&lt;br /&gt;
        return;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      const {&lt;br /&gt;
        ctx,&lt;br /&gt;
        chartArea: { top, right },&lt;br /&gt;
      } = chart;&lt;br /&gt;
      ctx.save();&lt;br /&gt;
      const text =&lt;br /&gt;
        defaultText.miss + &amp;quot; : &amp;quot; + percentFormat.format(missPercentage);&lt;br /&gt;
      const padding = 4;&lt;br /&gt;
      const fontSize = 14;&lt;br /&gt;
&lt;br /&gt;
      ctx.font = fontSize + &amp;quot;px Helvetica Neue&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
      const textWidth = ctx.measureText(text).width;&lt;br /&gt;
      const xPosition = right - textWidth - 5;&lt;br /&gt;
      const yPosition = top + 5;&lt;br /&gt;
&lt;br /&gt;
      ctx.fillStyle = &amp;quot;rgba(255, 0, 0, 0.2)&amp;quot;;&lt;br /&gt;
      ctx.fillRect(&lt;br /&gt;
        xPosition - padding,&lt;br /&gt;
        yPosition - padding,&lt;br /&gt;
        textWidth + 2 * padding,&lt;br /&gt;
        fontSize + 2 * padding&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      ctx.strokeStyle = &amp;quot;red&amp;quot;;&lt;br /&gt;
      ctx.strokeRect(&lt;br /&gt;
        xPosition - padding,&lt;br /&gt;
        yPosition - padding,&lt;br /&gt;
        textWidth + 2 * padding,&lt;br /&gt;
        fontSize + 2 * padding&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      ctx.fillStyle = &amp;quot;#666&amp;quot;;&lt;br /&gt;
      ctx.textBaseline = &amp;quot;top&amp;quot;;&lt;br /&gt;
      ctx.fillText(text, xPosition, yPosition + 1);&lt;br /&gt;
&lt;br /&gt;
      ctx.restore();&lt;br /&gt;
    },&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  Chart.register(customPlugins);&lt;br /&gt;
&lt;br /&gt;
  const ctx = battle.plotDamage.getContext(&amp;quot;2d&amp;quot;);&lt;br /&gt;
  const maxLabelsInTooltip = 10;&lt;br /&gt;
  const nullLabelText = &amp;quot; ...&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  const chart = new Chart(ctx, {&lt;br /&gt;
    type: &amp;quot;scatter&amp;quot;,&lt;br /&gt;
    data: {&lt;br /&gt;
      missPercentage: 0,&lt;br /&gt;
      datasets: [],&lt;br /&gt;
    },&lt;br /&gt;
    options: {&lt;br /&gt;
      locale: currentLanguage,&lt;br /&gt;
      responsive: true,&lt;br /&gt;
      maintainAspectRatio: false,&lt;br /&gt;
      plugins: {&lt;br /&gt;
        legend: {&lt;br /&gt;
          display: true,&lt;br /&gt;
          onHover: function (e) {&lt;br /&gt;
            e.native.target.style.cursor = &amp;quot;pointer&amp;quot;;&lt;br /&gt;
          },&lt;br /&gt;
          onLeave: function (e) {&lt;br /&gt;
            e.native.target.style.cursor = &amp;quot;default&amp;quot;;&lt;br /&gt;
          },&lt;br /&gt;
          onClick: function (e, legendItem, legend) {&lt;br /&gt;
            const currentIndex = legendItem.datasetIndex;&lt;br /&gt;
            const ci = legend.chart;&lt;br /&gt;
            const isCurrentDatasetVisible = ci.isDatasetVisible(currentIndex);&lt;br /&gt;
            const datasets = ci.data.datasets;&lt;br /&gt;
            const isReducePointsChecked = reduceChartPoints.checked;&lt;br /&gt;
            let hideReducePoints = true;&lt;br /&gt;
&lt;br /&gt;
            datasets[currentIndex].hidden = isCurrentDatasetVisible;&lt;br /&gt;
            legendItem.hidden = isCurrentDatasetVisible;&lt;br /&gt;
&lt;br /&gt;
            for (const index in datasets) {&lt;br /&gt;
              if (ci.isDatasetVisible(index) &amp;amp;&amp;amp; datasets[index].canBeReduced) {&lt;br /&gt;
                showElement(reduceChartPointsContainer);&lt;br /&gt;
                hideReducePoints = false;&lt;br /&gt;
                break;&lt;br /&gt;
              }&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            if (hideReducePoints) {&lt;br /&gt;
              hideElement(reduceChartPointsContainer);&lt;br /&gt;
              handleChartAnimations(ci, true);&lt;br /&gt;
            } else {&lt;br /&gt;
              handleChartAnimations(ci, isReducePointsChecked);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            ci.update();&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        title: {&lt;br /&gt;
          display: true,&lt;br /&gt;
          text: defaultText.damageRepartition,&lt;br /&gt;
          font: {&lt;br /&gt;
            size: 20,&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        tooltip: {&lt;br /&gt;
          callbacks: {&lt;br /&gt;
            label: function (context) {&lt;br /&gt;
              if (context.label === null) {&lt;br /&gt;
                return nullLabelText;&lt;br /&gt;
              }&lt;br /&gt;
&lt;br /&gt;
              const xValue = defaultFormat.format(context.parsed.x);&lt;br /&gt;
              const yValue = defaultFormat.format(context.parsed.y);&lt;br /&gt;
              const label =&lt;br /&gt;
                &amp;quot; &amp;quot; +&lt;br /&gt;
                context.dataset.label +&lt;br /&gt;
                &amp;quot; : (&amp;quot; +&lt;br /&gt;
                xValue +&lt;br /&gt;
                &amp;quot;, &amp;quot; +&lt;br /&gt;
                yValue +&lt;br /&gt;
                &amp;quot;)&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
              return label;&lt;br /&gt;
            },&lt;br /&gt;
            beforeBody: function (tooltipItems) {&lt;br /&gt;
              if (tooltipItems.length &amp;gt; maxLabelsInTooltip + 1) {&lt;br /&gt;
                tooltipItems.splice(maxLabelsInTooltip + 1);&lt;br /&gt;
                tooltipItems[maxLabelsInTooltip].label = null;&lt;br /&gt;
              }&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          caretPadding: 10,&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
      scales: {&lt;br /&gt;
        x: {&lt;br /&gt;
          type: &amp;quot;linear&amp;quot;,&lt;br /&gt;
          position: &amp;quot;bottom&amp;quot;,&lt;br /&gt;
          title: {&lt;br /&gt;
            display: true,&lt;br /&gt;
            text: defaultText.damage,&lt;br /&gt;
            font: {&lt;br /&gt;
              size: 16,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          ticks: {&lt;br /&gt;
            callback: function (value) {&lt;br /&gt;
              return Number.isInteger(value) ? value : &amp;quot;&amp;quot;;&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        y: {&lt;br /&gt;
          title: {&lt;br /&gt;
            display: true,&lt;br /&gt;
            text: defaultText.percentage,&lt;br /&gt;
            font: {&lt;br /&gt;
              size: 16,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          ticks: {&lt;br /&gt;
            format: {&lt;br /&gt;
              style: &amp;quot;percent&amp;quot;,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
      elements: {&lt;br /&gt;
        point: {&lt;br /&gt;
          borderWidth: 1,&lt;br /&gt;
          radius: 3,&lt;br /&gt;
          hitRadius: 3,&lt;br /&gt;
          hoverRadius: 6,&lt;br /&gt;
          hoverBorderWidth: 2,&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
    },&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  const datasetsStyle = [&lt;br /&gt;
    {&lt;br /&gt;
      name: &amp;quot;normalHit&amp;quot;,&lt;br /&gt;
      canBeReduced: false,&lt;br /&gt;
      label: defaultText.normalHit,&lt;br /&gt;
      backgroundColor: &amp;quot;rgba(75, 192, 192, 0.2)&amp;quot;,&lt;br /&gt;
      borderColor: &amp;quot;rgba(75, 192, 192, 1)&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      name: &amp;quot;piercingHit&amp;quot;,&lt;br /&gt;
      canBeReduced: false,&lt;br /&gt;
      label: defaultText.piercingHit,&lt;br /&gt;
      backgroundColor: &amp;quot;rgba(192, 192, 75, 0.2)&amp;quot;,&lt;br /&gt;
      borderColor: &amp;quot;rgba(192, 192, 75, 1)&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      name: &amp;quot;criticalHit&amp;quot;,&lt;br /&gt;
      canBeReduced: false,&lt;br /&gt;
      label: defaultText.criticalHit,&lt;br /&gt;
      backgroundColor: &amp;quot;rgba(192, 75, 192, 0.2)&amp;quot;,&lt;br /&gt;
      borderColor: &amp;quot;rgba(192, 75, 192, 1)&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      name: &amp;quot;criticalPiercingHit&amp;quot;,&lt;br /&gt;
      canBeReduced: false,&lt;br /&gt;
      label: defaultText.criticalPiercingHit,&lt;br /&gt;
      backgroundColor: &amp;quot;rgba(75, 75, 192, 0.2)&amp;quot;,&lt;br /&gt;
      borderColor: &amp;quot;rgba(75, 75, 192, 1)&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
  ];&lt;br /&gt;
  battle.damageChart = {&lt;br /&gt;
    chart: chart,&lt;br /&gt;
    datasetsStyle: datasetsStyle,&lt;br /&gt;
    maxPoints: 500,&lt;br /&gt;
    reduceChartPointsContainer: reduceChartPointsContainer,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initBonusVariationChart(battle, currentLanguage, defaultText) {&lt;br /&gt;
  const { plotBonusVariation } = battle;&lt;br /&gt;
&lt;br /&gt;
  const ctx = plotBonusVariation.getContext(&amp;quot;2d&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  const chart = new Chart(ctx, {&lt;br /&gt;
    type: &amp;quot;line&amp;quot;,&lt;br /&gt;
    data: {&lt;br /&gt;
      datasets: [&lt;br /&gt;
        {&lt;br /&gt;
          label: defaultText.averageDamage,&lt;br /&gt;
          backgroundColor: &amp;quot;rgba(75, 192, 192, 0.2)&amp;quot;,&lt;br /&gt;
          borderColor: &amp;quot;rgba(75, 192, 192, 1)&amp;quot;,&lt;br /&gt;
          fill: true,&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          label: defaultText.damageAugmentation,&lt;br /&gt;
          backgroundColor: &amp;quot;rgba(192, 192, 75, 0.2)&amp;quot;,&lt;br /&gt;
          borderColor: &amp;quot;rgba(192, 192, 75, 1)&amp;quot;,&lt;br /&gt;
          hidden: true,&lt;br /&gt;
          yTicksFormat: { style: &amp;quot;percent&amp;quot; },&lt;br /&gt;
          fill: true,&lt;br /&gt;
        },&lt;br /&gt;
      ],&lt;br /&gt;
    },&lt;br /&gt;
    options: {&lt;br /&gt;
      locale: currentLanguage,&lt;br /&gt;
      responsive: true,&lt;br /&gt;
      maintainAspectRatio: false,&lt;br /&gt;
      plugins: {&lt;br /&gt;
        legend: {&lt;br /&gt;
          display: true,&lt;br /&gt;
          onHover: function (e) {&lt;br /&gt;
            e.native.target.style.cursor = &amp;quot;pointer&amp;quot;;&lt;br /&gt;
          },&lt;br /&gt;
          onLeave: function (e) {&lt;br /&gt;
            e.native.target.style.cursor = &amp;quot;default&amp;quot;;&lt;br /&gt;
          },&lt;br /&gt;
          onClick: function (e, legendItem, legend) {&lt;br /&gt;
            var currentIndex = legendItem.datasetIndex;&lt;br /&gt;
            var ci = legend.chart;&lt;br /&gt;
            var datasets = ci.data.datasets;&lt;br /&gt;
            var isCurrentDatasetVisible = ci.isDatasetVisible(currentIndex);&lt;br /&gt;
            var yAxis = ci.options.scales.y;&lt;br /&gt;
&lt;br /&gt;
            var otherIndex = currentIndex === 0 ? 1 : 0;&lt;br /&gt;
            var visibleDataset = isCurrentDatasetVisible&lt;br /&gt;
              ? datasets[otherIndex]&lt;br /&gt;
              : datasets[currentIndex];&lt;br /&gt;
&lt;br /&gt;
            datasets[currentIndex].hidden = isCurrentDatasetVisible;&lt;br /&gt;
            datasets[otherIndex].hidden = !isCurrentDatasetVisible;&lt;br /&gt;
&lt;br /&gt;
            yAxis.title.text = visibleDataset.label;&lt;br /&gt;
            yAxis.ticks.format = visibleDataset.yTicksFormat;&lt;br /&gt;
&lt;br /&gt;
            ci.update();&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        title: {&lt;br /&gt;
          display: true,&lt;br /&gt;
          text: defaultText.bonusVariationTitle.split(&amp;quot;[[]]&amp;quot;),&lt;br /&gt;
          font: {&lt;br /&gt;
            size: 18,&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        tooltip: {&lt;br /&gt;
          caretPadding: 10,&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
      scales: {&lt;br /&gt;
        x: {&lt;br /&gt;
          type: &amp;quot;linear&amp;quot;,&lt;br /&gt;
          position: &amp;quot;bottom&amp;quot;,&lt;br /&gt;
          title: {&lt;br /&gt;
            display: true,&lt;br /&gt;
            text: &amp;quot;Bonus&amp;quot;,&lt;br /&gt;
            font: {&lt;br /&gt;
              size: 16,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          ticks: {&lt;br /&gt;
            callback: function (value) {&lt;br /&gt;
              if (Number.isInteger(value)) {&lt;br /&gt;
                return Number(value);&lt;br /&gt;
              }&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        y: {&lt;br /&gt;
          title: {&lt;br /&gt;
            display: true,&lt;br /&gt;
            text: defaultText.averageDamage,&lt;br /&gt;
            font: {&lt;br /&gt;
              size: 16,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
      elements: {&lt;br /&gt;
        point: {&lt;br /&gt;
          borderWidth: 1,&lt;br /&gt;
          radius: 3,&lt;br /&gt;
          hitRadius: 3,&lt;br /&gt;
          hoverRadius: 6,&lt;br /&gt;
          hoverBorderWidth: 2,&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
    },&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  battle.bonusVariationChart = chart;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterAttackTypeSelection(characters, battleChoice, targetValue) {&lt;br /&gt;
  var { nameOrVnum: attackerNameOrVnum, isCharacter: isAttackerPlayer } =&lt;br /&gt;
    parseTypeAndName(targetValue);&lt;br /&gt;
&lt;br /&gt;
  if (isAttackerPlayer) {&lt;br /&gt;
    var attacker = characters.savedCharacters[attackerNameOrVnum];&lt;br /&gt;
    filterAttackTypeSelectionCharacter(attacker, battleChoice.attackType);&lt;br /&gt;
  } else {&lt;br /&gt;
    filterAttackTypeSelectionMonster(battleChoice.attackType);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addBattleData(battle) {&lt;br /&gt;
  var errorElements = document.querySelectorAll(&amp;quot;[data-error]&amp;quot;);&lt;br /&gt;
  var { elements: attackTypeElements, container: attackTypeContainer } =&lt;br /&gt;
    battle.battleChoice.attackType;&lt;br /&gt;
  var attackTypeChilds = attackTypeContainer.children;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; errorElements.length; index++) {&lt;br /&gt;
    var errorElement = errorElements[index];&lt;br /&gt;
    battle.errorInformation[errorElement.dataset.error] = errorElement;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (var index = 1; index &amp;lt; attackTypeChilds.length - 1; index++) {&lt;br /&gt;
    var attackTypeChild = attackTypeChilds[index];&lt;br /&gt;
    var input = attackTypeChild.querySelector(&amp;quot;input&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    attackTypeElements.push({&lt;br /&gt;
      container: attackTypeChild,&lt;br /&gt;
      input: input,&lt;br /&gt;
      inputClass: input.dataset.class,&lt;br /&gt;
      inputValue: input.value,&lt;br /&gt;
    });&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createDamageCalculatorInformation(&lt;br /&gt;
  defaultLang,&lt;br /&gt;
  currentLanguage,&lt;br /&gt;
  defaultText&lt;br /&gt;
) {&lt;br /&gt;
  const characters = {&lt;br /&gt;
    unsavedChanges: false,&lt;br /&gt;
    savedCharacters: {},&lt;br /&gt;
    currentCharacter: null,&lt;br /&gt;
    savedMonsters: getSavedMonsters(),&lt;br /&gt;
    monsterElements: {},&lt;br /&gt;
    characterCreation: document.getElementById(&amp;quot;character-creation&amp;quot;),&lt;br /&gt;
    addNewCharacterButton: document.getElementById(&amp;quot;add-new-character&amp;quot;),&lt;br /&gt;
    dropZone: document.getElementById(&amp;quot;character-drop-zone&amp;quot;),&lt;br /&gt;
    characterInput: document.getElementById(&amp;quot;character-input&amp;quot;),&lt;br /&gt;
    newCharacterTemplate: document.getElementById(&amp;quot;new-character-template&amp;quot;)&lt;br /&gt;
      .children[0],&lt;br /&gt;
    charactersContainer: document.getElementById(&amp;quot;characters-container&amp;quot;),&lt;br /&gt;
    monsterButtonTemplates: document.getElementById(&amp;quot;monster-button-templates&amp;quot;),&lt;br /&gt;
    monsterTemplate: document.getElementById(&amp;quot;new-monster-template&amp;quot;)&lt;br /&gt;
      .children[0],&lt;br /&gt;
    monstersContainer: document.getElementById(&amp;quot;monsters-container&amp;quot;),&lt;br /&gt;
    monsteriFrame: document.getElementById(&amp;quot;monster-iframe&amp;quot;),&lt;br /&gt;
    stoneiFrame: document.getElementById(&amp;quot;stone-iframe&amp;quot;),&lt;br /&gt;
    saveButton: document.getElementById(&amp;quot;save-character&amp;quot;),&lt;br /&gt;
    weaponCategory: document.getElementById(&amp;quot;weapon-category&amp;quot;),&lt;br /&gt;
    weaponDisplay: document.getElementById(&amp;quot;weapon-display&amp;quot;),&lt;br /&gt;
    randomAttackValue: document.getElementById(&amp;quot;random-attack-value&amp;quot;),&lt;br /&gt;
    randomMagicAttackValue: document.getElementById(&lt;br /&gt;
      &amp;quot;random-magic-attack-value&amp;quot;&lt;br /&gt;
    ),&lt;br /&gt;
    toggleSiblings: {},&lt;br /&gt;
    polymorphDisplay: document.getElementById(&amp;quot;polymorph-display&amp;quot;),&lt;br /&gt;
    bonusVariation: {&lt;br /&gt;
      tabButton: document.getElementById(&amp;quot;Variation&amp;quot;),&lt;br /&gt;
      checkbox: document.getElementById(&amp;quot;use-bonus-variation&amp;quot;),&lt;br /&gt;
      input: document.getElementById(&amp;quot;bonus-variation&amp;quot;),&lt;br /&gt;
      inputName: document.getElementById(&amp;quot;bonus-variation-name&amp;quot;),&lt;br /&gt;
      container: document.getElementById(&amp;quot;bonus-variation-creation&amp;quot;),&lt;br /&gt;
      minValue: document.getElementById(&amp;quot;bonus-variation-min-value&amp;quot;),&lt;br /&gt;
      maxValue: document.getElementById(&amp;quot;bonus-variation-max-value&amp;quot;),&lt;br /&gt;
      disabledText: document.getElementById(&amp;quot;bonus-variation-disabled&amp;quot;),&lt;br /&gt;
      selectedText: document.getElementById(&amp;quot;bonus-variation-selected&amp;quot;),&lt;br /&gt;
      displaySpan: document.getElementById(&amp;quot;bonus-variation-display&amp;quot;),&lt;br /&gt;
    },&lt;br /&gt;
    skillElementsToFilter: document.querySelectorAll(&lt;br /&gt;
      &amp;quot;#skill-container [data-class]&amp;quot;&lt;br /&gt;
    ),&lt;br /&gt;
    currentLanguage: currentLanguage,&lt;br /&gt;
    translateMonsters: defaultLang !== currentLanguage,&lt;br /&gt;
    defaultText: defaultText,&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  for (const [pseudo, character] of Object.entries(getSavedCharacters())) {&lt;br /&gt;
    characters.savedCharacters[pseudo] = character;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  document.querySelectorAll(&amp;quot;.toggle-sibling&amp;quot;).forEach(function (element) {&lt;br /&gt;
    const target = element.dataset.target;&lt;br /&gt;
    const sibling = document.getElementById(target);&lt;br /&gt;
    characters.toggleSiblings[element.name] = sibling;&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  const constants = createConstants();&lt;br /&gt;
&lt;br /&gt;
  const battle = {&lt;br /&gt;
    savedFights: getSavedFights(),&lt;br /&gt;
    battleChoice: {&lt;br /&gt;
      resetAttackType: false,&lt;br /&gt;
      form: document.getElementById(&amp;quot;create-battle&amp;quot;),&lt;br /&gt;
      template: document.getElementById(&amp;quot;battle-selection-template&amp;quot;)&lt;br /&gt;
        .children[0],&lt;br /&gt;
      raceToImage: {&lt;br /&gt;
        warrior: &amp;quot;/images/0/0f/Bandeaurougehomme.png&amp;quot;,&lt;br /&gt;
        ninja: &amp;quot;/images/0/0e/Queuedechevalclair.png&amp;quot;,&lt;br /&gt;
        sura: &amp;quot;/images/3/37/Couperespectablerouge.png&amp;quot;,&lt;br /&gt;
        shaman: &amp;quot;/images/6/6a/Coupeeleganteclairfemme.png&amp;quot;,&lt;br /&gt;
        lycan: &amp;quot;/images/4/4e/Protectionfrontalerouge.png&amp;quot;,&lt;br /&gt;
      },&lt;br /&gt;
      categories: [&amp;quot;attacker&amp;quot;, &amp;quot;victim&amp;quot;],&lt;br /&gt;
      translateMonsters: defaultLang !== currentLanguage,&lt;br /&gt;
      attacker: {&lt;br /&gt;
        character: {&lt;br /&gt;
          count: 0,&lt;br /&gt;
          container: document.getElementById(&amp;quot;attacker-selection-characters&amp;quot;),&lt;br /&gt;
          elements: {},&lt;br /&gt;
        },&lt;br /&gt;
        monster: {&lt;br /&gt;
          count: 0,&lt;br /&gt;
          container: document.getElementById(&amp;quot;attacker-selection-monsters&amp;quot;),&lt;br /&gt;
          elements: {},&lt;br /&gt;
        },&lt;br /&gt;
        button: document.getElementById(&amp;quot;attacker-trigger&amp;quot;),&lt;br /&gt;
        defaultButtonContent: document.getElementById(&lt;br /&gt;
          &amp;quot;attacker-default-button-content&amp;quot;&lt;br /&gt;
        ),&lt;br /&gt;
        buttonContent: document.getElementById(&amp;quot;attacker-button-content&amp;quot;),&lt;br /&gt;
        container: document.getElementById(&amp;quot;attacker-selection&amp;quot;),&lt;br /&gt;
        selected: null,&lt;br /&gt;
      },&lt;br /&gt;
      victim: {&lt;br /&gt;
        character: {&lt;br /&gt;
          count: 0,&lt;br /&gt;
          container: document.getElementById(&amp;quot;victim-selection-characters&amp;quot;),&lt;br /&gt;
          elements: {},&lt;br /&gt;
        },&lt;br /&gt;
        monster: {&lt;br /&gt;
          count: 0,&lt;br /&gt;
          container: document.getElementById(&amp;quot;victim-selection-monsters&amp;quot;),&lt;br /&gt;
          elements: {},&lt;br /&gt;
        },&lt;br /&gt;
        stone: {&lt;br /&gt;
          count: 0,&lt;br /&gt;
          container: document.getElementById(&amp;quot;victim-selection-stones&amp;quot;),&lt;br /&gt;
          elements: {},&lt;br /&gt;
        },&lt;br /&gt;
        button: document.getElementById(&amp;quot;victim-trigger&amp;quot;),&lt;br /&gt;
        defaultButtonContent: document.getElementById(&lt;br /&gt;
          &amp;quot;victim-default-button-content&amp;quot;&lt;br /&gt;
        ),&lt;br /&gt;
        buttonContent: document.getElementById(&amp;quot;victim-button-content&amp;quot;),&lt;br /&gt;
        selected: null,&lt;br /&gt;
      },&lt;br /&gt;
      attackType: {&lt;br /&gt;
        container: document.getElementById(&amp;quot;attack-type-selection&amp;quot;),&lt;br /&gt;
        elements: [],&lt;br /&gt;
        defaultInput: document.getElementById(&amp;quot;physical-attack&amp;quot;),&lt;br /&gt;
        selectedText: &amp;quot;&amp;quot;,&lt;br /&gt;
      },&lt;br /&gt;
    },&lt;br /&gt;
    damageWeightedByType: {},&lt;br /&gt;
    scatterDataByType: {},&lt;br /&gt;
    damageByBonus: [],&lt;br /&gt;
    tableResultFight: document.getElementById(&amp;quot;result-table-fight&amp;quot;),&lt;br /&gt;
    tableResultHistory: document.getElementById(&amp;quot;result-table-history&amp;quot;),&lt;br /&gt;
    deleteFightTemplate: document.getElementById(&amp;quot;delete-fight-template&amp;quot;)&lt;br /&gt;
      .children[0],&lt;br /&gt;
    errorInformation: {},&lt;br /&gt;
    fightResultTitle: document.getElementById(&amp;quot;fight-result-title&amp;quot;),&lt;br /&gt;
    fightResultContainer: document.getElementById(&amp;quot;fight-result-container&amp;quot;),&lt;br /&gt;
    downLoadRawData: document.getElementById(&amp;quot;download-raw-data&amp;quot;),&lt;br /&gt;
    downLoadRawDataVariation: document.getElementById(&lt;br /&gt;
      &amp;quot;download-raw-data-variation&amp;quot;&lt;br /&gt;
    ),&lt;br /&gt;
    bonusVariationResultContainer: document.getElementById(&lt;br /&gt;
      &amp;quot;bonus-variation-result-container&amp;quot;&lt;br /&gt;
    ),&lt;br /&gt;
    reduceChartPointsContainer: document.getElementById(&lt;br /&gt;
      &amp;quot;reduce-chart-points-container&amp;quot;&lt;br /&gt;
    ),&lt;br /&gt;
    reduceChartPoints: document.getElementById(&amp;quot;reduce-chart-points&amp;quot;),&lt;br /&gt;
    plotDamage: document.getElementById(&amp;quot;plot-damage&amp;quot;),&lt;br /&gt;
    plotBonusVariation: document.getElementById(&amp;quot;plot-bonus-variation&amp;quot;),&lt;br /&gt;
    chartDescriptionContainer: document.getElementById(&lt;br /&gt;
      &amp;quot;chart-description-container&amp;quot;&lt;br /&gt;
    ),&lt;br /&gt;
    damageInfoContainer: document.getElementById(&amp;quot;damage-info-container&amp;quot;),&lt;br /&gt;
    uniqueDamageCounters: document.querySelectorAll(&amp;quot;.unique-damage-counter&amp;quot;),&lt;br /&gt;
    possibleDamageCounter: document.getElementById(&amp;quot;possible-damage-counter&amp;quot;),&lt;br /&gt;
    damageTime: document.getElementById(&amp;quot;damage-time&amp;quot;),&lt;br /&gt;
    displayTime: document.getElementById(&amp;quot;display-time&amp;quot;),&lt;br /&gt;
    simulationCounter: document.getElementById(&amp;quot;simulation-counter&amp;quot;),&lt;br /&gt;
    simulationTime: document.getElementById(&amp;quot;simulation-time&amp;quot;),&lt;br /&gt;
    numberFormats: {&lt;br /&gt;
      default: new Intl.NumberFormat(currentLanguage, {&lt;br /&gt;
        minimumFractionDigits: 0,&lt;br /&gt;
        maximumFractionDigits: 1,&lt;br /&gt;
      }),&lt;br /&gt;
      percent: new Intl.NumberFormat(currentLanguage, {&lt;br /&gt;
        style: &amp;quot;percent&amp;quot;,&lt;br /&gt;
        maximumFractionDigits: 3,&lt;br /&gt;
      }),&lt;br /&gt;
      second: new Intl.NumberFormat(currentLanguage, {&lt;br /&gt;
        style: &amp;quot;unit&amp;quot;,&lt;br /&gt;
        unit: &amp;quot;second&amp;quot;,&lt;br /&gt;
        unitDisplay: &amp;quot;long&amp;quot;,&lt;br /&gt;
        maximumFractionDigits: 3,&lt;br /&gt;
      }),&lt;br /&gt;
    },&lt;br /&gt;
    mapping: createMapping(),&lt;br /&gt;
    constants: constants,&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  addBattleData(battle);&lt;br /&gt;
  initResultTableHistory(battle);&lt;br /&gt;
  initDamageChart(battle, currentLanguage, defaultText);&lt;br /&gt;
  initBonusVariationChart(battle, currentLanguage, defaultText);&lt;br /&gt;
  reduceChartPointsListener(battle);&lt;br /&gt;
  downloadRawDataListener(battle);&lt;br /&gt;
&lt;br /&gt;
  return [characters, battle];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function parseText(input) {&lt;br /&gt;
  const regex = /\[\[(.*?)\]\]|([^\[]+)/g;&lt;br /&gt;
  const result = [];&lt;br /&gt;
&lt;br /&gt;
  input.replace(regex, (_, matchA, matchText) =&amp;gt; {&lt;br /&gt;
    if (matchA !== undefined) {&lt;br /&gt;
      result.push({&lt;br /&gt;
        text: matchA,&lt;br /&gt;
        category: matchA === &amp;quot;&amp;quot; ? &amp;quot;NOTRANSLATE&amp;quot; : &amp;quot;A&amp;quot;,&lt;br /&gt;
      });&lt;br /&gt;
    } else if (matchText) {&lt;br /&gt;
      result.push({ text: matchText, category: &amp;quot;#text&amp;quot; });&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  return result;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function translateText(general) {&lt;br /&gt;
  const nodesToTranslate = [&amp;quot;A&amp;quot;, &amp;quot;I&amp;quot;, &amp;quot;B&amp;quot;];&lt;br /&gt;
&lt;br /&gt;
  for (const element of document.querySelectorAll(&amp;quot;[data-t]&amp;quot;)) {&lt;br /&gt;
    const translateText = general[element.dataset.t];&lt;br /&gt;
&lt;br /&gt;
    if (!translateText) continue;&lt;br /&gt;
&lt;br /&gt;
    const childNodes = element.childNodes;&lt;br /&gt;
    const numChildren = childNodes.length;&lt;br /&gt;
&lt;br /&gt;
    if (numChildren === 1) {&lt;br /&gt;
      childNodes[0].textContent = translateText;&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    const parsedText = parseText(translateText);&lt;br /&gt;
    const numParsed = parsedText.length;&lt;br /&gt;
&lt;br /&gt;
    let childIndex = 0;&lt;br /&gt;
    let textIndex = 0;&lt;br /&gt;
&lt;br /&gt;
    while (childIndex &amp;lt; numChildren) {&lt;br /&gt;
      const child = childNodes[childIndex];&lt;br /&gt;
&lt;br /&gt;
      if (childIndex === numParsed) {&lt;br /&gt;
        console.warn(&amp;quot;Bad translation for element&amp;quot;, element);&lt;br /&gt;
        break;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      const parsed = parsedText[textIndex];&lt;br /&gt;
&lt;br /&gt;
      let childName = child.nodeName;&lt;br /&gt;
      const isNodeToTranslate = nodesToTranslate.includes(childName);&lt;br /&gt;
&lt;br /&gt;
      if (&lt;br /&gt;
        (childName === &amp;quot;A&amp;quot; &amp;amp;&amp;amp; child.firstChild?.nodeName === &amp;quot;IMG&amp;quot;) ||&lt;br /&gt;
        !(isNodeToTranslate || childName === &amp;quot;#text&amp;quot;) ||&lt;br /&gt;
        child.dataset?.notranslate&lt;br /&gt;
      ) {&lt;br /&gt;
        childName = &amp;quot;NOTRANSLATE&amp;quot;;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (&lt;br /&gt;
        childName === parsed.category ||&lt;br /&gt;
        (parsed.category === &amp;quot;A&amp;quot; &amp;amp;&amp;amp; isNodeToTranslate)&lt;br /&gt;
      ) {&lt;br /&gt;
        if (childName !== &amp;quot;NOTRANSLATE&amp;quot;) {&lt;br /&gt;
          child.textContent = parsed.text;&lt;br /&gt;
        }&lt;br /&gt;
        childIndex++;&lt;br /&gt;
        textIndex++;&lt;br /&gt;
      } else if (childName === &amp;quot;NOTRANSLATE&amp;quot;) {&lt;br /&gt;
        childIndex++;&lt;br /&gt;
      } else if (isNodeToTranslate) {&lt;br /&gt;
        element.insertBefore(document.createTextNode(parsed.text), child);&lt;br /&gt;
        textIndex++;&lt;br /&gt;
      } else {&lt;br /&gt;
        child.textContent = &amp;quot;&amp;quot;;&lt;br /&gt;
        childIndex++;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (textIndex &amp;lt; parsedText.length) {&lt;br /&gt;
      const textNode = document.createTextNode(parsedText[textIndex].text);&lt;br /&gt;
      element.appendChild(textNode);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function translateWeapons(weapons) {&lt;br /&gt;
  const characterCreation = document.getElementById(&amp;quot;character-creation&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  for (const weaponInput of characterCreation.elements[&amp;quot;weapon&amp;quot;]) {&lt;br /&gt;
    const weaponTranslation = weapons[weaponInput.value];&lt;br /&gt;
&lt;br /&gt;
    if (weaponTranslation) {&lt;br /&gt;
      weaponInput.parentElement.lastElementChild.textContent =&lt;br /&gt;
        weaponTranslation;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleSpecialIndexes(generalTranslations, specialIndexes) {&lt;br /&gt;
  const specialTranslations = {};&lt;br /&gt;
&lt;br /&gt;
  translation.special = specialTranslations;&lt;br /&gt;
&lt;br /&gt;
  for (const [generalIndex, specialKey] of Object.entries(specialIndexes)) {&lt;br /&gt;
    const translatedValue = generalTranslations[generalIndex];&lt;br /&gt;
&lt;br /&gt;
    if (translatedValue) {&lt;br /&gt;
      specialTranslations[specialKey] = translatedValue;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  translation.mapping = {&lt;br /&gt;
    &amp;quot;Demi-humain&amp;quot;: specialTranslations.halfHuman,&lt;br /&gt;
    Mal: specialTranslations.devil,&lt;br /&gt;
    Désert: specialTranslations.desert,&lt;br /&gt;
    Animal: specialTranslations.animal,&lt;br /&gt;
    Orc: specialTranslations.orc,&lt;br /&gt;
    Mystique: specialTranslations.mystic,&lt;br /&gt;
    &amp;quot;Mort-vivant&amp;quot;: specialTranslations.undead,&lt;br /&gt;
    Insecte: specialTranslations.insect,&lt;br /&gt;
    Zodiaque: specialTranslations.zodiac,&lt;br /&gt;
    &amp;quot;Aucun type&amp;quot;: specialTranslations.noType,&lt;br /&gt;
    Mêlée: specialTranslations.melee,&lt;br /&gt;
    Flèche: specialTranslations.arrow,&lt;br /&gt;
    Magique: specialTranslations.magic,&lt;br /&gt;
    DC: specialTranslations.skill,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function translateTitle() {&lt;br /&gt;
  const translatedTitle = translation.special.pageTitle;&lt;br /&gt;
&lt;br /&gt;
  if (translatedTitle) {&lt;br /&gt;
    document.querySelector(&amp;quot;h1&amp;quot;).textContent = translatedTitle;&lt;br /&gt;
    document.querySelector(&amp;quot;ul.subpage&amp;quot;).lastElementChild.textContent =&lt;br /&gt;
      translatedTitle;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function translateSummary() {&lt;br /&gt;
  const tocContainer = document.getElementById(&amp;quot;toc&amp;quot;);&lt;br /&gt;
  const { toc, hide } = translation.special;&lt;br /&gt;
&lt;br /&gt;
  if (tocContainer) {&lt;br /&gt;
    if (toc) {&lt;br /&gt;
      tocContainer.querySelector(&amp;quot;h2&amp;quot;).textContent = toc;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (hide) {&lt;br /&gt;
      tocContainer.querySelector(&amp;quot;a.togglelink&amp;quot;).textContent = hide;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    for (const link of tocContainer.querySelectorAll(&amp;quot;ul a&amp;quot;)) {&lt;br /&gt;
      const hash = link.hash.substr(1);&lt;br /&gt;
      const title = document.getElementById(hash);&lt;br /&gt;
&lt;br /&gt;
      if (title) {&lt;br /&gt;
        const toctext = link.querySelector(&amp;quot;span.toctext&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        if (toctext) {&lt;br /&gt;
          toctext.firstElementChild.textContent = title.textContent;&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function translateDefaultText(defaultText) {&lt;br /&gt;
  const specialTranslations = translation.special;&lt;br /&gt;
&lt;br /&gt;
  for (const key of Object.keys(defaultText)) {&lt;br /&gt;
    if (specialTranslations.hasOwnProperty(key)) {&lt;br /&gt;
      defaultText[key] = specialTranslations[key];&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function translatePage(defaultText, currentLanguage) {&lt;br /&gt;
  const mwContent = document.querySelector(&amp;quot;.mw-content-ltr&amp;quot;);&lt;br /&gt;
  const { general, weapons } = translation;&lt;br /&gt;
  const specialIndexes = {&lt;br /&gt;
    471: &amp;quot;placeholder&amp;quot;,&lt;br /&gt;
    473: &amp;quot;boss&amp;quot;,&lt;br /&gt;
    474: &amp;quot;pageTitle&amp;quot;,&lt;br /&gt;
    475: &amp;quot;toc&amp;quot;,&lt;br /&gt;
    476: &amp;quot;hide&amp;quot;,&lt;br /&gt;
    502: &amp;quot;unsavedWarning&amp;quot;,&lt;br /&gt;
    503: &amp;quot;deleteWarning&amp;quot;,&lt;br /&gt;
    504: &amp;quot;pseudo&amp;quot;,&lt;br /&gt;
    481: &amp;quot;damage&amp;quot;,&lt;br /&gt;
    505: &amp;quot;percentage&amp;quot;,&lt;br /&gt;
    506: &amp;quot;miss&amp;quot;,&lt;br /&gt;
    507: &amp;quot;normalHit&amp;quot;,&lt;br /&gt;
    508: &amp;quot;criticalHit&amp;quot;,&lt;br /&gt;
    509: &amp;quot;piercingHit&amp;quot;,&lt;br /&gt;
    510: &amp;quot;criticalPiercingHit&amp;quot;,&lt;br /&gt;
    511: &amp;quot;damageRepartition&amp;quot;,&lt;br /&gt;
    512: &amp;quot;averageDamage&amp;quot;,&lt;br /&gt;
    513: &amp;quot;damageAugmentation&amp;quot;,&lt;br /&gt;
    514: &amp;quot;bonusVariationTitle&amp;quot;,&lt;br /&gt;
    489: &amp;quot;halfHuman&amp;quot;,&lt;br /&gt;
    490: &amp;quot;devil&amp;quot;,&lt;br /&gt;
    491: &amp;quot;desert&amp;quot;,&lt;br /&gt;
    492: &amp;quot;animal&amp;quot;,&lt;br /&gt;
    493: &amp;quot;orc&amp;quot;,&lt;br /&gt;
    494: &amp;quot;mystic&amp;quot;,&lt;br /&gt;
    495: &amp;quot;undead&amp;quot;,&lt;br /&gt;
    496: &amp;quot;insect&amp;quot;,&lt;br /&gt;
    497: &amp;quot;zodiac&amp;quot;,&lt;br /&gt;
    515: &amp;quot;noType&amp;quot;,&lt;br /&gt;
    498: &amp;quot;melee&amp;quot;,&lt;br /&gt;
    499: &amp;quot;arrow&amp;quot;,&lt;br /&gt;
    500: &amp;quot;magic&amp;quot;,&lt;br /&gt;
    516: &amp;quot;skill&amp;quot;,&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  translateText(general);&lt;br /&gt;
  translateWeapons(weapons);&lt;br /&gt;
  handleSpecialIndexes(general, specialIndexes);&lt;br /&gt;
  translateTitle();&lt;br /&gt;
  translateSummary();&lt;br /&gt;
  translateDefaultText(defaultText);&lt;br /&gt;
&lt;br /&gt;
  if (mwContent) {&lt;br /&gt;
    mwContent.setAttribute(&amp;quot;lang&amp;quot;, currentLanguage);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getDefaultText() {&lt;br /&gt;
  return {&lt;br /&gt;
    unsavedWarning:&lt;br /&gt;
      &amp;quot;Voulez-vous continuer ? Les dernières modifications ne seront pas sauvegardées.&amp;quot;,&lt;br /&gt;
    deleteWarning:&lt;br /&gt;
      &amp;quot;Voulez-vous vraiment supprimer définitivement le personnage [[]] ?&amp;quot;,&lt;br /&gt;
    pseudo: &amp;quot;Pseudo&amp;quot;,&lt;br /&gt;
    damage: &amp;quot;Dégâts&amp;quot;,&lt;br /&gt;
    percentage: &amp;quot;Pourcentage&amp;quot;,&lt;br /&gt;
    miss: &amp;quot;Miss&amp;quot;,&lt;br /&gt;
    normalHit: &amp;quot;Coup classique&amp;quot;,&lt;br /&gt;
    criticalHit: &amp;quot;Coup critique&amp;quot;,&lt;br /&gt;
    piercingHit: &amp;quot;Coup perçant&amp;quot;,&lt;br /&gt;
    criticalPiercingHit: &amp;quot;Coup critique perçant&amp;quot;,&lt;br /&gt;
    damageRepartition: &amp;quot;Distribution des dégâts&amp;quot;,&lt;br /&gt;
    averageDamage: &amp;quot;Dégâts moyens&amp;quot;,&lt;br /&gt;
    damageAugmentation: &amp;quot;Augmentation des dégâts&amp;quot;,&lt;br /&gt;
    bonusVariationTitle:&lt;br /&gt;
      &amp;quot;Évolution des dégâts moyens[[]]par rapport à la valeur d'un bonus&amp;quot;,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setLanguage(radios, lang, url, reload = false) {&lt;br /&gt;
  url.searchParams.set(&amp;quot;lang&amp;quot;, lang);&lt;br /&gt;
  updateLastLang(lang);&lt;br /&gt;
&lt;br /&gt;
  if (reload) {&lt;br /&gt;
    window.location.href = url.toString();&lt;br /&gt;
  } else {&lt;br /&gt;
    radios.value = lang;&lt;br /&gt;
    history.replaceState(null, &amp;quot;&amp;quot;, url);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getCurrentLanguage(defaultLang) {&lt;br /&gt;
  const url = new URL(window.location.href);&lt;br /&gt;
  const URLlang = url.searchParams.get(&amp;quot;lang&amp;quot;);&lt;br /&gt;
  const lastLang = getLastLang();&lt;br /&gt;
  const browserLang = navigator.language.split(&amp;quot;-&amp;quot;)[0];&lt;br /&gt;
  const languageSelection = document.getElementById(&amp;quot;language-selection&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (!languageSelection) {&lt;br /&gt;
    return defaultLang;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  const radios = languageSelection.elements[&amp;quot;country&amp;quot;];&lt;br /&gt;
&lt;br /&gt;
  if (!radios) {&lt;br /&gt;
    return defaultLang;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  languageSelection.addEventListener(&amp;quot;change&amp;quot;, changeLanguage);&lt;br /&gt;
&lt;br /&gt;
  function changeLanguage(event) {&lt;br /&gt;
    const newLang = event.target.value;&lt;br /&gt;
    const newUrl = new URL(window.location.href);&lt;br /&gt;
    setLanguage(radios, newLang, newUrl, true);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  const allowedLanguages = Array.from(radios).map((input) =&amp;gt; input.value);&lt;br /&gt;
&lt;br /&gt;
  for (const lang of [URLlang, lastLang, browserLang]) {&lt;br /&gt;
    if (allowedLanguages.includes(lang)) {&lt;br /&gt;
      setLanguage(radios, lang, url);&lt;br /&gt;
      return lang;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return defaultLang;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadStyle(src) {&lt;br /&gt;
  var link = document.createElement(&amp;quot;link&amp;quot;);&lt;br /&gt;
  link.href = src;&lt;br /&gt;
  link.rel = &amp;quot;stylesheet&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  document.head.appendChild(link);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
async function addScript(src) {&lt;br /&gt;
  return new Promise((resolve, reject) =&amp;gt; {&lt;br /&gt;
    const script = document.createElement(&amp;quot;script&amp;quot;);&lt;br /&gt;
    script.src = src;&lt;br /&gt;
    script.async = true;&lt;br /&gt;
&lt;br /&gt;
    script.onload = () =&amp;gt; resolve();&lt;br /&gt;
    script.onerror = () =&amp;gt; reject(new Error(`Failed to load script: ${src}`));&lt;br /&gt;
&lt;br /&gt;
    document.head.appendChild(script);&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
(async function () {&lt;br /&gt;
  const basePath = &amp;quot;/index.php?title=Utilisateur:Ankhseram/&amp;quot;;&lt;br /&gt;
  const dataScript = `${basePath}WeaponsAndMonsters.js&amp;amp;action=raw&amp;amp;ctype=text/javascript`;&lt;br /&gt;
  const simulatorStyle = `${basePath}SimulatorStyle.css&amp;amp;action=raw&amp;amp;ctype=text/css`;&lt;br /&gt;
  const chartLibrary = &amp;quot;https://cdn.jsdelivr.net/npm/chart.js&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  const defaultLang = &amp;quot;fr&amp;quot;;&lt;br /&gt;
  const defaultText = getDefaultText();&lt;br /&gt;
  const currentLanguage = getCurrentLanguage(defaultLang);&lt;br /&gt;
&lt;br /&gt;
  loadStyle(simulatorStyle);&lt;br /&gt;
&lt;br /&gt;
  let translationScript;&lt;br /&gt;
&lt;br /&gt;
  if (currentLanguage !== defaultLang) {&lt;br /&gt;
    translationScript = `${basePath}Calculator/${currentLanguage}.js&amp;amp;action=raw&amp;amp;ctype=text/javascript`;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  const scriptsToLoad = [addScript(chartLibrary), addScript(dataScript)];&lt;br /&gt;
&lt;br /&gt;
  if (translationScript) {&lt;br /&gt;
    scriptsToLoad.push(addScript(translationScript));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  await Promise.all(scriptsToLoad);&lt;br /&gt;
&lt;br /&gt;
  if (translationScript) {&lt;br /&gt;
    translatePage(defaultText, currentLanguage);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  const [characters, battle] = createDamageCalculatorInformation(&lt;br /&gt;
    defaultLang,&lt;br /&gt;
    currentLanguage,&lt;br /&gt;
    defaultText&lt;br /&gt;
  );&lt;br /&gt;
  characterManagement(characters, battle);&lt;br /&gt;
  monsterManagement(characters, battle);&lt;br /&gt;
  updateBattleChoice(characters, battle.battleChoice);&lt;br /&gt;
  createBattle(characters, battle);&lt;br /&gt;
})();&lt;/div&gt;</summary>
		<author><name>Dexter</name></author>
		
	</entry>
	<entry>
		<id>https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Common.js&amp;diff=106743</id>
		<title>MediaWiki:Common.js</title>
		<link rel="alternate" type="text/html" href="https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Common.js&amp;diff=106743"/>
		<updated>2025-03-11T05:38:28Z</updated>

		<summary type="html">&lt;p&gt;Dexter : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;/* Tout le JavaScript ici sera chargé avec chaque page accédée par n’importe quel utilisateur. */&lt;br /&gt;
&lt;br /&gt;
/* =====================================&lt;br /&gt;
DECLARATIONS DES FONCTIONS ET PROCEDURES&lt;br /&gt;
======================================== */&lt;br /&gt;
&lt;br /&gt;
function showElement(element) {&lt;br /&gt;
  element.classList.remove(&amp;quot;tabber-noactive&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function hideElement(element) {&lt;br /&gt;
  element.classList.add(&amp;quot;tabber-noactive&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function toggleElement(element) {&lt;br /&gt;
  element.classList.toggle(&amp;quot;tabber-noactive&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* Favicon */&lt;br /&gt;
function fixInsecureFavicon() {&lt;br /&gt;
  document.querySelector('link[rel=&amp;quot;shortcut icon&amp;quot;]').href =&lt;br /&gt;
    &amp;quot;https://gf1.geo.gfsrv.net/cdn98/191b803adbf82f4b8febe3a2c38c2c.ico&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* Liste des équipements */&lt;br /&gt;
function changeEquipementDisplay(container) {&lt;br /&gt;
  var switchButton = container.querySelector(&amp;quot;.button&amp;quot;);&lt;br /&gt;
  var content = container.nextElementSibling;&lt;br /&gt;
&lt;br /&gt;
  switchButton.addEventListener(&amp;quot;click&amp;quot;, function () {&lt;br /&gt;
    switchButton.classList.toggle(&amp;quot;tabber-active&amp;quot;);&lt;br /&gt;
    toggleElement(content);&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* Enlève l'animation de chargement et affiche le contenu de la page lorsque c'est nécessaire */&lt;br /&gt;
function removeLoadingAnimation() {&lt;br /&gt;
  var loadingAnimation = document.getElementById(&amp;quot;loading-animation&amp;quot;);&lt;br /&gt;
  var showAfterLoading = document.getElementById(&amp;quot;show-after-loading&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (loadingAnimation) {&lt;br /&gt;
    hideElement(loadingAnimation);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (showAfterLoading) {&lt;br /&gt;
    showElement(showAfterLoading);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* BOUTON RETOUR VERS LE HAUT */&lt;br /&gt;
function addButtonTop() {&lt;br /&gt;
  var contentText = document.querySelector(&amp;quot;div#mw-content-text&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (contentText !== null) {&lt;br /&gt;
    var divButtonTop = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
    divButtonTop.classList.add(&amp;quot;top-button&amp;quot;);&lt;br /&gt;
    contentText.appendChild(divButtonTop);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function buttonTop() {&lt;br /&gt;
  var balise = document.querySelector(&amp;quot;div#mw-page-header-links&amp;quot;);&lt;br /&gt;
  var topButton = document.querySelector(&amp;quot;.top-button&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (balise !== null) {&lt;br /&gt;
    var options = {&lt;br /&gt;
      root: null,&lt;br /&gt;
      rootMargin: &amp;quot;0px&amp;quot;,&lt;br /&gt;
      threshold: 0,&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    var observer = new IntersectionObserver(callback, options);&lt;br /&gt;
    observer.observe(balise);&lt;br /&gt;
&lt;br /&gt;
    function callback(entries) {&lt;br /&gt;
      entries.forEach(function (entry) {&lt;br /&gt;
        if (entry.isIntersecting) {&lt;br /&gt;
          topButton.classList.remove(&amp;quot;show-button&amp;quot;);&lt;br /&gt;
        } else {&lt;br /&gt;
          topButton.classList.add(&amp;quot;show-button&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
      });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    topButton.addEventListener(&amp;quot;click&amp;quot;, function () {&lt;br /&gt;
      document.documentElement.scrollTo({&lt;br /&gt;
        top: 0,&lt;br /&gt;
      });&lt;br /&gt;
    });&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* Cookies */&lt;br /&gt;
function cookies() {&lt;br /&gt;
  var req = new XMLHttpRequest();&lt;br /&gt;
  req.addEventListener(&amp;quot;load&amp;quot;, function (ev) {&lt;br /&gt;
    if (this.status &amp;gt;= 200 &amp;amp;&amp;amp; this.status &amp;lt; 300) {&lt;br /&gt;
      var data = JSON.parse(this.responseText);&lt;br /&gt;
      if (data.hasOwnProperty(&amp;quot;version&amp;quot;)) {&lt;br /&gt;
        var gdpr = document.createElement(&amp;quot;script&amp;quot;);&lt;br /&gt;
        gdpr.src =&lt;br /&gt;
          &amp;quot;https://s3-static.geo.gfsrv.net/cookiebanner/&amp;quot; +&lt;br /&gt;
          data.version +&lt;br /&gt;
          &amp;quot;/cookie.min.js&amp;quot;;&lt;br /&gt;
        document.head.appendChild(gdpr);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
  req.open(&amp;quot;GET&amp;quot;, &amp;quot;https://s3-static.geo.gfsrv.net/cookiebanner/version.json&amp;quot;);&lt;br /&gt;
  req.send();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* =======================================&lt;br /&gt;
FONCTION GLOBALE&lt;br /&gt;
Exécutée une fois au chargement de la page&lt;br /&gt;
========================================== */&lt;br /&gt;
&lt;br /&gt;
(function () {&lt;br /&gt;
  fixInsecureFavicon();&lt;br /&gt;
&lt;br /&gt;
  var equipmentContainer = document.querySelectorAll(&lt;br /&gt;
    &amp;quot;div#mw-content-text .list-equip&amp;quot;&lt;br /&gt;
  );&lt;br /&gt;
  var loadScripts = document.querySelectorAll(&amp;quot;div[data-load-javascript]&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  equipmentContainer.forEach(function (container) {&lt;br /&gt;
    changeEquipementDisplay(container);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  /* Charge des scripts spécifiques au chargement de certaines pages */&lt;br /&gt;
  if (loadScripts.length) {&lt;br /&gt;
    var allowedScripts = {&lt;br /&gt;
      Tabber: true,&lt;br /&gt;
      Skills: true,&lt;br /&gt;
      Modal: true,&lt;br /&gt;
      Switch: true,&lt;br /&gt;
      Loot: true,&lt;br /&gt;
      Map: true,&lt;br /&gt;
      Filter: true,&lt;br /&gt;
      Calculator: true,&lt;br /&gt;
      Element: true,&lt;br /&gt;
      Pets: true,&lt;br /&gt;
      Colorblind: true,&lt;br /&gt;
    };&lt;br /&gt;
    var urlStart = &amp;quot;/index.php?title=MediaWiki:Script/&amp;quot;;&lt;br /&gt;
    var urlEnd = &amp;quot;.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&amp;quot;;&lt;br /&gt;
    var scriptsToLoad = [];&lt;br /&gt;
&lt;br /&gt;
    loadScripts.forEach(function (scriptElement) {&lt;br /&gt;
      var scriptName = scriptElement.dataset.loadJavascript;&lt;br /&gt;
&lt;br /&gt;
      if (allowedScripts[scriptName]) {&lt;br /&gt;
        allowedScripts[scriptName] = false;&lt;br /&gt;
        scriptsToLoad.push(scriptName);&lt;br /&gt;
      }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    if (scriptsToLoad.length) {&lt;br /&gt;
      var firstScriptName = scriptsToLoad[0];&lt;br /&gt;
&lt;br /&gt;
      if (firstScriptName === &amp;quot;Element&amp;quot;) {&lt;br /&gt;
        scriptsToLoad.shift()&lt;br /&gt;
        $.getScript(urlStart + firstScriptName + urlEnd, function () {&lt;br /&gt;
          injectCustomElements();&lt;br /&gt;
          loadNextScripts();&lt;br /&gt;
        });&lt;br /&gt;
      } else {&lt;br /&gt;
        loadNextScripts();&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function loadNextScripts() {&lt;br /&gt;
      scriptsToLoad.forEach(function (scriptName) {&lt;br /&gt;
        mw.loader.load(urlStart + scriptName + urlEnd);&lt;br /&gt;
      });&lt;br /&gt;
      &lt;br /&gt;
      removeLoadingAnimation();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (mw.config.get(&amp;quot;wgUserName&amp;quot;)) {&lt;br /&gt;
    mw.loader.load(urlStart + &amp;quot;Redactor&amp;quot; + urlEnd);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  addButtonTop();&lt;br /&gt;
  buttonTop();&lt;br /&gt;
  cookies();&lt;br /&gt;
})();&lt;/div&gt;</summary>
		<author><name>Dexter</name></author>
		
	</entry>
	<entry>
		<id>https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Script/Element.js&amp;diff=106676</id>
		<title>MediaWiki:Script/Element.js</title>
		<link rel="alternate" type="text/html" href="https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Script/Element.js&amp;diff=106676"/>
		<updated>2025-03-06T06:20:44Z</updated>

		<summary type="html">&lt;p&gt;Dexter : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;function camelToKebab(str) {&lt;br /&gt;
  return str.replace(/([a-z0-9])([A-Z])/g, &amp;quot;$1-$2&amp;quot;).toLowerCase();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function copyProperties(source, target, allowedProps) {&lt;br /&gt;
  var sourceKeys = Object.keys(source);&lt;br /&gt;
&lt;br /&gt;
  for (var keyIndex = 0; keyIndex &amp;lt; sourceKeys.length; keyIndex++) {&lt;br /&gt;
    var property = sourceKeys[keyIndex];&lt;br /&gt;
    var propValue = source[property];&lt;br /&gt;
&lt;br /&gt;
    if (property === &amp;quot;viewBox&amp;quot;) {&lt;br /&gt;
      target.setAttribute(property, propValue);&lt;br /&gt;
    } else if (&lt;br /&gt;
      property.indexOf(&amp;quot;data&amp;quot;) === 0 ||&lt;br /&gt;
      allowedProps.indexOf(property) !== -1&lt;br /&gt;
    ) {&lt;br /&gt;
      target.setAttribute(camelToKebab(property), propValue);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createElement(&lt;br /&gt;
  elementsToReplace,&lt;br /&gt;
  elementsNS,&lt;br /&gt;
  allowedProperties,&lt;br /&gt;
  elementDataset,&lt;br /&gt;
  elementType,&lt;br /&gt;
  skillValues&lt;br /&gt;
) {&lt;br /&gt;
  if (elementsNS.indexOf(elementType) !== -1) {&lt;br /&gt;
    var newElement = document.createElementNS(&lt;br /&gt;
      &amp;quot;http://www.w3.org/2000/svg&amp;quot;,&lt;br /&gt;
      elementType&lt;br /&gt;
    );&lt;br /&gt;
  } else {&lt;br /&gt;
    var newElement = document.createElement(elementType);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var childdNodes = elementsToReplace.childNodes;&lt;br /&gt;
&lt;br /&gt;
  copyProperties(elementDataset, newElement, allowedProperties);&lt;br /&gt;
&lt;br /&gt;
  for (var childIndex = 0; childIndex &amp;lt; childdNodes.length; childIndex++) {&lt;br /&gt;
    newElement.appendChild(childdNodes[childIndex].cloneNode(true));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var addAttribute = newElement.dataset.add;&lt;br /&gt;
&lt;br /&gt;
  if (addAttribute &amp;amp;&amp;amp; addAttribute.startsWith(&amp;quot;skill&amp;quot;)) {&lt;br /&gt;
    var maxLevel = Number(addAttribute.split(&amp;quot;skill&amp;quot;)[1]);&lt;br /&gt;
&lt;br /&gt;
    for (var index = 0; index &amp;lt;= maxLevel; index++) {&lt;br /&gt;
      var option = document.createElement(&amp;quot;option&amp;quot;);&lt;br /&gt;
      option.value = index;&lt;br /&gt;
      option.textContent = skillValues[index];&lt;br /&gt;
      newElement.appendChild(option);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return newElement;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function replaceElement(&lt;br /&gt;
  elementsToReplace,&lt;br /&gt;
  allowedElements,&lt;br /&gt;
  elementsNS,&lt;br /&gt;
  allowedProperties,&lt;br /&gt;
  skillValues&lt;br /&gt;
) {&lt;br /&gt;
  var elementDataset = elementsToReplace.dataset;&lt;br /&gt;
  var elementType = elementDataset.element;&lt;br /&gt;
&lt;br /&gt;
  if (allowedElements.indexOf(elementType) !== -1) {&lt;br /&gt;
    var newElement = createElement(&lt;br /&gt;
      elementsToReplace,&lt;br /&gt;
      elementsNS,&lt;br /&gt;
      allowedProperties,&lt;br /&gt;
      elementDataset,&lt;br /&gt;
      elementType,&lt;br /&gt;
      skillValues&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    elementsToReplace.parentNode.replaceChild(newElement, elementsToReplace);&lt;br /&gt;
  } else {&lt;br /&gt;
    elementsToReplace.remove();&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addCollapsible(collapsibleContainer) {&lt;br /&gt;
  var toggleButton = collapsibleContainer.querySelector(&lt;br /&gt;
    &amp;quot;.mw-collapsible-toggle&amp;quot;&lt;br /&gt;
  );&lt;br /&gt;
  var collapsibleContent = collapsibleContainer.querySelector(&lt;br /&gt;
    &amp;quot;.mw-collapsible-content&amp;quot;&lt;br /&gt;
  );&lt;br /&gt;
  var collapsibleContentChild = collapsibleContent.firstElementChild;&lt;br /&gt;
  var expandedClass = &amp;quot;mw-collapsible-toggle-expanded&amp;quot;;&lt;br /&gt;
  var isCollapsed = false;&lt;br /&gt;
&lt;br /&gt;
  toggleButton.setAttribute(&amp;quot;tabindex&amp;quot;, 0);&lt;br /&gt;
&lt;br /&gt;
  toggleButton.addEventListener(&amp;quot;click&amp;quot;, function (event) {&lt;br /&gt;
    if (isCollapsed) {&lt;br /&gt;
      this.classList.remove(expandedClass);&lt;br /&gt;
      collapsibleContentChild.style.overflow = &amp;quot;hidden&amp;quot;;&lt;br /&gt;
      collapsibleContent.style.gridTemplateRows = &amp;quot;0fr&amp;quot;;&lt;br /&gt;
    } else {&lt;br /&gt;
      collapsibleContentChild.classList.remove(&amp;quot;tabber-noactive&amp;quot;);&lt;br /&gt;
      this.classList.add(expandedClass);&lt;br /&gt;
      collapsibleContent.style.gridTemplateRows = &amp;quot;1fr&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
    isCollapsed = !isCollapsed;&lt;br /&gt;
  });&lt;br /&gt;
  toggleButton.addEventListener(&amp;quot;keyup&amp;quot;, function (event) {&lt;br /&gt;
    if (event.keyCode === 13) {&lt;br /&gt;
      this.click();&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
  collapsibleContent.addEventListener(&amp;quot;transitionend&amp;quot;, function (event) {&lt;br /&gt;
    if (isCollapsed) {&lt;br /&gt;
      collapsibleContentChild.style.overflow = &amp;quot;visible&amp;quot;;&lt;br /&gt;
    } else {&lt;br /&gt;
      collapsibleContentChild.classList.add(&amp;quot;tabber-noactive&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function injectCustomElements() {&lt;br /&gt;
  var allowedElements = [&lt;br /&gt;
    &amp;quot;input&amp;quot;,&lt;br /&gt;
    &amp;quot;button&amp;quot;,&lt;br /&gt;
    &amp;quot;select&amp;quot;,&lt;br /&gt;
    &amp;quot;option&amp;quot;,&lt;br /&gt;
    &amp;quot;label&amp;quot;,&lt;br /&gt;
    &amp;quot;form&amp;quot;,&lt;br /&gt;
    &amp;quot;svg&amp;quot;,&lt;br /&gt;
    &amp;quot;path&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;,&lt;br /&gt;
    &amp;quot;canvas&amp;quot;,&lt;br /&gt;
    &amp;quot;iframe&amp;quot;,&lt;br /&gt;
  ];&lt;br /&gt;
  var elementsNS = [&amp;quot;svg&amp;quot;, &amp;quot;path&amp;quot;, &amp;quot;title&amp;quot;];&lt;br /&gt;
  var allowedProperties = [&lt;br /&gt;
    &amp;quot;id&amp;quot;,&lt;br /&gt;
    &amp;quot;class&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;,&lt;br /&gt;
    &amp;quot;name&amp;quot;,&lt;br /&gt;
    &amp;quot;ariaHaspopup&amp;quot;,&lt;br /&gt;
    &amp;quot;ariaExpanded&amp;quot;,&lt;br /&gt;
    &amp;quot;ariaControls&amp;quot;,&lt;br /&gt;
    &amp;quot;for&amp;quot;,&lt;br /&gt;
    &amp;quot;min&amp;quot;,&lt;br /&gt;
    &amp;quot;max&amp;quot;,&lt;br /&gt;
    &amp;quot;value&amp;quot;,&lt;br /&gt;
    &amp;quot;style&amp;quot;,&lt;br /&gt;
    &amp;quot;pattern&amp;quot;,&lt;br /&gt;
    &amp;quot;required&amp;quot;,&lt;br /&gt;
    &amp;quot;selected&amp;quot;,&lt;br /&gt;
    &amp;quot;disabled&amp;quot;,&lt;br /&gt;
    &amp;quot;checked&amp;quot;,&lt;br /&gt;
    &amp;quot;tabindex&amp;quot;,&lt;br /&gt;
    &amp;quot;placeholder&amp;quot;,&lt;br /&gt;
    &amp;quot;xmlns&amp;quot;,&lt;br /&gt;
    &amp;quot;height&amp;quot;,&lt;br /&gt;
    &amp;quot;viewBox&amp;quot;,&lt;br /&gt;
    &amp;quot;width&amp;quot;,&lt;br /&gt;
    &amp;quot;fill&amp;quot;,&lt;br /&gt;
    &amp;quot;d&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;,&lt;br /&gt;
  ];&lt;br /&gt;
&lt;br /&gt;
  var skillValues = [&lt;br /&gt;
    0,&lt;br /&gt;
    1,&lt;br /&gt;
    2,&lt;br /&gt;
    3,&lt;br /&gt;
    4,&lt;br /&gt;
    5,&lt;br /&gt;
    6,&lt;br /&gt;
    7,&lt;br /&gt;
    8,&lt;br /&gt;
    9,&lt;br /&gt;
    10,&lt;br /&gt;
    11,&lt;br /&gt;
    12,&lt;br /&gt;
    13,&lt;br /&gt;
    14,&lt;br /&gt;
    15,&lt;br /&gt;
    16,&lt;br /&gt;
    17,&lt;br /&gt;
    18,&lt;br /&gt;
    19,&lt;br /&gt;
    &amp;quot;M1&amp;quot;,&lt;br /&gt;
    &amp;quot;M2&amp;quot;,&lt;br /&gt;
    &amp;quot;M3&amp;quot;,&lt;br /&gt;
    &amp;quot;M4&amp;quot;,&lt;br /&gt;
    &amp;quot;M5&amp;quot;,&lt;br /&gt;
    &amp;quot;M6&amp;quot;,&lt;br /&gt;
    &amp;quot;M7&amp;quot;,&lt;br /&gt;
    &amp;quot;M8&amp;quot;,&lt;br /&gt;
    &amp;quot;M9&amp;quot;,&lt;br /&gt;
    &amp;quot;M10&amp;quot;,&lt;br /&gt;
    &amp;quot;G1&amp;quot;,&lt;br /&gt;
    &amp;quot;G2&amp;quot;,&lt;br /&gt;
    &amp;quot;G3&amp;quot;,&lt;br /&gt;
    &amp;quot;G4&amp;quot;,&lt;br /&gt;
    &amp;quot;G5&amp;quot;,&lt;br /&gt;
    &amp;quot;G6&amp;quot;,&lt;br /&gt;
    &amp;quot;G7&amp;quot;,&lt;br /&gt;
    &amp;quot;G8&amp;quot;,&lt;br /&gt;
    &amp;quot;G9&amp;quot;,&lt;br /&gt;
    &amp;quot;G10&amp;quot;,&lt;br /&gt;
    &amp;quot;P&amp;quot;,&lt;br /&gt;
  ];&lt;br /&gt;
&lt;br /&gt;
  var elementsToReplace = document.querySelector(&amp;quot;div[data-element]&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  while (elementsToReplace) {&lt;br /&gt;
    replaceElement(&lt;br /&gt;
      elementsToReplace,&lt;br /&gt;
      allowedElements,&lt;br /&gt;
      elementsNS,&lt;br /&gt;
      allowedProperties,&lt;br /&gt;
      skillValues&lt;br /&gt;
    );&lt;br /&gt;
    elementsToReplace = document.querySelector(&amp;quot;div[data-element]&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var collapsibleContainers = document.querySelectorAll(&lt;br /&gt;
    &amp;quot;.improved-collapsible.custom-js&amp;quot;&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  for (var collapsibleContainer of collapsibleContainers) {&lt;br /&gt;
    addCollapsible(collapsibleContainer);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;/div&gt;</summary>
		<author><name>Dexter</name></author>
		
	</entry>
	<entry>
		<id>https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Common.js&amp;diff=106675</id>
		<title>MediaWiki:Common.js</title>
		<link rel="alternate" type="text/html" href="https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Common.js&amp;diff=106675"/>
		<updated>2025-03-06T06:19:50Z</updated>

		<summary type="html">&lt;p&gt;Dexter : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;/* Tout le JavaScript ici sera chargé avec chaque page accédée par n’importe quel utilisateur. */&lt;br /&gt;
&lt;br /&gt;
/* =====================================&lt;br /&gt;
DECLARATIONS DES FONCTIONS ET PROCEDURES&lt;br /&gt;
======================================== */&lt;br /&gt;
&lt;br /&gt;
function showElement(element) {&lt;br /&gt;
  element.classList.remove(&amp;quot;tabber-noactive&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function hideElement(element) {&lt;br /&gt;
  element.classList.add(&amp;quot;tabber-noactive&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function toggleElement(element) {&lt;br /&gt;
  element.classList.toggle(&amp;quot;tabber-noactive&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* Favicon */&lt;br /&gt;
function fixInsecureFavicon() {&lt;br /&gt;
  document.querySelector('link[rel=&amp;quot;shortcut icon&amp;quot;]').href =&lt;br /&gt;
    &amp;quot;https://gf1.geo.gfsrv.net/cdn98/191b803adbf82f4b8febe3a2c38c2c.ico&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* Liste des équipements */&lt;br /&gt;
function changeEquipementDisplay(container) {&lt;br /&gt;
  var switchButton = container.querySelector(&amp;quot;.button&amp;quot;);&lt;br /&gt;
  var content = container.nextElementSibling;&lt;br /&gt;
&lt;br /&gt;
  switchButton.addEventListener(&amp;quot;click&amp;quot;, function () {&lt;br /&gt;
    switchButton.classList.toggle(&amp;quot;tabber-active&amp;quot;);&lt;br /&gt;
    toggleElement(content);&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* Enlève l'animation de chargement et affiche le contenu de la page lorsque c'est nécessaire */&lt;br /&gt;
function removeLoadingAnimation() {&lt;br /&gt;
  var loadingAnimation = document.getElementById(&amp;quot;loading-animation&amp;quot;);&lt;br /&gt;
  var showAfterLoading = document.getElementById(&amp;quot;show-after-loading&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (loadingAnimation) {&lt;br /&gt;
    hideElement(loadingAnimation);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (showAfterLoading) {&lt;br /&gt;
    showElement(showAfterLoading);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* BOUTON RETOUR VERS LE HAUT */&lt;br /&gt;
function addButtonTop() {&lt;br /&gt;
  var contentText = document.querySelector(&amp;quot;div#mw-content-text&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (contentText !== null) {&lt;br /&gt;
    var divButtonTop = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
    divButtonTop.classList.add(&amp;quot;top-button&amp;quot;);&lt;br /&gt;
    contentText.appendChild(divButtonTop);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function buttonTop() {&lt;br /&gt;
  var balise = document.querySelector(&amp;quot;div#mw-page-header-links&amp;quot;);&lt;br /&gt;
  var topButton = document.querySelector(&amp;quot;.top-button&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (balise !== null) {&lt;br /&gt;
    var options = {&lt;br /&gt;
      root: null,&lt;br /&gt;
      rootMargin: &amp;quot;0px&amp;quot;,&lt;br /&gt;
      threshold: 0,&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    var observer = new IntersectionObserver(callback, options);&lt;br /&gt;
    observer.observe(balise);&lt;br /&gt;
&lt;br /&gt;
    function callback(entries) {&lt;br /&gt;
      entries.forEach(function (entry) {&lt;br /&gt;
        if (entry.isIntersecting) {&lt;br /&gt;
          topButton.classList.remove(&amp;quot;show-button&amp;quot;);&lt;br /&gt;
        } else {&lt;br /&gt;
          topButton.classList.add(&amp;quot;show-button&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
      });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    topButton.addEventListener(&amp;quot;click&amp;quot;, function () {&lt;br /&gt;
      document.documentElement.scrollTo({&lt;br /&gt;
        top: 0,&lt;br /&gt;
      });&lt;br /&gt;
    });&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* Cookies */&lt;br /&gt;
function cookies() {&lt;br /&gt;
  var req = new XMLHttpRequest();&lt;br /&gt;
  req.addEventListener(&amp;quot;load&amp;quot;, function (ev) {&lt;br /&gt;
    if (this.status &amp;gt;= 200 &amp;amp;&amp;amp; this.status &amp;lt; 300) {&lt;br /&gt;
      var data = JSON.parse(this.responseText);&lt;br /&gt;
      if (data.hasOwnProperty(&amp;quot;version&amp;quot;)) {&lt;br /&gt;
        var gdpr = document.createElement(&amp;quot;script&amp;quot;);&lt;br /&gt;
        gdpr.src =&lt;br /&gt;
          &amp;quot;https://s3-static.geo.gfsrv.net/cookiebanner/&amp;quot; +&lt;br /&gt;
          data.version +&lt;br /&gt;
          &amp;quot;/cookie.min.js&amp;quot;;&lt;br /&gt;
        document.head.appendChild(gdpr);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
  req.open(&amp;quot;GET&amp;quot;, &amp;quot;https://s3-static.geo.gfsrv.net/cookiebanner/version.json&amp;quot;);&lt;br /&gt;
  req.send();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* =======================================&lt;br /&gt;
FONCTION GLOBALE&lt;br /&gt;
Exécutée une fois au chargement de la page&lt;br /&gt;
========================================== */&lt;br /&gt;
&lt;br /&gt;
(function () {&lt;br /&gt;
  fixInsecureFavicon();&lt;br /&gt;
&lt;br /&gt;
  var equipmentContainer = document.querySelectorAll(&lt;br /&gt;
    &amp;quot;div#mw-content-text .list-equip&amp;quot;&lt;br /&gt;
  );&lt;br /&gt;
  var loadScripts = document.querySelectorAll(&amp;quot;div[data-load-javascript]&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  equipmentContainer.forEach(function (container) {&lt;br /&gt;
    changeEquipementDisplay(container);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  /* Charge des scripts spécifiques au chargement de certaines pages */&lt;br /&gt;
  if (loadScripts.length) {&lt;br /&gt;
    var allowedScripts = {&lt;br /&gt;
      Tabber: true,&lt;br /&gt;
      Skills: true,&lt;br /&gt;
      Modal: true,&lt;br /&gt;
      Switch: true,&lt;br /&gt;
      Loot: true,&lt;br /&gt;
      Map: true,&lt;br /&gt;
      Filter: true,&lt;br /&gt;
      Calculator: true,&lt;br /&gt;
      Element: true,&lt;br /&gt;
      Pets: true,&lt;br /&gt;
      Colorblind: true,&lt;br /&gt;
    };&lt;br /&gt;
    var urlStart = &amp;quot;/index.php?title=MediaWiki:Script/&amp;quot;;&lt;br /&gt;
    var urlEnd = &amp;quot;.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&amp;quot;;&lt;br /&gt;
    var scriptsToLoad = [];&lt;br /&gt;
&lt;br /&gt;
    loadScripts.forEach(function (scriptElement) {&lt;br /&gt;
      var scriptName = scriptElement.dataset.loadJavascript;&lt;br /&gt;
&lt;br /&gt;
      if (allowedScripts[scriptName]) {&lt;br /&gt;
        allowedScripts[scriptName] = false;&lt;br /&gt;
        scriptsToLoad.push(scriptName);&lt;br /&gt;
      }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    if (scriptsToLoad.length) {&lt;br /&gt;
      var firstScriptName = scriptsToLoad[0];&lt;br /&gt;
&lt;br /&gt;
      if (firstScriptName === &amp;quot;Element&amp;quot;) {&lt;br /&gt;
        scriptsToLoad.shift()&lt;br /&gt;
        $.getScript(urlStart + firstScriptName + urlEnd, function () {&lt;br /&gt;
          injectCustomElements();&lt;br /&gt;
          loadNextScripts();&lt;br /&gt;
        });&lt;br /&gt;
      } else {&lt;br /&gt;
        loadNextScripts();&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function loadNextScripts() {&lt;br /&gt;
      scriptsToLoad.forEach(function (scriptName) {&lt;br /&gt;
        mw.loader.load(urlStart + scriptName + urlEnd);&lt;br /&gt;
      });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    removeLoadingAnimation();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (mw.config.get(&amp;quot;wgUserName&amp;quot;)) {&lt;br /&gt;
    mw.loader.load(urlStart + &amp;quot;Redactor&amp;quot; + urlEnd);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  addButtonTop();&lt;br /&gt;
  buttonTop();&lt;br /&gt;
  cookies();&lt;br /&gt;
})();&lt;/div&gt;</summary>
		<author><name>Dexter</name></author>
		
	</entry>
	<entry>
		<id>https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Script/Calculator.js&amp;diff=106674</id>
		<title>MediaWiki:Script/Calculator.js</title>
		<link rel="alternate" type="text/html" href="https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Script/Calculator.js&amp;diff=106674"/>
		<updated>2025-03-06T06:18:55Z</updated>

		<summary type="html">&lt;p&gt;Dexter : v0.20&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;function removeAccent(str) {&lt;br /&gt;
  return str.normalize(&amp;quot;NFD&amp;quot;).replace(/[\u0300-\u036f]/g, &amp;quot;&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function pseudoFormat(str) {&lt;br /&gt;
  return removeAccent(str).replace(/[^A-Za-z0-9 \(\)\+_-]+/g, &amp;quot;&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isValueInArray(value, array) {&lt;br /&gt;
  return array.indexOf(value) !== -1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function splitFirst(value, delimiter) {&lt;br /&gt;
  var parts = value.split(delimiter);&lt;br /&gt;
  var first = parts[0];&lt;br /&gt;
  var rest = parts.slice(1).join(delimiter);&lt;br /&gt;
  return [first, rest];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function copyObject(object) {&lt;br /&gt;
  var copy = {};&lt;br /&gt;
  for (var key in object) {&lt;br /&gt;
    copy[key] = object[key];&lt;br /&gt;
  }&lt;br /&gt;
  return copy;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function compareNumbers(a, b) {&lt;br /&gt;
  return b - a;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isChecked(attribute) {&lt;br /&gt;
  return attribute === &amp;quot;on&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function floorMultiplication(firstFactor, secondFactor) {&lt;br /&gt;
  return Math.floor((firstFactor * secondFactor).toFixed(8));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function truncateNumber(number, precision) {&lt;br /&gt;
  return Math.floor(number * 10 ** precision) / 10 ** precision;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function newChangeEvent() {&lt;br /&gt;
  return new Event(&amp;quot;change&amp;quot;, { bubbles: true });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function openTargetTab(target) {&lt;br /&gt;
  var tabberContainer = target.closest(&amp;quot;.tabber-container&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (!tabberContainer) {&lt;br /&gt;
    return;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var [buttonsContainer, tabsContainer] = tabberContainer.children;&lt;br /&gt;
  var buttons = buttonsContainer.children;&lt;br /&gt;
  var tabs = tabsContainer.children;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; tabs.length; index++) {&lt;br /&gt;
    var tab = tabs[index];&lt;br /&gt;
    if (tab.contains(target) &amp;amp;&amp;amp; !tab.checkVisibility()) {&lt;br /&gt;
      buttons[index].click();&lt;br /&gt;
      break;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function openTargetCollapsible(target) {&lt;br /&gt;
  var collapsible = target.closest(&amp;quot;.improved-collapsible&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (!collapsible) {&lt;br /&gt;
    return;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var span = collapsible.firstElementChild;&lt;br /&gt;
&lt;br /&gt;
  if (!span.classList.contains(&amp;quot;mw-collapsible-toggle-expanded&amp;quot;)) {&lt;br /&gt;
    span.click();&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function editTableResultRow(row, valuesToDisplay, numberFormat) {&lt;br /&gt;
  row.innerHTML = &amp;quot;&amp;quot;;&lt;br /&gt;
  for (var index = 0; index &amp;lt; valuesToDisplay.length; index++) {&lt;br /&gt;
    var cell = row.insertCell();&lt;br /&gt;
    var textContent;&lt;br /&gt;
&lt;br /&gt;
    if (index &amp;gt;= 3) {&lt;br /&gt;
      textContent = numberFormat.format(valuesToDisplay[index]);&lt;br /&gt;
    } else {&lt;br /&gt;
      textContent = valuesToDisplay[index];&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    cell.textContent = textContent;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return row;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addRowToTableResultHistory(&lt;br /&gt;
  tableResultHistory,&lt;br /&gt;
  valuesToDisplay,&lt;br /&gt;
  deleteFightTemplate,&lt;br /&gt;
  numberFormat&lt;br /&gt;
) {&lt;br /&gt;
  var row = tableResultHistory.insertRow();&lt;br /&gt;
  editTableResultRow(row, valuesToDisplay, numberFormat);&lt;br /&gt;
  var cell = row.insertCell();&lt;br /&gt;
  cell.appendChild(deleteFightTemplate.cloneNode(true));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function processSavedDamage(savedDamage, damageWeightedByType, battleValues) {&lt;br /&gt;
  const { damageTypeWeights, attackTypeMapping } = battleValues;&lt;br /&gt;
&lt;br /&gt;
  for (const key in savedDamage) {&lt;br /&gt;
    const [weight, damageByType] = savedDamage[key];&lt;br /&gt;
&lt;br /&gt;
    for (let index = 0; index &amp;lt; 4; index++) {&lt;br /&gt;
      const damageWeighted = damageWeightedByType[attackTypeMapping[index]];&lt;br /&gt;
      const damageByTypeIndex = damageByType[index];&lt;br /&gt;
&lt;br /&gt;
      if (damageByTypeIndex.length === 0) continue;&lt;br /&gt;
&lt;br /&gt;
      const currentWeight =&lt;br /&gt;
        (weight * damageTypeWeights[index]) / damageByTypeIndex.length;&lt;br /&gt;
&lt;br /&gt;
      for (const damage of damageByTypeIndex) {&lt;br /&gt;
        damageWeighted[damage] = (damageWeighted[damage] || 0) + currentWeight;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcMeanDamage(damageWeightedByType, totalCardinal) {&lt;br /&gt;
  var sumDamage = 0;&lt;br /&gt;
&lt;br /&gt;
  for (var damageTypeName in damageWeightedByType) {&lt;br /&gt;
    if (damageTypeName === &amp;quot;miss&amp;quot;) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var damageWeighted = damageWeightedByType[damageTypeName];&lt;br /&gt;
&lt;br /&gt;
    for (var damage in damageWeighted) {&lt;br /&gt;
      sumDamage += damage * damageWeighted[damage];&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return sumDamage / totalCardinal;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function prepareDamageData(damageWeightedByType, attackValues) {&lt;br /&gt;
  const totalCardinal = attackValues.totalCardinal;&lt;br /&gt;
  const scatterDataByType = {};&lt;br /&gt;
  const criticalAttackRange = attackValues.criticalAttackRange;&lt;br /&gt;
&lt;br /&gt;
  let minDamage = Infinity;&lt;br /&gt;
  let maxDamage = 0;&lt;br /&gt;
  let sumDamage = 0;&lt;br /&gt;
&lt;br /&gt;
  let possibleDamageCount = 0;&lt;br /&gt;
  let possibleDamageCountTemp = 0;&lt;br /&gt;
  let uniqueDamageCount = 0;&lt;br /&gt;
&lt;br /&gt;
  for (const damageTypeName in damageWeightedByType) {&lt;br /&gt;
    if (damageTypeName === &amp;quot;miss&amp;quot;) {&lt;br /&gt;
      scatterDataByType.miss = damageWeightedByType.miss;&lt;br /&gt;
      possibleDamageCount++;&lt;br /&gt;
      uniqueDamageCount++;&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
    const damageWeighted = damageWeightedByType[damageTypeName];&lt;br /&gt;
    const scatterData = [];&lt;br /&gt;
&lt;br /&gt;
    scatterDataByType[damageTypeName] = scatterData;&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      (damageTypeName === &amp;quot;criticalHit&amp;quot; ||&lt;br /&gt;
        damageTypeName === &amp;quot;criticalPiercingHit&amp;quot;) &amp;amp;&amp;amp;&lt;br /&gt;
      criticalAttackRange&lt;br /&gt;
    ) {&lt;br /&gt;
      possibleDamageCountTemp =&lt;br /&gt;
        attackValues.possibleDamageCount * criticalAttackRange.length;&lt;br /&gt;
    } else {&lt;br /&gt;
      possibleDamageCountTemp = attackValues.possibleDamageCount;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    for (let damage in damageWeighted) {&lt;br /&gt;
      damage = +damage;&lt;br /&gt;
&lt;br /&gt;
      if (damage &amp;lt; minDamage) {&lt;br /&gt;
        minDamage = damage;&lt;br /&gt;
      }&lt;br /&gt;
      if (damage &amp;gt; maxDamage) {&lt;br /&gt;
        maxDamage = damage;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      const weight = damageWeighted[damage];&lt;br /&gt;
      const probability = weight / totalCardinal;&lt;br /&gt;
&lt;br /&gt;
      sumDamage += damage * weight;&lt;br /&gt;
      damageWeighted[damage] = probability;&lt;br /&gt;
      scatterData.push({ x: damage, y: probability });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    const scatterDataLength = scatterData.length;&lt;br /&gt;
&lt;br /&gt;
    if (!scatterDataLength) {&lt;br /&gt;
      delete scatterDataByType[damageTypeName];&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    possibleDamageCount += possibleDamageCountTemp;&lt;br /&gt;
    uniqueDamageCount += scatterDataLength;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (minDamage === Infinity) {&lt;br /&gt;
    minDamage = 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  attackValues.possibleDamageCount = possibleDamageCount;&lt;br /&gt;
&lt;br /&gt;
  return [&lt;br /&gt;
    sumDamage / totalCardinal,&lt;br /&gt;
    minDamage,&lt;br /&gt;
    maxDamage,&lt;br /&gt;
    scatterDataByType,&lt;br /&gt;
    uniqueDamageCount,&lt;br /&gt;
  ];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function aggregateDamage(scatterData, maxPoints) {&lt;br /&gt;
  var dataLength = scatterData.length;&lt;br /&gt;
  var remainingData = dataLength;&lt;br /&gt;
  var aggregateScatterData = [];&lt;br /&gt;
&lt;br /&gt;
  for (var groupIndex = 0; groupIndex &amp;lt; maxPoints; groupIndex++) {&lt;br /&gt;
    var groupLength = Math.floor(remainingData / (maxPoints - groupIndex));&lt;br /&gt;
    var startIndex = dataLength - remainingData;&lt;br /&gt;
    var aggregateDamage = 0;&lt;br /&gt;
    var aggregateProbability = 0;&lt;br /&gt;
&lt;br /&gt;
    for (var index = startIndex; index &amp;lt; startIndex + groupLength; index++) {&lt;br /&gt;
      var { x: damage, y: probability } = scatterData[index];&lt;br /&gt;
      aggregateDamage += damage * probability;&lt;br /&gt;
      aggregateProbability += probability;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    aggregateScatterData.push({&lt;br /&gt;
      x: aggregateDamage / aggregateProbability,&lt;br /&gt;
      y: aggregateProbability,&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    remainingData -= groupLength;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return aggregateScatterData;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addToDamageChart(&lt;br /&gt;
  scatterDataByType,&lt;br /&gt;
  damageChart,&lt;br /&gt;
  isReducePointsChecked&lt;br /&gt;
) {&lt;br /&gt;
  var { chart, datasetsStyle, maxPoints, reduceChartPointsContainer } =&lt;br /&gt;
    damageChart;&lt;br /&gt;
  var isFirstDataset = true;&lt;br /&gt;
  var datasets = chart.data.datasets;&lt;br /&gt;
&lt;br /&gt;
  datasets.length = 0;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; datasetsStyle.length; index++) {&lt;br /&gt;
    var dataset = copyObject(datasetsStyle[index]);&lt;br /&gt;
&lt;br /&gt;
    if (!scatterDataByType.hasOwnProperty(dataset.name)) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var scatterData = scatterDataByType[dataset.name];&lt;br /&gt;
    var canBeReduced = scatterData.length &amp;gt; 2 * maxPoints;&lt;br /&gt;
&lt;br /&gt;
    dataset.hidden = !isFirstDataset;&lt;br /&gt;
    dataset.canBeReduced = canBeReduced;&lt;br /&gt;
&lt;br /&gt;
    if (canBeReduced &amp;amp;&amp;amp; isReducePointsChecked) {&lt;br /&gt;
      dataset.data = aggregateDamage(scatterData, maxPoints);&lt;br /&gt;
    } else {&lt;br /&gt;
      dataset.data = scatterData;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isFirstDataset) {&lt;br /&gt;
      isFirstDataset = false;&lt;br /&gt;
&lt;br /&gt;
      if (canBeReduced) {&lt;br /&gt;
        showElement(reduceChartPointsContainer);&lt;br /&gt;
&lt;br /&gt;
        if (!isReducePointsChecked) {&lt;br /&gt;
          handleChartAnimations(chart, false);&lt;br /&gt;
        }&lt;br /&gt;
      } else {&lt;br /&gt;
        hideElement(reduceChartPointsContainer);&lt;br /&gt;
        handleChartAnimations(chart, true);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    datasets.push(dataset);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  chart.data.missPercentage = scatterDataByType.miss;&lt;br /&gt;
  chart.update();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addToBonusVariationChart(&lt;br /&gt;
  damageByBonus,&lt;br /&gt;
  augmentationByBonus,&lt;br /&gt;
  xLabel,&lt;br /&gt;
  chart&lt;br /&gt;
) {&lt;br /&gt;
  chart.data.datasets[0].data = damageByBonus;&lt;br /&gt;
  chart.data.datasets[1].data = augmentationByBonus;&lt;br /&gt;
  chart.options.scales.x.title.text = xLabel;&lt;br /&gt;
  chart.update();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleChartAnimations(chart, addAnimations) {&lt;br /&gt;
  chart.options.animation = addAnimations;&lt;br /&gt;
  chart.options.animations.colors = addAnimations;&lt;br /&gt;
  chart.options.animations.x = addAnimations;&lt;br /&gt;
  chart.options.transitions.active.animation.duration = addAnimations * 1000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateDamageChartDescription(&lt;br /&gt;
  uniqueDamageCounters,&lt;br /&gt;
  uniqueDamageCount,&lt;br /&gt;
  formatNumber&lt;br /&gt;
) {&lt;br /&gt;
  uniqueDamageCounters.forEach(function (element) {&lt;br /&gt;
    if (uniqueDamageCount &amp;lt;= 1) {&lt;br /&gt;
      hideElement(element.parentElement);&lt;br /&gt;
    } else {&lt;br /&gt;
      showElement(element.parentElement);&lt;br /&gt;
      element.textContent = formatNumber.format(uniqueDamageCount);&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getMonsterName(monsterVnum) {&lt;br /&gt;
  var monsterAttributes = monsterData[monsterVnum];&lt;br /&gt;
  return monsterAttributes[monsterAttributes.length - 1];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getTranslatedMonsterName(monsterVnum) {&lt;br /&gt;
  return translation.monsters[monsterVnum];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterClass(selectedRace, classChoice, selectValueIsChanged = false) {&lt;br /&gt;
  for (var radioNode of classChoice) {&lt;br /&gt;
    var radioGrandParent = radioNode.parentElement.parentElement;&lt;br /&gt;
&lt;br /&gt;
    if (radioNode.getAttribute(&amp;quot;data-race&amp;quot;) === selectedRace) {&lt;br /&gt;
      if (!selectValueIsChanged) {&lt;br /&gt;
        radioNode.checked = true;&lt;br /&gt;
        selectValueIsChanged = true;&lt;br /&gt;
      }&lt;br /&gt;
      showElement(radioGrandParent);&lt;br /&gt;
    } else {&lt;br /&gt;
      hideElement(radioGrandParent);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterWeapon(&lt;br /&gt;
  selectedRace,&lt;br /&gt;
  weaponElement,&lt;br /&gt;
  weaponCategory,&lt;br /&gt;
  allowedWeaponsPerRace,&lt;br /&gt;
  selectValueIsChanged = false&lt;br /&gt;
) {&lt;br /&gt;
  var allowedWeapons = allowedWeaponsPerRace[selectedRace];&lt;br /&gt;
&lt;br /&gt;
  if (!selectValueIsChanged) {&lt;br /&gt;
    var weaponType = createWeapon(weaponElement.value).type;&lt;br /&gt;
&lt;br /&gt;
    if (!isValueInArray(weaponType, allowedWeapons)) {&lt;br /&gt;
      weaponElement.value = 0;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var children = weaponCategory.children;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; children.length; index++) {&lt;br /&gt;
    var child = children[index];&lt;br /&gt;
&lt;br /&gt;
    if (isValueInArray(index, allowedWeapons)) {&lt;br /&gt;
      showElement(child);&lt;br /&gt;
    } else {&lt;br /&gt;
      hideElement(child);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function changePolymorphValues(characterCreation, monsterVnum, monsterImage) {&lt;br /&gt;
  var { polymorphMonster, polymorphMonsterImage } = characterCreation;&lt;br /&gt;
&lt;br /&gt;
  polymorphMonster.value = monsterVnum;&lt;br /&gt;
  polymorphMonsterImage.value = monsterImage;&lt;br /&gt;
&lt;br /&gt;
  polymorphMonster.dispatchEvent(newChangeEvent());&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function resetImageFromWiki(image) {&lt;br /&gt;
  image.removeAttribute(&amp;quot;srcset&amp;quot;);&lt;br /&gt;
  image.removeAttribute(&amp;quot;data-file-width&amp;quot;);&lt;br /&gt;
  image.removeAttribute(&amp;quot;data-file-height&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleImageFromWiki(image, newSrc) {&lt;br /&gt;
  image.src = newSrc;&lt;br /&gt;
  image.alt = newSrc.split(&amp;quot;/&amp;quot;).pop();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handlePolymorphDisplay(characters, monsterVnum, monsterSrc) {&lt;br /&gt;
  var { translateMonsters, polymorphDisplay } = characters;&lt;br /&gt;
  var oldImage = polymorphDisplay.firstChild;&lt;br /&gt;
  var oldLink = oldImage.nextElementSibling;&lt;br /&gt;
  var monsterName = getMonsterName(monsterVnum);&lt;br /&gt;
  var displayName = translateMonsters&lt;br /&gt;
    ? getTranslatedMonsterName(monsterVnum)&lt;br /&gt;
    : monsterName;&lt;br /&gt;
  var newLink = createWikiLink(monsterName, displayName);&lt;br /&gt;
&lt;br /&gt;
  resetImageFromWiki(oldImage);&lt;br /&gt;
  handleImageFromWiki(oldImage, monsterSrc);&lt;br /&gt;
&lt;br /&gt;
  polymorphDisplay.replaceChild(newLink, oldLink);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createWikiLink(pageName, displayName) {&lt;br /&gt;
  var wikiLink = document.createElement(&amp;quot;a&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  wikiLink.href = mw.util.getUrl(pageName);&lt;br /&gt;
  wikiLink.title = pageName;&lt;br /&gt;
  wikiLink.textContent = displayName || pageName;&lt;br /&gt;
&lt;br /&gt;
  return wikiLink;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSelectedWeapon(weaponCategory) {&lt;br /&gt;
  return weaponCategory.querySelector(&amp;quot;input[type='radio']:checked&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleWeaponDisplay(&lt;br /&gt;
  weaponCategory,&lt;br /&gt;
  weaponDisplay,&lt;br /&gt;
  weaponVnum,&lt;br /&gt;
  newWeapon&lt;br /&gt;
) {&lt;br /&gt;
  var newWeapon = newWeapon || getSelectedWeapon(weaponCategory);&lt;br /&gt;
&lt;br /&gt;
  var newImage = newWeapon.nextElementSibling;&lt;br /&gt;
  var newText = document.createElement(&amp;quot;span&amp;quot;);&lt;br /&gt;
  var oldImage = weaponDisplay.firstChild;&lt;br /&gt;
  var oldText = oldImage.nextElementSibling;&lt;br /&gt;
  var weaponTooltip = newImage.nextElementSibling;&lt;br /&gt;
  var originalWeaponName = weaponTooltip.dataset.o;&lt;br /&gt;
  var weaponName = weaponTooltip.textContent;&lt;br /&gt;
&lt;br /&gt;
  if (weaponVnum == 0) {&lt;br /&gt;
    newText.textContent = weaponName;&lt;br /&gt;
  } else {&lt;br /&gt;
    var weaponLink = createWikiLink(originalWeaponName, weaponName);&lt;br /&gt;
    newText.appendChild(weaponLink);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  weaponDisplay.replaceChild(newImage.cloneNode(), oldImage);&lt;br /&gt;
  weaponDisplay.replaceChild(newText, oldText);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterUpgrade(&lt;br /&gt;
  weaponUpgrade,&lt;br /&gt;
  weaponVnum,&lt;br /&gt;
  randomAttackValue,&lt;br /&gt;
  randomMagicAttackValue&lt;br /&gt;
) {&lt;br /&gt;
  var weapon = createWeapon(weaponVnum);&lt;br /&gt;
  var currentUpgrade = Number(weaponUpgrade.value);&lt;br /&gt;
  var weaponUpgradeChildren = weaponUpgrade.children;&lt;br /&gt;
&lt;br /&gt;
  if (weapon.isSerpent) {&lt;br /&gt;
    showElement(randomAttackValue);&lt;br /&gt;
&lt;br /&gt;
    if (weapon.isMagic) {&lt;br /&gt;
      showElement(randomMagicAttackValue);&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    hideElement(randomAttackValue);&lt;br /&gt;
    hideElement(randomMagicAttackValue);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (weapon.maxUpgrade &amp;lt; 1) {&lt;br /&gt;
    hideElement(weaponUpgrade.parentElement);&lt;br /&gt;
  } else {&lt;br /&gt;
    showElement(weaponUpgrade.parentElement);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (var upgrade = 0; upgrade &amp;lt;= weapon.maxUpgrade; upgrade++) {&lt;br /&gt;
    showElement(weaponUpgradeChildren[upgrade]);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (&lt;br /&gt;
    var upgrade = weapon.maxUpgrade + 1;&lt;br /&gt;
    upgrade &amp;lt; weaponUpgradeChildren.length;&lt;br /&gt;
    upgrade++&lt;br /&gt;
  ) {&lt;br /&gt;
    hideElement(weaponUpgradeChildren[upgrade]);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (currentUpgrade &amp;gt; weapon.maxUpgrade) {&lt;br /&gt;
    weaponUpgrade.value = weapon.maxUpgrade;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterCheckbox(checkbox, element) {&lt;br /&gt;
  if (checkbox.checked) {&lt;br /&gt;
    showElement(element);&lt;br /&gt;
  } else {&lt;br /&gt;
    hideElement(element);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterSkills(selectedClass, skillElementsToFilter) {&lt;br /&gt;
  for (var element of skillElementsToFilter) {&lt;br /&gt;
    if (isValueInArray(selectedClass, element.dataset.class)) {&lt;br /&gt;
      showElement(element);&lt;br /&gt;
    } else {&lt;br /&gt;
      hideElement(element);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterForm(characters, battle) {&lt;br /&gt;
  var { saveButton, characterCreation, toggleSiblings } = characters;&lt;br /&gt;
  var allowedWeaponsPerRace = battle.constants.allowedWeaponsPerRace;&lt;br /&gt;
  var battleChoice = battle.battleChoice;&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;change&amp;quot;, function (event) {&lt;br /&gt;
    var target = event.target;&lt;br /&gt;
    var targetName = target.name;&lt;br /&gt;
&lt;br /&gt;
    saveButtonOrange(saveButton);&lt;br /&gt;
    characters.unsavedChanges = true;&lt;br /&gt;
&lt;br /&gt;
    switch (targetName) {&lt;br /&gt;
      case &amp;quot;race&amp;quot;:&lt;br /&gt;
        var selectedRace = target.value;&lt;br /&gt;
        var classChoice = characterCreation.class;&lt;br /&gt;
        var weaponElement = characterCreation.weapon;&lt;br /&gt;
&lt;br /&gt;
        filterClass(selectedRace, classChoice);&lt;br /&gt;
        filterWeapon(&lt;br /&gt;
          selectedRace,&lt;br /&gt;
          weaponElement,&lt;br /&gt;
          characters.weaponCategory,&lt;br /&gt;
          allowedWeaponsPerRace&lt;br /&gt;
        );&lt;br /&gt;
        handleWeaponDisplay(&lt;br /&gt;
          characters.weaponCategory,&lt;br /&gt;
          characters.weaponDisplay,&lt;br /&gt;
          weaponElement.value&lt;br /&gt;
        );&lt;br /&gt;
        filterUpgrade(&lt;br /&gt;
          characterCreation.weaponUpgrade,&lt;br /&gt;
          weaponElement.value,&lt;br /&gt;
          characters.randomAttackValue,&lt;br /&gt;
          characters.randomMagicAttackValue&lt;br /&gt;
        );&lt;br /&gt;
        filterSkills(classChoice.value, characters.skillElementsToFilter);&lt;br /&gt;
        handleBonusVariationUpdate(&lt;br /&gt;
          characterCreation,&lt;br /&gt;
          characters.bonusVariation,&lt;br /&gt;
          true&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        battleChoice.resetAttackType = true;&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;class&amp;quot;:&lt;br /&gt;
        filterSkills(target.value, characters.skillElementsToFilter);&lt;br /&gt;
        handleBonusVariationUpdate(&lt;br /&gt;
          characterCreation,&lt;br /&gt;
          characters.bonusVariation,&lt;br /&gt;
          true&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        battleChoice.resetAttackType = true;&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;weapon&amp;quot;:&lt;br /&gt;
        var weaponElement = characterCreation.weapon;&lt;br /&gt;
&lt;br /&gt;
        handleWeaponDisplay(&lt;br /&gt;
          characters.weaponCategory,&lt;br /&gt;
          characters.weaponDisplay,&lt;br /&gt;
          weaponElement.value,&lt;br /&gt;
          target&lt;br /&gt;
        );&lt;br /&gt;
        filterUpgrade(&lt;br /&gt;
          characterCreation.weaponUpgrade,&lt;br /&gt;
          target.value,&lt;br /&gt;
          characters.randomAttackValue,&lt;br /&gt;
          characters.randomMagicAttackValue&lt;br /&gt;
        );&lt;br /&gt;
        handleBonusVariationUpdate(&lt;br /&gt;
          characterCreation,&lt;br /&gt;
          characters.bonusVariation&lt;br /&gt;
        );&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;isRiding&amp;quot;:&lt;br /&gt;
        battleChoice.resetAttackType = true;&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;isPolymorph&amp;quot;:&lt;br /&gt;
        battleChoice.resetAttackType = true;&lt;br /&gt;
        break;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (toggleSiblings.hasOwnProperty(targetName)) {&lt;br /&gt;
      filterCheckbox(target, toggleSiblings[targetName]);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      targetName.startsWith(&amp;quot;attackSkill&amp;quot;) ||&lt;br /&gt;
      targetName.startsWith(&amp;quot;horseSkill&amp;quot;)&lt;br /&gt;
    ) {&lt;br /&gt;
      battleChoice.resetAttackType = true;&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addUniquePseudo(characterDataObject, savedCharactersPseudo) {&lt;br /&gt;
  var characterPseudo = String(characterDataObject.name);&lt;br /&gt;
  var originalPseudo = characterPseudo;&lt;br /&gt;
  var count = 0;&lt;br /&gt;
&lt;br /&gt;
  var regex = /(.*)(\d)$/;&lt;br /&gt;
  var match = characterPseudo.match(regex);&lt;br /&gt;
&lt;br /&gt;
  if (match) {&lt;br /&gt;
    originalPseudo = match[1];&lt;br /&gt;
    count = match[2];&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  while (isValueInArray(characterPseudo, savedCharactersPseudo)) {&lt;br /&gt;
    characterPseudo = originalPseudo + count;&lt;br /&gt;
    count++;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  characterDataObject.name = characterPseudo;&lt;br /&gt;
  return [characterDataObject, characterPseudo];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function convertToNumber(value) {&lt;br /&gt;
  var valueNumber = Number(value);&lt;br /&gt;
  return isNaN(valueNumber) ? value : valueNumber;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getLocalStorageValue(key, defaultValue) {&lt;br /&gt;
  var storedValue = localStorage.getItem(key);&lt;br /&gt;
&lt;br /&gt;
  if (storedValue) {&lt;br /&gt;
    return JSON.parse(storedValue);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return defaultValue;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSavedCharacters() {&lt;br /&gt;
  return getLocalStorageValue(&amp;quot;mt2-calc.characters.saved&amp;quot;, {});&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSavedMonsters() {&lt;br /&gt;
  return getLocalStorageValue(&amp;quot;mt2-calc.monsters.saved&amp;quot;, {});&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSavedFights() {&lt;br /&gt;
  return getLocalStorageValue(&amp;quot;mt2-calc.fights.saved&amp;quot;, []);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getLastLang() {&lt;br /&gt;
  return getLocalStorageValue(&amp;quot;mt2-calc.language.last-used&amp;quot;, &amp;quot;&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveToLocalStorage(key, value) {&lt;br /&gt;
  localStorage.setItem(key, JSON.stringify(value));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateSavedCharacters(savedCharacters) {&lt;br /&gt;
  saveToLocalStorage(&amp;quot;mt2-calc.characters.saved&amp;quot;, savedCharacters);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateSavedMonsters(savedMonsters) {&lt;br /&gt;
  saveToLocalStorage(&amp;quot;mt2-calc.monsters.saved&amp;quot;, savedMonsters);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateSavedFights(savedFights) {&lt;br /&gt;
  saveToLocalStorage(&amp;quot;mt2-calc.fights.saved&amp;quot;, savedFights);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateLastLang(lang) {&lt;br /&gt;
  saveToLocalStorage(&amp;quot;mt2-calc.language.last-used&amp;quot;, lang);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveCharacter(&lt;br /&gt;
  savedCharacters,&lt;br /&gt;
  characterCreation,&lt;br /&gt;
  battle,&lt;br /&gt;
  newCharacter,&lt;br /&gt;
  characterDataObject&lt;br /&gt;
) {&lt;br /&gt;
  if (!characterDataObject) {&lt;br /&gt;
    var characterData = new FormData(characterCreation);&lt;br /&gt;
    var characterDataObject = {};&lt;br /&gt;
&lt;br /&gt;
    characterData.forEach(function (value, key) {&lt;br /&gt;
      characterDataObject[key] = convertToNumber(value);&lt;br /&gt;
    });&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var characterPseudo = characterDataObject.name;&lt;br /&gt;
  var { battleChoice } = battle;&lt;br /&gt;
&lt;br /&gt;
  savedCharacters[characterPseudo] = characterDataObject;&lt;br /&gt;
  updateSavedCharacters(savedCharacters);&lt;br /&gt;
&lt;br /&gt;
  if (newCharacter) {&lt;br /&gt;
    addBattleChoice(battleChoice, characterPseudo, characterDataObject);&lt;br /&gt;
  } else {&lt;br /&gt;
    updateBattleChoiceImage(&lt;br /&gt;
      battleChoice,&lt;br /&gt;
      characterPseudo,&lt;br /&gt;
      characterDataObject.race&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (battleChoice.resetAttackType) {&lt;br /&gt;
    if (isCharacterSelected(characterPseudo, battleChoice.attacker.selected)) {&lt;br /&gt;
      filterAttackTypeSelectionCharacter(&lt;br /&gt;
        characterDataObject,&lt;br /&gt;
        battleChoice.attackType&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
    battleChoice.resetAttackType = false;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveButtonGreen(saveButton) {&lt;br /&gt;
  saveButton.classList.remove(&amp;quot;unsaved-character&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveButtonOrange(saveButton) {&lt;br /&gt;
  saveButton.classList.add(&amp;quot;unsaved-character&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function characterCreationListener(characters, battle) {&lt;br /&gt;
  var { characterCreation, saveButton, weaponCategory } = characters;&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;submit&amp;quot;, handleSubmitForm);&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;invalid&amp;quot;, handleInvalidInput, true);&lt;br /&gt;
  document.addEventListener(&amp;quot;keydown&amp;quot;, handleSaveShortcut);&lt;br /&gt;
  weaponCategory.addEventListener(&amp;quot;mouseover&amp;quot;, handleTooltipOverflow);&lt;br /&gt;
&lt;br /&gt;
  function handleSubmitForm(event) {&lt;br /&gt;
    event.preventDefault();&lt;br /&gt;
&lt;br /&gt;
    if (characters.unsavedChanges) {&lt;br /&gt;
      saveCharacter(characters.savedCharacters, characterCreation, battle);&lt;br /&gt;
      saveButtonGreen(saveButton);&lt;br /&gt;
      characters.unsavedChanges = false;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function handleInvalidInput(event) {&lt;br /&gt;
    var target = event.target;&lt;br /&gt;
&lt;br /&gt;
    if (target.checkVisibility()) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var autoCorrectInput = target.closest(&amp;quot;.auto-correct-input&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      autoCorrectInput &amp;amp;&amp;amp;&lt;br /&gt;
      autoCorrectInput.classList.contains(&amp;quot;tabber-noactive&amp;quot;)&lt;br /&gt;
    ) {&lt;br /&gt;
      target.value = target.defaultValue;&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    openTargetTab(target);&lt;br /&gt;
    openTargetCollapsible(target);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function handleSaveShortcut(event) {&lt;br /&gt;
    if (event.ctrlKey &amp;amp;&amp;amp; event.key === &amp;quot;s&amp;quot;) {&lt;br /&gt;
      event.preventDefault();&lt;br /&gt;
      saveButton.click();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function handleTooltipOverflow(event) {&lt;br /&gt;
    var label = event.target.closest(&amp;quot;label&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (label) {&lt;br /&gt;
      var tooltip = label.lastChild;&lt;br /&gt;
&lt;br /&gt;
      if (tooltip.classList.contains(&amp;quot;popContenu&amp;quot;)) {&lt;br /&gt;
        var tooltipRect = tooltip.getBoundingClientRect();&lt;br /&gt;
        var modalRect = weaponCategory.getBoundingClientRect();&lt;br /&gt;
&lt;br /&gt;
        if (tooltipRect.right &amp;gt; modalRect.right) {&lt;br /&gt;
          tooltip.style.left = &amp;quot;-100%&amp;quot;;&lt;br /&gt;
        } else if (tooltipRect.left &amp;lt; modalRect.left) {&lt;br /&gt;
          tooltip.style.left = &amp;quot;200%&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function downloadData(content, type, filename) {&lt;br /&gt;
  var link = document.createElement(&amp;quot;a&amp;quot;);&lt;br /&gt;
  var blob = new Blob([content], { type: type });&lt;br /&gt;
  var blobURL = URL.createObjectURL(blob);&lt;br /&gt;
&lt;br /&gt;
  link.href = blobURL;&lt;br /&gt;
  link.download = filename;&lt;br /&gt;
  document.body.appendChild(link);&lt;br /&gt;
&lt;br /&gt;
  link.click();&lt;br /&gt;
  document.body.removeChild(link);&lt;br /&gt;
  URL.revokeObjectURL(blobURL);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function uploadCharacter(&lt;br /&gt;
  selectedFiles,&lt;br /&gt;
  characters,&lt;br /&gt;
  characterTemplate,&lt;br /&gt;
  charactersContainer,&lt;br /&gt;
  battle&lt;br /&gt;
) {&lt;br /&gt;
  var selectFilesLength = selectedFiles.length;&lt;br /&gt;
  var defaultPseudo = characters.defaultText.pseudo;&lt;br /&gt;
&lt;br /&gt;
  for (var fileIndex = 0; fileIndex &amp;lt; selectFilesLength; fileIndex++) {&lt;br /&gt;
    var selectedFile = selectedFiles[fileIndex];&lt;br /&gt;
&lt;br /&gt;
    if (selectedFile.type === &amp;quot;text/plain&amp;quot;) {&lt;br /&gt;
      var reader = new FileReader();&lt;br /&gt;
      reader.onload = function (e) {&lt;br /&gt;
        var fileContent = e.target.result;&lt;br /&gt;
        try {&lt;br /&gt;
          var characterDataObject = JSON.parse(fileContent);&lt;br /&gt;
&lt;br /&gt;
          if (characterDataObject.hasOwnProperty(&amp;quot;name&amp;quot;)) {&lt;br /&gt;
            var characterPseudo = String(characterDataObject.name);&lt;br /&gt;
&lt;br /&gt;
            hideElement(characters.characterCreation);&lt;br /&gt;
            characterPseudo = validPseudo(characterPseudo, defaultPseudo);&lt;br /&gt;
&lt;br /&gt;
            [characterDataObject, characterPseudo] = addUniquePseudo(&lt;br /&gt;
              characterDataObject,&lt;br /&gt;
              Object.keys(characters.savedCharacters)&lt;br /&gt;
            );&lt;br /&gt;
            var selectedCharacter = handleNewCharacter(&lt;br /&gt;
              characters,&lt;br /&gt;
              characterTemplate,&lt;br /&gt;
              charactersContainer,&lt;br /&gt;
              battle,&lt;br /&gt;
              characterPseudo&lt;br /&gt;
            )[0];&lt;br /&gt;
&lt;br /&gt;
            if (selectFilesLength === 1) {&lt;br /&gt;
              updateForm(&lt;br /&gt;
                characterDataObject,&lt;br /&gt;
                characters.characterCreation,&lt;br /&gt;
                characters,&lt;br /&gt;
                selectedCharacter,&lt;br /&gt;
                battle&lt;br /&gt;
              );&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            saveCharacter(&lt;br /&gt;
              characters.savedCharacters,&lt;br /&gt;
              characters.characterCreation,&lt;br /&gt;
              battle,&lt;br /&gt;
              true,&lt;br /&gt;
              characterDataObject&lt;br /&gt;
            );&lt;br /&gt;
          }&lt;br /&gt;
        } catch (error) {&lt;br /&gt;
          console.warn(error);&lt;br /&gt;
          if (error.name === &amp;quot;TypeError&amp;quot;) {&lt;br /&gt;
            // delete the character&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
      };&lt;br /&gt;
      reader.readAsText(selectedFile);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleUploadCharacter(&lt;br /&gt;
  characters,&lt;br /&gt;
  characterTemplate,&lt;br /&gt;
  charactersContainer,&lt;br /&gt;
  battle&lt;br /&gt;
) {&lt;br /&gt;
  var characterInput = characters.characterInput;&lt;br /&gt;
  var dropZone = characters.dropZone;&lt;br /&gt;
&lt;br /&gt;
  characterInput.accept = &amp;quot;.txt&amp;quot;;&lt;br /&gt;
  characterInput.multiple = true;&lt;br /&gt;
  dropZone.setAttribute(&amp;quot;tabindex&amp;quot;, &amp;quot;0&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  dropZone.addEventListener(&amp;quot;click&amp;quot;, function () {&lt;br /&gt;
    characterInput.click();&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  dropZone.addEventListener(&amp;quot;dragover&amp;quot;, function (event) {&lt;br /&gt;
    event.preventDefault();&lt;br /&gt;
    dropZone.classList.add(&amp;quot;drop-zone--dragover&amp;quot;);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  [&amp;quot;dragleave&amp;quot;, &amp;quot;dragend&amp;quot;].forEach(function (type) {&lt;br /&gt;
    dropZone.addEventListener(type, function () {&lt;br /&gt;
      dropZone.classList.remove(&amp;quot;drop-zone--dragover&amp;quot;);&lt;br /&gt;
    });&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  dropZone.addEventListener(&amp;quot;drop&amp;quot;, function (event) {&lt;br /&gt;
    event.preventDefault();&lt;br /&gt;
    uploadCharacter(&lt;br /&gt;
      event.dataTransfer.files,&lt;br /&gt;
      characters,&lt;br /&gt;
      characterTemplate,&lt;br /&gt;
      charactersContainer,&lt;br /&gt;
      battle&lt;br /&gt;
    );&lt;br /&gt;
    dropZone.classList.remove(&amp;quot;drop-zone--dragover&amp;quot;);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  characterInput.addEventListener(&amp;quot;change&amp;quot;, function (event) {&lt;br /&gt;
    uploadCharacter(&lt;br /&gt;
      event.target.files,&lt;br /&gt;
      characters,&lt;br /&gt;
      characterTemplate,&lt;br /&gt;
      charactersContainer,&lt;br /&gt;
      battle&lt;br /&gt;
    );&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function deleteCharacter(characters, pseudo, element, battle) {&lt;br /&gt;
  delete characters.savedCharacters[pseudo];&lt;br /&gt;
  element.remove();&lt;br /&gt;
&lt;br /&gt;
  updateSavedCharacters(characters.savedCharacters);&lt;br /&gt;
  removeBattleChoice(battle.battleChoice, pseudo, &amp;quot;character&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (&lt;br /&gt;
    !Object.keys(characters.savedCharacters).length ||&lt;br /&gt;
    characters.characterCreation.name.value === pseudo&lt;br /&gt;
  ) {&lt;br /&gt;
    saveButtonGreen(characters.saveButton);&lt;br /&gt;
    characters.unsavedChanges = false;&lt;br /&gt;
    hideElement(characters.characterCreation);&lt;br /&gt;
    showElement(characters.characterCreation.previousElementSibling);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function deleteMonster(characters, battle, monsterVnum) {&lt;br /&gt;
  var monsterElements = characters.monsterElements;&lt;br /&gt;
  var monsterType = characters.savedMonsters[monsterVnum].category;&lt;br /&gt;
&lt;br /&gt;
  if (monsterElements.hasOwnProperty(monsterVnum)) {&lt;br /&gt;
    monsterElements[monsterVnum].remove();&lt;br /&gt;
    delete monsterElements[monsterVnum];&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  delete characters.savedMonsters[monsterVnum];&lt;br /&gt;
&lt;br /&gt;
  updateSavedMonsters(characters.savedMonsters);&lt;br /&gt;
  removeBattleChoice(battle.battleChoice, monsterVnum, monsterType);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleStyle(characters, selectedElement) {&lt;br /&gt;
  var currentCharacter = characters.currentCharacter;&lt;br /&gt;
&lt;br /&gt;
  if (currentCharacter) {&lt;br /&gt;
    currentCharacter.classList.remove(&amp;quot;selected-character&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  selectedElement.classList.add(&amp;quot;selected-character&amp;quot;);&lt;br /&gt;
  characters.currentCharacter = selectedElement;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateForm(&lt;br /&gt;
  formData,&lt;br /&gt;
  characterCreation,&lt;br /&gt;
  characters,&lt;br /&gt;
  selectedElement,&lt;br /&gt;
  battle&lt;br /&gt;
) {&lt;br /&gt;
  saveButtonGreen(characters.saveButton);&lt;br /&gt;
  hideElement(characterCreation.previousElementSibling);&lt;br /&gt;
  showElement(characterCreation);&lt;br /&gt;
  handleStyle(characters, selectedElement);&lt;br /&gt;
&lt;br /&gt;
  characterCreation.reset();&lt;br /&gt;
&lt;br /&gt;
  for (var [name, value] of Object.entries(formData)) {&lt;br /&gt;
    var formElement = characterCreation[name];&lt;br /&gt;
&lt;br /&gt;
    if (!formElement) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (formElement.type === &amp;quot;checkbox&amp;quot;) {&lt;br /&gt;
      if (isChecked(value)) {&lt;br /&gt;
        formElement.checked = true;&lt;br /&gt;
      }&lt;br /&gt;
    } else {&lt;br /&gt;
      formElement.value = value;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  var selectedRace = characterCreation.race.value;&lt;br /&gt;
  var classChoice = characterCreation.class;&lt;br /&gt;
  var weaponElement = characterCreation.weapon;&lt;br /&gt;
&lt;br /&gt;
  filterClass(selectedRace, classChoice, true);&lt;br /&gt;
  filterWeapon(&lt;br /&gt;
    selectedRace,&lt;br /&gt;
    weaponElement,&lt;br /&gt;
    characters.weaponCategory,&lt;br /&gt;
    battle.constants.allowedWeaponsPerRace,&lt;br /&gt;
    true&lt;br /&gt;
  );&lt;br /&gt;
  handlePolymorphDisplay(&lt;br /&gt;
    characters,&lt;br /&gt;
    characterCreation.polymorphMonster.value,&lt;br /&gt;
    characterCreation.polymorphMonsterImage.value&lt;br /&gt;
  );&lt;br /&gt;
  handleWeaponDisplay(&lt;br /&gt;
    characters.weaponCategory,&lt;br /&gt;
    characters.weaponDisplay,&lt;br /&gt;
    weaponElement.value&lt;br /&gt;
  );&lt;br /&gt;
  filterUpgrade(&lt;br /&gt;
    characterCreation.weaponUpgrade,&lt;br /&gt;
    weaponElement.value,&lt;br /&gt;
    characters.randomAttackValue,&lt;br /&gt;
    characters.randomMagicAttackValue&lt;br /&gt;
  );&lt;br /&gt;
  for (var [targetName, sibling] of Object.entries(characters.toggleSiblings)) {&lt;br /&gt;
    filterCheckbox(characterCreation[targetName], sibling);&lt;br /&gt;
  }&lt;br /&gt;
  filterSkills(classChoice.value, characters.skillElementsToFilter);&lt;br /&gt;
  handleBonusVariationUpdate(characterCreation, characters.bonusVariation);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleClickOnCharacter(&lt;br /&gt;
  spanInput,&lt;br /&gt;
  target,&lt;br /&gt;
  characters,&lt;br /&gt;
  characterElement,&lt;br /&gt;
  battle,&lt;br /&gt;
  edition&lt;br /&gt;
) {&lt;br /&gt;
  var displayedPseudo = characters.characterCreation.name.value;&lt;br /&gt;
  var pseudo = spanInput.dataset.name;&lt;br /&gt;
  var { unsavedWarning, deleteWarning } = characters.defaultText;&lt;br /&gt;
&lt;br /&gt;
  if (edition) {&lt;br /&gt;
    if (!characters.unsavedChanges) {&lt;br /&gt;
      updateForm(&lt;br /&gt;
        characters.savedCharacters[pseudo],&lt;br /&gt;
        characters.characterCreation,&lt;br /&gt;
        characters,&lt;br /&gt;
        characterElement,&lt;br /&gt;
        battle&lt;br /&gt;
      );&lt;br /&gt;
    } else if (displayedPseudo === pseudo) {&lt;br /&gt;
      // pass&lt;br /&gt;
    } else {&lt;br /&gt;
      var result = confirm(unsavedWarning);&lt;br /&gt;
&lt;br /&gt;
      if (result) {&lt;br /&gt;
        updateForm(&lt;br /&gt;
          characters.savedCharacters[pseudo],&lt;br /&gt;
          characters.characterCreation,&lt;br /&gt;
          characters,&lt;br /&gt;
          characterElement,&lt;br /&gt;
          battle&lt;br /&gt;
        );&lt;br /&gt;
        characters.unsavedChanges = false;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    if (target.tagName === &amp;quot;path&amp;quot;) {&lt;br /&gt;
      target = target.parentElement;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    switch (target.dataset.icon) {&lt;br /&gt;
      case &amp;quot;duplicate&amp;quot;:&lt;br /&gt;
        if (!characters.unsavedChanges) {&lt;br /&gt;
          addNewCharacter(&lt;br /&gt;
            characters,&lt;br /&gt;
            characters.newCharacterTemplate,&lt;br /&gt;
            characters.charactersContainer,&lt;br /&gt;
            battle,&lt;br /&gt;
            pseudo&lt;br /&gt;
          );&lt;br /&gt;
        } else {&lt;br /&gt;
          var result = confirm(unsavedWarning);&lt;br /&gt;
&lt;br /&gt;
          if (result) {&lt;br /&gt;
            addNewCharacter(&lt;br /&gt;
              characters,&lt;br /&gt;
              characters.newCharacterTemplate,&lt;br /&gt;
              characters.charactersContainer,&lt;br /&gt;
              battle,&lt;br /&gt;
              pseudo&lt;br /&gt;
            );&lt;br /&gt;
            saveButtonGreen(characters.saveButton);&lt;br /&gt;
            characters.unsavedChanges = false;&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
        break;&lt;br /&gt;
&lt;br /&gt;
      case &amp;quot;download&amp;quot;:&lt;br /&gt;
        var character = characters.savedCharacters[pseudo];&lt;br /&gt;
        downloadData(&lt;br /&gt;
          JSON.stringify(character),&lt;br /&gt;
          &amp;quot;text/plain&amp;quot;,&lt;br /&gt;
          character.name + &amp;quot;.txt&amp;quot;&lt;br /&gt;
        );&lt;br /&gt;
        break;&lt;br /&gt;
&lt;br /&gt;
      case &amp;quot;delete&amp;quot;:&lt;br /&gt;
        var result = confirm(deleteWarning.replace(&amp;quot;[[]]&amp;quot;, pseudo));&lt;br /&gt;
        if (result) {&lt;br /&gt;
          deleteCharacter(characters, pseudo, characterElement, battle);&lt;br /&gt;
        }&lt;br /&gt;
        break;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleNewCharacter(&lt;br /&gt;
  characters,&lt;br /&gt;
  characterTemplate,&lt;br /&gt;
  charactersContainer,&lt;br /&gt;
  battle,&lt;br /&gt;
  pseudo&lt;br /&gt;
) {&lt;br /&gt;
  var newCharacterTemplate = characterTemplate.cloneNode(true);&lt;br /&gt;
  var spanInput = newCharacterTemplate.querySelector(&amp;quot;span.input&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  newCharacterTemplate.setAttribute(&amp;quot;tabindex&amp;quot;, &amp;quot;0&amp;quot;);&lt;br /&gt;
  charactersContainer.appendChild(newCharacterTemplate);&lt;br /&gt;
&lt;br /&gt;
  if (pseudo) {&lt;br /&gt;
    spanInput.textContent = pseudo;&lt;br /&gt;
    spanInput.setAttribute(&amp;quot;data-name&amp;quot;, pseudo);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  newCharacterTemplate.addEventListener(&amp;quot;click&amp;quot;, function (event) {&lt;br /&gt;
    var target = event.target;&lt;br /&gt;
&lt;br /&gt;
    if (target.tagName === &amp;quot;path&amp;quot; || target.tagName === &amp;quot;svg&amp;quot;) {&lt;br /&gt;
      handleClickOnCharacter(&lt;br /&gt;
        spanInput,&lt;br /&gt;
        target,&lt;br /&gt;
        characters,&lt;br /&gt;
        newCharacterTemplate,&lt;br /&gt;
        battle&lt;br /&gt;
      );&lt;br /&gt;
    } else {&lt;br /&gt;
      handleClickOnCharacter(&lt;br /&gt;
        spanInput,&lt;br /&gt;
        null,&lt;br /&gt;
        characters,&lt;br /&gt;
        newCharacterTemplate,&lt;br /&gt;
        battle,&lt;br /&gt;
        true&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  newCharacterTemplate.addEventListener(&amp;quot;keydown&amp;quot;, function (event) {&lt;br /&gt;
    if (event.keyCode === 13) {&lt;br /&gt;
      event.target.click();&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  return [newCharacterTemplate, spanInput];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function validPseudo(pseudo, defaultPseudo) {&lt;br /&gt;
  var newPseudo = pseudoFormat(pseudo);&lt;br /&gt;
&lt;br /&gt;
  if (!newPseudo) {&lt;br /&gt;
    return pseudoFormat(defaultPseudo);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return newPseudo;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addNewCharacter(&lt;br /&gt;
  characters,&lt;br /&gt;
  characterTemplate,&lt;br /&gt;
  charactersContainer,&lt;br /&gt;
  battle,&lt;br /&gt;
  pseudoToDuplicate&lt;br /&gt;
) {&lt;br /&gt;
  function editAndSetCharacterPseudoInput(selectedCharacter, spanInput) {&lt;br /&gt;
    var maxPseudoLength = 20;&lt;br /&gt;
    var defaultPseudo = characters.defaultText.pseudo;&lt;br /&gt;
&lt;br /&gt;
    var selection = window.getSelection();&lt;br /&gt;
    var range = document.createRange();&lt;br /&gt;
&lt;br /&gt;
    if (pseudoToDuplicate) {&lt;br /&gt;
      spanInput.textContent = pseudoToDuplicate;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    spanInput.contentEditable = true;&lt;br /&gt;
    spanInput.focus();&lt;br /&gt;
    range.selectNodeContents(spanInput);&lt;br /&gt;
    selection.removeAllRanges();&lt;br /&gt;
    selection.addRange(range);&lt;br /&gt;
&lt;br /&gt;
    function pseudoValidation() {&lt;br /&gt;
      var characterPseudo = validPseudo(spanInput.textContent, defaultPseudo);&lt;br /&gt;
      var characterDataObject = { name: characterPseudo };&lt;br /&gt;
&lt;br /&gt;
      if (pseudoToDuplicate) {&lt;br /&gt;
        characterDataObject = copyObject(&lt;br /&gt;
          characters.savedCharacters[pseudoToDuplicate]&lt;br /&gt;
        );&lt;br /&gt;
        characterDataObject.name = characterPseudo;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      [characterDataObject, characterPseudo] = addUniquePseudo(&lt;br /&gt;
        characterDataObject,&lt;br /&gt;
        Object.keys(characters.savedCharacters)&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      selection.removeAllRanges();&lt;br /&gt;
      spanInput.contentEditable = false;&lt;br /&gt;
      spanInput.textContent = characterPseudo;&lt;br /&gt;
      spanInput.setAttribute(&amp;quot;data-name&amp;quot;, characterPseudo);&lt;br /&gt;
&lt;br /&gt;
      updateForm(&lt;br /&gt;
        characterDataObject,&lt;br /&gt;
        characters.characterCreation,&lt;br /&gt;
        characters,&lt;br /&gt;
        selectedCharacter,&lt;br /&gt;
        battle&lt;br /&gt;
      );&lt;br /&gt;
      saveCharacter(&lt;br /&gt;
        characters.savedCharacters,&lt;br /&gt;
        characters.characterCreation,&lt;br /&gt;
        battle,&lt;br /&gt;
        true&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handleMaxLength(event) {&lt;br /&gt;
      if (spanInput.textContent.length &amp;gt; maxPseudoLength) {&lt;br /&gt;
        spanInput.textContent = spanInput.textContent.slice(0, maxPseudoLength);&lt;br /&gt;
        range.setStart(spanInput.childNodes[0], maxPseudoLength);&lt;br /&gt;
        selection.removeAllRanges();&lt;br /&gt;
        selection.addRange(range);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handleBlur() {&lt;br /&gt;
      spanInput.removeEventListener(&amp;quot;blur&amp;quot;, handleBlur);&lt;br /&gt;
      spanInput.removeEventListener(&amp;quot;input&amp;quot;, handleMaxLength);&lt;br /&gt;
      pseudoValidation();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handleKeyDown(event) {&lt;br /&gt;
      if (event.key === &amp;quot;Enter&amp;quot;) {&lt;br /&gt;
        event.preventDefault();&lt;br /&gt;
&lt;br /&gt;
        spanInput.removeEventListener(&amp;quot;keydown&amp;quot;, handleKeyDown);&lt;br /&gt;
        spanInput.removeEventListener(&amp;quot;blur&amp;quot;, handleBlur);&lt;br /&gt;
        spanInput.removeEventListener(&amp;quot;input&amp;quot;, handleMaxLength);&lt;br /&gt;
&lt;br /&gt;
        pseudoValidation();&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    spanInput.addEventListener(&amp;quot;input&amp;quot;, handleMaxLength);&lt;br /&gt;
    spanInput.addEventListener(&amp;quot;keydown&amp;quot;, handleKeyDown);&lt;br /&gt;
    spanInput.addEventListener(&amp;quot;blur&amp;quot;, handleBlur);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  hideElement(characters.characterCreation);&lt;br /&gt;
  var [selectedCharacter, spanInput] = handleNewCharacter(&lt;br /&gt;
    characters,&lt;br /&gt;
    characterTemplate,&lt;br /&gt;
    charactersContainer,&lt;br /&gt;
    battle&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  editAndSetCharacterPseudoInput(selectedCharacter, spanInput);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleFocus() {&lt;br /&gt;
  var tooltipLinks = document.querySelectorAll(&amp;quot;div.tooltip a&amp;quot;);&lt;br /&gt;
  tooltipLinks.forEach(function (link) {&lt;br /&gt;
    link.setAttribute(&amp;quot;tabindex&amp;quot;, -1);&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function resetBonusVariation(bonusVariation) {&lt;br /&gt;
  function resetInput(input) {&lt;br /&gt;
    input.removeAttribute(&amp;quot;min&amp;quot;);&lt;br /&gt;
    input.removeAttribute(&amp;quot;max&amp;quot;);&lt;br /&gt;
    input.defaultValue = 0;&lt;br /&gt;
    input.value = input.defaultValue;&lt;br /&gt;
  }&lt;br /&gt;
  var { minValue, maxValue, checkbox, container, disabledText, selectedText } =&lt;br /&gt;
    bonusVariation;&lt;br /&gt;
&lt;br /&gt;
  resetInput(minValue);&lt;br /&gt;
  resetInput(maxValue);&lt;br /&gt;
  showElement(disabledText);&lt;br /&gt;
  hideElement(selectedText);&lt;br /&gt;
  hideElement(container);&lt;br /&gt;
  checkbox.checked = false;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleBonusVariationUpdate(&lt;br /&gt;
  characterCreation,&lt;br /&gt;
  bonusVariation,&lt;br /&gt;
  resetSkill&lt;br /&gt;
) {&lt;br /&gt;
  var selectedBonus = characterCreation.bonusVariation.value;&lt;br /&gt;
  var displayName = characterCreation.bonusVariationName.value;&lt;br /&gt;
&lt;br /&gt;
  if (&lt;br /&gt;
    resetSkill &amp;amp;&amp;amp;&lt;br /&gt;
    (selectedBonus.startsWith(&amp;quot;attackSkill&amp;quot;) ||&lt;br /&gt;
      selectedBonus.startsWith(&amp;quot;horseSkill&amp;quot;) ||&lt;br /&gt;
      selectedBonus.startsWith(&amp;quot;skillBonus&amp;quot;))&lt;br /&gt;
  ) {&lt;br /&gt;
    resetBonusVariation(bonusVariation);&lt;br /&gt;
    return;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (&lt;br /&gt;
    characterCreation.hasOwnProperty(selectedBonus) &amp;amp;&amp;amp;&lt;br /&gt;
    selectedBonus != 0 &amp;amp;&amp;amp;&lt;br /&gt;
    displayName != 0&lt;br /&gt;
  ) {&lt;br /&gt;
    handleBonusVariation(&lt;br /&gt;
      characterCreation[selectedBonus],&lt;br /&gt;
      bonusVariation,&lt;br /&gt;
      displayName&lt;br /&gt;
    );&lt;br /&gt;
  } else {&lt;br /&gt;
    resetBonusVariation(bonusVariation);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getTargetContent(targetParent, targetName, isSkill) {&lt;br /&gt;
  var targetContent = &amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  if (targetParent.children.length &amp;lt;= 1) {&lt;br /&gt;
    targetContent = targetParent.textContent;&lt;br /&gt;
  } else if (targetName === &amp;quot;weaponUpgrade&amp;quot;) {&lt;br /&gt;
    targetContent = targetParent.children[1].textContent;&lt;br /&gt;
  } else if (targetName === &amp;quot;level&amp;quot;) {&lt;br /&gt;
    targetContent = targetParent.textContent.replace(&amp;quot;Lv&amp;quot;, &amp;quot;&amp;quot;).trim();&lt;br /&gt;
  } else if (isSkill) {&lt;br /&gt;
    var container = targetParent.children[1];&lt;br /&gt;
&lt;br /&gt;
    for (var index = 0; index &amp;lt; container.children.length; index++) {&lt;br /&gt;
      var element = container.children[index];&lt;br /&gt;
&lt;br /&gt;
      if (element.checkVisibility()) {&lt;br /&gt;
        targetContent += element.textContent;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    for (var index = 1; index &amp;lt; targetParent.children.length; index++) {&lt;br /&gt;
      var element = targetParent.children[index];&lt;br /&gt;
&lt;br /&gt;
      if (element.checkVisibility()) {&lt;br /&gt;
        targetContent += element.textContent;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return targetContent.trim();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleBonusVariation(target, bonusVariation, displayName) {&lt;br /&gt;
  var {&lt;br /&gt;
    minValue,&lt;br /&gt;
    maxValue,&lt;br /&gt;
    checkbox,&lt;br /&gt;
    container,&lt;br /&gt;
    disabledText,&lt;br /&gt;
    selectedText,&lt;br /&gt;
    displaySpan,&lt;br /&gt;
  } = bonusVariation;&lt;br /&gt;
&lt;br /&gt;
  var {&lt;br /&gt;
    min: targetMin,&lt;br /&gt;
    max: targetMax,&lt;br /&gt;
    name: targetName,&lt;br /&gt;
    value: targetValue,&lt;br /&gt;
    parentElement: targetParent,&lt;br /&gt;
    tagName,&lt;br /&gt;
  } = target;&lt;br /&gt;
&lt;br /&gt;
  targetMin = Number(targetMin);&lt;br /&gt;
  targetMax = Number(targetMax);&lt;br /&gt;
  targetValue = Number(targetValue);&lt;br /&gt;
&lt;br /&gt;
  var isSkill = tagName === &amp;quot;SELECT&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  if (isSkill) {&lt;br /&gt;
    var options = target.options;&lt;br /&gt;
&lt;br /&gt;
    targetMin = options[0].value;&lt;br /&gt;
    targetMax = options[options.length - 1].value;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  minValue.min = targetMin;&lt;br /&gt;
  minValue.max = targetMax;&lt;br /&gt;
  minValue.defaultValue = targetMin;&lt;br /&gt;
&lt;br /&gt;
  maxValue.min = targetMin;&lt;br /&gt;
  maxValue.max = targetMax;&lt;br /&gt;
  maxValue.defaultValue = targetMin;&lt;br /&gt;
&lt;br /&gt;
  hideElement(disabledText);&lt;br /&gt;
  showElement(selectedText);&lt;br /&gt;
&lt;br /&gt;
  if (displayName) {&lt;br /&gt;
    minValue.value = Math.min(Math.max(minValue.value, targetMin), targetMax);&lt;br /&gt;
    maxValue.value = Math.max(Math.min(maxValue.value, targetMax), targetMin);&lt;br /&gt;
&lt;br /&gt;
    displaySpan.textContent = displayName;&lt;br /&gt;
  } else {&lt;br /&gt;
    var { input, inputName, tabButton } = bonusVariation;&lt;br /&gt;
    var targetContent = getTargetContent(targetParent, targetName, isSkill);&lt;br /&gt;
&lt;br /&gt;
    input.value = targetName;&lt;br /&gt;
    inputName.value = targetContent;&lt;br /&gt;
    displaySpan.textContent = targetContent;&lt;br /&gt;
&lt;br /&gt;
    minValue.value = Math.max(targetValue - 10, targetMin);&lt;br /&gt;
    maxValue.value = Math.min(targetValue + 10, targetMax);&lt;br /&gt;
&lt;br /&gt;
    showElement(container);&lt;br /&gt;
    checkbox.checked = true;&lt;br /&gt;
&lt;br /&gt;
    tabButton.click();&lt;br /&gt;
    tabButton.scrollIntoView(true);&lt;br /&gt;
&lt;br /&gt;
    input.dispatchEvent(newChangeEvent());&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function characterManagement(characters, battle) {&lt;br /&gt;
  var {&lt;br /&gt;
    newCharacterTemplate: characterTemplate,&lt;br /&gt;
    charactersContainer,&lt;br /&gt;
    addNewCharacterButton,&lt;br /&gt;
    saveButton,&lt;br /&gt;
    characterCreation,&lt;br /&gt;
    bonusVariation,&lt;br /&gt;
    defaultText: { unsavedWarning },&lt;br /&gt;
  } = characters;&lt;br /&gt;
&lt;br /&gt;
  Object.keys(characters.savedCharacters).forEach(function (pseudo) {&lt;br /&gt;
    handleNewCharacter(&lt;br /&gt;
      characters,&lt;br /&gt;
      characterTemplate,&lt;br /&gt;
      charactersContainer,&lt;br /&gt;
      battle,&lt;br /&gt;
      pseudo&lt;br /&gt;
    );&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  addNewCharacterButton.addEventListener(&amp;quot;click&amp;quot;, function (event) {&lt;br /&gt;
    if (!characters.unsavedChanges) {&lt;br /&gt;
      addNewCharacter(&lt;br /&gt;
        characters,&lt;br /&gt;
        characterTemplate,&lt;br /&gt;
        charactersContainer,&lt;br /&gt;
        battle&lt;br /&gt;
      );&lt;br /&gt;
    } else {&lt;br /&gt;
      var result = confirm(unsavedWarning);&lt;br /&gt;
&lt;br /&gt;
      if (result) {&lt;br /&gt;
        addNewCharacter(&lt;br /&gt;
          characters,&lt;br /&gt;
          characterTemplate,&lt;br /&gt;
          charactersContainer,&lt;br /&gt;
          battle&lt;br /&gt;
        );&lt;br /&gt;
        saveButtonGreen(saveButton);&lt;br /&gt;
        characters.unsavedChanges = false;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  handleUploadCharacter(&lt;br /&gt;
    characters,&lt;br /&gt;
    characterTemplate,&lt;br /&gt;
    charactersContainer,&lt;br /&gt;
    battle&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  function handleLongPress(target) {&lt;br /&gt;
    if (target.tagName !== &amp;quot;INPUT&amp;quot; &amp;amp;&amp;amp; target.tagName !== &amp;quot;SELECT&amp;quot;) {&lt;br /&gt;
      target = target.querySelector(&amp;quot;input&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      !target ||&lt;br /&gt;
      (target.type !== &amp;quot;number&amp;quot; &amp;amp;&amp;amp;&lt;br /&gt;
        !target.classList.contains(&amp;quot;skill-select&amp;quot;) &amp;amp;&amp;amp;&lt;br /&gt;
        target.name !== &amp;quot;weaponUpgrade&amp;quot;) ||&lt;br /&gt;
      target.classList.contains(&amp;quot;disabled-variation&amp;quot;)&lt;br /&gt;
    ) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    handleBonusVariation(target, bonusVariation, null);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;click&amp;quot;, function (event) {&lt;br /&gt;
    if (event.shiftKey || event.ctrlKey) {&lt;br /&gt;
      handleLongPress(event.target);&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  var longPressTimer;&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;touchstart&amp;quot;, function (event) {&lt;br /&gt;
    longPressTimer = setTimeout(function () {&lt;br /&gt;
      handleLongPress(event.target);&lt;br /&gt;
    }, 800);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;touchend&amp;quot;, function () {&lt;br /&gt;
    clearTimeout(longPressTimer);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;touchmove&amp;quot;, function () {&lt;br /&gt;
    clearTimeout(longPressTimer);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  filterForm(characters, battle);&lt;br /&gt;
  characterCreationListener(characters, battle);&lt;br /&gt;
  handleFocus();&lt;br /&gt;
&lt;br /&gt;
  window.addEventListener(&amp;quot;beforeunload&amp;quot;, function (event) {&lt;br /&gt;
    if (characters.unsavedChanges) {&lt;br /&gt;
      event.preventDefault();&lt;br /&gt;
      return &amp;quot;&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addMonsterElement(characters, battle, monsterVnum, iframeInfo) {&lt;br /&gt;
  var { monsterTemplate, monstersContainer } = characters;&lt;br /&gt;
  var monsterElement = monsterTemplate.cloneNode(true);&lt;br /&gt;
  var spanInput = monsterElement.querySelector(&amp;quot;span.input&amp;quot;);&lt;br /&gt;
  var deleteSvg = monsterElement.querySelector(&amp;quot;svg&amp;quot;);&lt;br /&gt;
  var monsterName = getMonsterName(monsterVnum);&lt;br /&gt;
  var displayName = characters.translateMonsters&lt;br /&gt;
    ? getTranslatedMonsterName(monsterVnum)&lt;br /&gt;
    : monsterName;&lt;br /&gt;
  var link = createWikiLink(monsterName, displayName);&lt;br /&gt;
&lt;br /&gt;
  monsterElement.setAttribute(&amp;quot;tabindex&amp;quot;, &amp;quot;0&amp;quot;);&lt;br /&gt;
  spanInput.appendChild(link);&lt;br /&gt;
  monstersContainer.appendChild(monsterElement);&lt;br /&gt;
  characters.monsterElements[monsterVnum] = monsterElement;&lt;br /&gt;
&lt;br /&gt;
  deleteSvg.addEventListener(&amp;quot;click&amp;quot;, function () {&lt;br /&gt;
    var monster = characters.savedMonsters[monsterVnum];&lt;br /&gt;
    iframeInfo[monster.category].shouldBeUpdated = true;&lt;br /&gt;
&lt;br /&gt;
    deleteMonster(characters, battle, monsterVnum);&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addNewMonster(&lt;br /&gt;
  characters,&lt;br /&gt;
  battle,&lt;br /&gt;
  monsterVnum,&lt;br /&gt;
  monsterImage,&lt;br /&gt;
  iframeInfo,&lt;br /&gt;
  category&lt;br /&gt;
) {&lt;br /&gt;
  if (isValueInArray(monsterVnum, Object.keys(characters.savedMonsters)))&lt;br /&gt;
    return;&lt;br /&gt;
&lt;br /&gt;
  var newMonster = {&lt;br /&gt;
    image: monsterImage,&lt;br /&gt;
    category: category,&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  characters.savedMonsters[monsterVnum] = newMonster;&lt;br /&gt;
&lt;br /&gt;
  addMonsterElement(characters, battle, monsterVnum, iframeInfo);&lt;br /&gt;
  updateSavedMonsters(characters.savedMonsters);&lt;br /&gt;
  addBattleChoice(battle.battleChoice, monsterVnum, newMonster, true);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function translateiFrame(iframeDoc) {&lt;br /&gt;
  const filterName = iframeDoc.getElementById(&amp;quot;filter-name&amp;quot;);&lt;br /&gt;
  const { general, special } = translation;&lt;br /&gt;
  const translatedPlaceholder = special.placeholder;&lt;br /&gt;
&lt;br /&gt;
  if (filterName &amp;amp;&amp;amp; translatedPlaceholder) {&lt;br /&gt;
    filterName.placeholder = translatedPlaceholder;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (const element of iframeDoc.querySelectorAll(&amp;quot;[data-t]&amp;quot;)) {&lt;br /&gt;
    const translateText = general[element.dataset.t];&lt;br /&gt;
&lt;br /&gt;
    if (translateText) {&lt;br /&gt;
      element.textContent = translateText;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function translateMonsterCard(card, cardNameElement, monsterVnum) {&lt;br /&gt;
  const mapping = translation.mapping;&lt;br /&gt;
  const levelElement = card.querySelector(&amp;quot;[data-level]&amp;quot;);&lt;br /&gt;
  const typeElement = card.querySelector(&amp;quot;[data-type] a&amp;quot;);&lt;br /&gt;
  const damageElements = card.querySelectorAll(&amp;quot;[data-damage] a&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  cardNameElement.textContent = getTranslatedMonsterName(monsterVnum);&lt;br /&gt;
&lt;br /&gt;
  levelElement.textContent = levelElement.textContent.replace(&lt;br /&gt;
    &amp;quot;Boss&amp;quot;,&lt;br /&gt;
    translation.special.boss&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  if (typeElement) {&lt;br /&gt;
    typeElement.textContent = mapping[typeElement.textContent];&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  damageElements.forEach((damageElement) =&amp;gt; {&lt;br /&gt;
    damageElement.textContent = mapping[damageElement.textContent];&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addButtonsToCardsAndTranslate(&lt;br /&gt;
  characters,&lt;br /&gt;
  iframeDoc,&lt;br /&gt;
  iframeInfo,&lt;br /&gt;
  category&lt;br /&gt;
) {&lt;br /&gt;
  const buttonTemplates = characters.monsterButtonTemplates.children[0];&lt;br /&gt;
  const cardToEdit = iframeDoc.getElementById(&amp;quot;cards-container&amp;quot;).children;&lt;br /&gt;
  const { nameToVnum } = iframeInfo;&lt;br /&gt;
  const vnumToButtons = iframeInfo[category].vnumToButtons;&lt;br /&gt;
  const translateMonsters = characters.translateMonsters;&lt;br /&gt;
&lt;br /&gt;
  for (let cardIndex = 0; cardIndex &amp;lt; cardToEdit.length; cardIndex++) {&lt;br /&gt;
    const card = cardToEdit[cardIndex];&lt;br /&gt;
    const cardNameElement = card.querySelector(&amp;quot;[data-name]&amp;quot;).firstChild;&lt;br /&gt;
    const buttonTemplatesClone = buttonTemplates.cloneNode(true);&lt;br /&gt;
    const cardName = cardNameElement.title.replace(/\s/g, &amp;quot; &amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (!nameToVnum.hasOwnProperty(cardName)) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    const monsterVnum = nameToVnum[cardName];&lt;br /&gt;
&lt;br /&gt;
    buttonTemplatesClone.dataset.monsterId = monsterVnum;&lt;br /&gt;
    card.lastElementChild.appendChild(buttonTemplatesClone);&lt;br /&gt;
    vnumToButtons[monsterVnum] = buttonTemplatesClone.children;&lt;br /&gt;
&lt;br /&gt;
    if (translateMonsters) {&lt;br /&gt;
      translateMonsterCard(card, cardNameElement, monsterVnum);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (translateMonsters) {&lt;br /&gt;
    translateiFrame(iframeDoc);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateiFrameButtons(characters, iframeInfo, category) {&lt;br /&gt;
  var addedMonsters = Object.keys(characters.savedMonsters);&lt;br /&gt;
  var { currentiFrameIsMonster } = iframeInfo;&lt;br /&gt;
  var vnumToButtons = iframeInfo[category].vnumToButtons;&lt;br /&gt;
  var isPolymorphModal = category === &amp;quot;monster&amp;quot; &amp;amp;&amp;amp; !currentiFrameIsMonster;&lt;br /&gt;
&lt;br /&gt;
  for (var monsterVnum in vnumToButtons) {&lt;br /&gt;
    var [addButton, deleteButton, selectButton] = vnumToButtons[monsterVnum];&lt;br /&gt;
&lt;br /&gt;
    if (isPolymorphModal) {&lt;br /&gt;
      hideElement(addButton);&lt;br /&gt;
      hideElement(deleteButton);&lt;br /&gt;
      showElement(selectButton);&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isValueInArray(monsterVnum, addedMonsters)) {&lt;br /&gt;
      hideElement(addButton);&lt;br /&gt;
      showElement(deleteButton);&lt;br /&gt;
      hideElement(selectButton);&lt;br /&gt;
    } else {&lt;br /&gt;
      showElement(addButton);&lt;br /&gt;
      hideElement(deleteButton);&lt;br /&gt;
      hideElement(selectButton);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  iframeInfo.lastiFrameIsMonster = currentiFrameIsMonster;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getMonsterImage(buttonsContainer) {&lt;br /&gt;
  var elder = buttonsContainer.parentElement.firstElementChild;&lt;br /&gt;
  var image = elder.querySelector(&amp;quot;img&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (image) {&lt;br /&gt;
    return image.getAttribute(&amp;quot;src&amp;quot;) || &amp;quot;&amp;quot;;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return &amp;quot;&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleiFrame(iframeInfo, category) {&lt;br /&gt;
  var { characters, battle } = iframeInfo;&lt;br /&gt;
  var iframeInfoCategory = iframeInfo[category];&lt;br /&gt;
  var { iframe, pageName, vnumToButtons } = iframeInfoCategory;&lt;br /&gt;
  var loadingAnimation = iframeInfoCategory.iframe.previousElementSibling;&lt;br /&gt;
&lt;br /&gt;
  iframe.src = mw.util.getUrl(pageName);&lt;br /&gt;
&lt;br /&gt;
  iframe.addEventListener(&amp;quot;load&amp;quot;, function () {&lt;br /&gt;
    var iframeDoc = this.contentDocument || this.contentWindow.document;&lt;br /&gt;
    var htmlElement = iframeDoc.documentElement;&lt;br /&gt;
    var iframeBody = iframeDoc.body;&lt;br /&gt;
    var content = iframeDoc.getElementById(&amp;quot;show-after-loading&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    htmlElement.setAttribute(&amp;quot;lang&amp;quot;, characters.currentLanguage);&lt;br /&gt;
    iframeBody.firstElementChild.replaceWith(content);&lt;br /&gt;
&lt;br /&gt;
    iframeBody.style.background = &amp;quot;transparent&amp;quot;;&lt;br /&gt;
    iframeBody.style.paddingRight = &amp;quot;10px&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    addButtonsToCardsAndTranslate(characters, iframeDoc, iframeInfo, category);&lt;br /&gt;
    updateiFrameButtons(characters, iframeInfo, category);&lt;br /&gt;
&lt;br /&gt;
    iframeInfoCategory.loadIsFinished = true;&lt;br /&gt;
&lt;br /&gt;
    hideElement(loadingAnimation);&lt;br /&gt;
    showElement(iframe);&lt;br /&gt;
&lt;br /&gt;
    iframeDoc.addEventListener(&amp;quot;click&amp;quot;, handleButtonClick);&lt;br /&gt;
&lt;br /&gt;
    function handleButtonClick(event) {&lt;br /&gt;
      var target = event.target;&lt;br /&gt;
      var link = target.closest(&amp;quot;a&amp;quot;);&lt;br /&gt;
      var buttonsContainer = target.closest(&amp;quot;.handle-monster&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
      if (link) {&lt;br /&gt;
        event.preventDefault();&lt;br /&gt;
        window.open(link.href, &amp;quot;_blank&amp;quot;);&lt;br /&gt;
      } else if (buttonsContainer) {&lt;br /&gt;
        var { monsterId: monsterVnum } = buttonsContainer.dataset;&lt;br /&gt;
&lt;br /&gt;
        // polymorph iframe&lt;br /&gt;
        if (category === &amp;quot;monster&amp;quot; &amp;amp;&amp;amp; !iframeInfo.currentiFrameIsMonster) {&lt;br /&gt;
          var monsterImage = getMonsterImage(buttonsContainer);&lt;br /&gt;
          changePolymorphValues(&lt;br /&gt;
            characters.characterCreation,&lt;br /&gt;
            monsterVnum,&lt;br /&gt;
            monsterImage&lt;br /&gt;
          );&lt;br /&gt;
          handlePolymorphDisplay(characters, monsterVnum, monsterImage);&lt;br /&gt;
          iframe.dispatchEvent(newChangeEvent());&lt;br /&gt;
        } else {&lt;br /&gt;
          var addedMonsters = Object.keys(characters.savedMonsters);&lt;br /&gt;
          var [addButton, deleteButton] = vnumToButtons[monsterVnum];&lt;br /&gt;
&lt;br /&gt;
          if (isValueInArray(monsterVnum, addedMonsters)) {&lt;br /&gt;
            deleteMonster(characters, battle, monsterVnum);&lt;br /&gt;
            showElement(addButton);&lt;br /&gt;
            hideElement(deleteButton);&lt;br /&gt;
          } else {&lt;br /&gt;
            var monsterImage = getMonsterImage(buttonsContainer);&lt;br /&gt;
            addNewMonster(&lt;br /&gt;
              characters,&lt;br /&gt;
              battle,&lt;br /&gt;
              monsterVnum,&lt;br /&gt;
              monsterImage,&lt;br /&gt;
              iframeInfo,&lt;br /&gt;
              category&lt;br /&gt;
            );&lt;br /&gt;
            hideElement(addButton);&lt;br /&gt;
            showElement(deleteButton);&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getNameToVnumMapping() {&lt;br /&gt;
  var nameToVnum = {};&lt;br /&gt;
&lt;br /&gt;
  for (var monsterVnum in monsterData) {&lt;br /&gt;
    nameToVnum[monsterData[monsterVnum][monsterData[monsterVnum].length - 1]] =&lt;br /&gt;
      monsterVnum;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return nameToVnum;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function monsterManagement(characters, battle) {&lt;br /&gt;
  var { monsteriFrame, stoneiFrame } = characters;&lt;br /&gt;
  var monsterVnums = Object.keys(monsterData);&lt;br /&gt;
&lt;br /&gt;
  var iframeInfo = {&lt;br /&gt;
    lastiFrameIsMonster: false,&lt;br /&gt;
    currentiFrameIsMonster: false,&lt;br /&gt;
    characters: characters,&lt;br /&gt;
    battle: battle,&lt;br /&gt;
    nameToVnum: getNameToVnumMapping(),&lt;br /&gt;
    monster: {&lt;br /&gt;
      isLoaded: false,&lt;br /&gt;
      loadIsFinished: false,&lt;br /&gt;
      shouldBeUpdated: false,&lt;br /&gt;
      vnumToButtons: {},&lt;br /&gt;
      pageName: &amp;quot;Monstres&amp;quot;,&lt;br /&gt;
      iframe: monsteriFrame,&lt;br /&gt;
    },&lt;br /&gt;
    stone: {&lt;br /&gt;
      isLoaded: false,&lt;br /&gt;
      loadIsFinished: false,&lt;br /&gt;
      shouldBeUpdated: false,&lt;br /&gt;
      vnumToButtons: {},&lt;br /&gt;
      pageName: &amp;quot;Pierres Metin&amp;quot;,&lt;br /&gt;
      iframe: stoneiFrame,&lt;br /&gt;
    },&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  document.addEventListener(&amp;quot;modalOpen&amp;quot;, function (event) {&lt;br /&gt;
    var modalName = event.detail.name;&lt;br /&gt;
&lt;br /&gt;
    if (modalName === &amp;quot;monster&amp;quot; || modalName === &amp;quot;stone&amp;quot;) {&lt;br /&gt;
      handleModal(event.target, modalName);&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  function handleModal(target, modalName) {&lt;br /&gt;
    var iframeInfoCategory = iframeInfo[modalName];&lt;br /&gt;
&lt;br /&gt;
    if (modalName === &amp;quot;monster&amp;quot;) {&lt;br /&gt;
      var isMonsteriFrame = target.id === &amp;quot;add-new-monster&amp;quot;;&lt;br /&gt;
      iframeInfo.currentiFrameIsMonster = isMonsteriFrame;&lt;br /&gt;
&lt;br /&gt;
      if (&lt;br /&gt;
        iframeInfoCategory.loadIsFinished &amp;amp;&amp;amp;&lt;br /&gt;
        ((isMonsteriFrame &amp;amp;&amp;amp; !iframeInfo.lastiFrameIsMonster) ||&lt;br /&gt;
          (!isMonsteriFrame &amp;amp;&amp;amp; iframeInfo.lastiFrameIsMonster))&lt;br /&gt;
      ) {&lt;br /&gt;
        iframeInfoCategory.shouldBeUpdated = true;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!iframeInfoCategory.isLoaded) {&lt;br /&gt;
      handleiFrame(iframeInfo, modalName);&lt;br /&gt;
      iframeInfoCategory.isLoaded = true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      iframeInfoCategory.loadIsFinished &amp;amp;&amp;amp;&lt;br /&gt;
      iframeInfoCategory.shouldBeUpdated&lt;br /&gt;
    ) {&lt;br /&gt;
      updateiFrameButtons(characters, iframeInfo, modalName);&lt;br /&gt;
      iframeInfoCategory.shouldBeUpdated = false;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  Object.keys(characters.savedMonsters)&lt;br /&gt;
    .slice()&lt;br /&gt;
    .forEach(function (monsterVnum) {&lt;br /&gt;
      if (isValueInArray(monsterVnum, monsterVnums)) {&lt;br /&gt;
        addMonsterElement(characters, battle, monsterVnum, iframeInfo);&lt;br /&gt;
      } else {&lt;br /&gt;
        deleteMonster(characters, battle, monsterVnum);&lt;br /&gt;
      }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function hideAttackType(container, input, attackType) {&lt;br /&gt;
  hideElement(container);&lt;br /&gt;
&lt;br /&gt;
  if (input.checked) {&lt;br /&gt;
    var defaultInput = attackType.defaultInput;&lt;br /&gt;
&lt;br /&gt;
    input.checked = false;&lt;br /&gt;
    defaultInput.checked = true;&lt;br /&gt;
    defaultInput.dispatchEvent(newChangeEvent());&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterAttackTypeSelectionCharacter(attacker, attackType) {&lt;br /&gt;
  var attackerClass = attacker.class;&lt;br /&gt;
  var attackerIsNotPolymorph = !isPolymorph(attacker);&lt;br /&gt;
  var { elements: attackTypeElements } = attackType;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; attackTypeElements.length; index++) {&lt;br /&gt;
    var { container, input, inputClass, inputValue } =&lt;br /&gt;
      attackTypeElements[index];&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      attackerIsNotPolymorph &amp;amp;&amp;amp;&lt;br /&gt;
      attacker[inputValue] &amp;amp;&amp;amp;&lt;br /&gt;
      (attackerClass === inputClass ||&lt;br /&gt;
        (inputValue.startsWith(&amp;quot;horseSkill&amp;quot;) &amp;amp;&amp;amp;&lt;br /&gt;
          isRiding(attacker) &amp;amp;&amp;amp;&lt;br /&gt;
          (!inputClass || isValueInArray(attackerClass, inputClass))))&lt;br /&gt;
    ) {&lt;br /&gt;
      showElement(container);&lt;br /&gt;
    } else {&lt;br /&gt;
      hideAttackType(container, input, attackType);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterAttackTypeSelectionMonster(attackType) {&lt;br /&gt;
  var attackTypeElements = attackType.elements;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; attackTypeElements.length; index++) {&lt;br /&gt;
    var { container, input } = attackTypeElements[index];&lt;br /&gt;
    hideAttackType(container, input, attackType);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function removeBattleElement(battleChoice, nameOrVnum, category, type) {&lt;br /&gt;
  var elements = battleChoice[category][type].elements;&lt;br /&gt;
&lt;br /&gt;
  if (elements.hasOwnProperty(nameOrVnum)) {&lt;br /&gt;
    elements[nameOrVnum].container.remove();&lt;br /&gt;
    delete elements[nameOrVnum];&lt;br /&gt;
    battleChoice[category][type].count--;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function removeBattleChoice(battleChoice, nameOrVnum, type) {&lt;br /&gt;
  battleChoice.categories.forEach(function (category) {&lt;br /&gt;
    if (category === &amp;quot;attacker&amp;quot; &amp;amp;&amp;amp; type === &amp;quot;stone&amp;quot;) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
    var selected = battleChoice[category].selected;&lt;br /&gt;
&lt;br /&gt;
    if (selected) {&lt;br /&gt;
      var { type: selectedType, nameOrVnum: selectedNameOrVnum } =&lt;br /&gt;
        parseTypeAndName(selected);&lt;br /&gt;
&lt;br /&gt;
      if (nameOrVnum === selectedNameOrVnum &amp;amp;&amp;amp; type === selectedType) {&lt;br /&gt;
        resetBattleChoiceButton(battleChoice, category);&lt;br /&gt;
        battleChoice[category].selected = null;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    removeBattleElement(battleChoice, nameOrVnum, category, type);&lt;br /&gt;
    updateBattleChoiceText(battleChoice, category, type);&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addBattleElement(&lt;br /&gt;
  battleChoice,&lt;br /&gt;
  pseudoOrVnum,&lt;br /&gt;
  characterOrMonster,&lt;br /&gt;
  category,&lt;br /&gt;
  isMonster&lt;br /&gt;
) {&lt;br /&gt;
  var { template, raceToImage, translateMonsters } = battleChoice;&lt;br /&gt;
  var battleChoiceCategory = battleChoice[category];&lt;br /&gt;
  var templateClone = template.cloneNode(true);&lt;br /&gt;
  var label = templateClone.firstElementChild;&lt;br /&gt;
  var [input, image, span] = label.children;&lt;br /&gt;
  var imageSrc;&lt;br /&gt;
  var name;&lt;br /&gt;
  var type;&lt;br /&gt;
&lt;br /&gt;
  if (isMonster) {&lt;br /&gt;
    type = characterOrMonster.category;&lt;br /&gt;
&lt;br /&gt;
    if (type === &amp;quot;stone&amp;quot; &amp;amp;&amp;amp; category === &amp;quot;attacker&amp;quot;) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
    imageSrc = characterOrMonster.image;&lt;br /&gt;
    name = translateMonsters&lt;br /&gt;
      ? getTranslatedMonsterName(pseudoOrVnum)&lt;br /&gt;
      : getMonsterName(pseudoOrVnum);&lt;br /&gt;
  } else {&lt;br /&gt;
    type = &amp;quot;character&amp;quot;;&lt;br /&gt;
    imageSrc = raceToImage[characterOrMonster.race];&lt;br /&gt;
    name = pseudoOrVnum;&lt;br /&gt;
    label.classList.add(&amp;quot;notranslate&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var value = type + &amp;quot;-&amp;quot; + pseudoOrVnum;&lt;br /&gt;
  var id = category + &amp;quot;-&amp;quot; + value;&lt;br /&gt;
  var currentBattleChoice = battleChoiceCategory[type];&lt;br /&gt;
&lt;br /&gt;
  label.setAttribute(&amp;quot;for&amp;quot;, id);&lt;br /&gt;
  input.value = value;&lt;br /&gt;
  input.id = id;&lt;br /&gt;
  input.name = category;&lt;br /&gt;
  span.textContent = name;&lt;br /&gt;
&lt;br /&gt;
  handleImageFromWiki(image, imageSrc);&lt;br /&gt;
&lt;br /&gt;
  currentBattleChoice.container.appendChild(templateClone);&lt;br /&gt;
  currentBattleChoice.count++;&lt;br /&gt;
  currentBattleChoice.elements[pseudoOrVnum] = {&lt;br /&gt;
    container: templateClone,&lt;br /&gt;
    image: image,&lt;br /&gt;
    name: name,&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  updateBattleChoiceText(battleChoice, category, type);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addBattleChoice(&lt;br /&gt;
  battleChoice,&lt;br /&gt;
  pseudoOrVnum,&lt;br /&gt;
  characterOrMonster,&lt;br /&gt;
  isMonster = false&lt;br /&gt;
) {&lt;br /&gt;
  addBattleElement(&lt;br /&gt;
    battleChoice,&lt;br /&gt;
    pseudoOrVnum,&lt;br /&gt;
    characterOrMonster,&lt;br /&gt;
    &amp;quot;attacker&amp;quot;,&lt;br /&gt;
    isMonster&lt;br /&gt;
  );&lt;br /&gt;
  addBattleElement(&lt;br /&gt;
    battleChoice,&lt;br /&gt;
    pseudoOrVnum,&lt;br /&gt;
    characterOrMonster,&lt;br /&gt;
    &amp;quot;victim&amp;quot;,&lt;br /&gt;
    isMonster&lt;br /&gt;
  );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateBattleChoiceImage(battleChoice, characterName, newRace) {&lt;br /&gt;
  var imageSrc = battleChoice.raceToImage[newRace];&lt;br /&gt;
&lt;br /&gt;
  battleChoice.categories.forEach(function (category) {&lt;br /&gt;
    handleImageFromWiki(&lt;br /&gt;
      battleChoice[category].character.elements[characterName].image,&lt;br /&gt;
      imageSrc&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    var selected = battleChoice[category].selected;&lt;br /&gt;
&lt;br /&gt;
    if (isCharacterSelected(characterName, selected)) {&lt;br /&gt;
      updateBattleChoiceButton(battleChoice, category, selected);&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateBattleChoiceText(battleChoice, category, type) {&lt;br /&gt;
  var { count, container } = battleChoice[category][type];&lt;br /&gt;
  var parentContainer = container.parentElement;&lt;br /&gt;
&lt;br /&gt;
  if (count === 0) {&lt;br /&gt;
    hideElement(parentContainer);&lt;br /&gt;
    showElement(parentContainer.nextElementSibling);&lt;br /&gt;
  } else if (count === 1) {&lt;br /&gt;
    showElement(parentContainer);&lt;br /&gt;
    hideElement(parentContainer.nextElementSibling);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateBattleChoice(characters, battleChoice) {&lt;br /&gt;
  var templateImage = battleChoice.template.querySelector(&amp;quot;img&amp;quot;);&lt;br /&gt;
  var attackerImage = battleChoice.attacker.buttonContent.querySelector(&amp;quot;img&amp;quot;);&lt;br /&gt;
  var victimImage = battleChoice.victim.buttonContent.querySelector(&amp;quot;img&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  resetImageFromWiki(templateImage);&lt;br /&gt;
  resetImageFromWiki(attackerImage);&lt;br /&gt;
  resetImageFromWiki(victimImage);&lt;br /&gt;
&lt;br /&gt;
  for (var [pseudo, character] of Object.entries(characters.savedCharacters)) {&lt;br /&gt;
    addBattleChoice(battleChoice, pseudo, character);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (var [vnum, monster] of Object.entries(characters.savedMonsters)) {&lt;br /&gt;
    addBattleChoice(battleChoice, vnum, monster, true);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateBattleChoiceButton(battleChoice, category, data) {&lt;br /&gt;
  var battleChoiceCategory = battleChoice[category];&lt;br /&gt;
  var { defaultButtonContent, buttonContent } = battleChoiceCategory;&lt;br /&gt;
  var [buttonImage, buttonSpan] = buttonContent.firstElementChild.children;&lt;br /&gt;
  var { type, nameOrVnum } = parseTypeAndName(data);&lt;br /&gt;
  var { name, image } = battleChoiceCategory[type].elements[nameOrVnum];&lt;br /&gt;
&lt;br /&gt;
  hideElement(defaultButtonContent);&lt;br /&gt;
  showElement(buttonContent);&lt;br /&gt;
&lt;br /&gt;
  buttonSpan.textContent = name;&lt;br /&gt;
  buttonImage.src = image.src;&lt;br /&gt;
  battleChoiceCategory.selected = data;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function resetBattleChoiceButton(battleChoice, category) {&lt;br /&gt;
  var { defaultButtonContent, buttonContent } = battleChoice[category];&lt;br /&gt;
&lt;br /&gt;
  showElement(defaultButtonContent);&lt;br /&gt;
  hideElement(buttonContent);&lt;br /&gt;
&lt;br /&gt;
  if (category === &amp;quot;attacker&amp;quot;) {&lt;br /&gt;
    filterAttackTypeSelectionMonster(battleChoice.attackType);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isPC(character) {&lt;br /&gt;
  if (character.race === 0 || character.race === 1) {&lt;br /&gt;
    return false;&lt;br /&gt;
  }&lt;br /&gt;
  return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isBoss(character) {&lt;br /&gt;
  return character.race === 0 &amp;amp;&amp;amp; character.rank &amp;gt;= 5;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isStone(character) {&lt;br /&gt;
  return character.race === 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isMeleeAttacker(monster) {&lt;br /&gt;
  return monster.attack == 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isRangeAttacker(monster) {&lt;br /&gt;
  return monster.attack == 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isMagicAttacker(monster) {&lt;br /&gt;
  return monster.attack == 2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isMagicClass(character) {&lt;br /&gt;
  return character.race === &amp;quot;shaman&amp;quot; || character.class === &amp;quot;black_magic&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isDispell(character, skillId) {&lt;br /&gt;
  return character.class === &amp;quot;weaponary&amp;quot; &amp;amp;&amp;amp; skillId === 6;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isPolymorph(character) {&lt;br /&gt;
  return isChecked(character.isPolymorph);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isRiding(character) {&lt;br /&gt;
  return isChecked(character.isRiding);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isBow(weaponType) {&lt;br /&gt;
  return weaponType === 2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcAttackFactor(attacker, victim) {&lt;br /&gt;
  function calcCoeffK(dex, level) {&lt;br /&gt;
    return Math.min(90, Math.floor((2 * dex + level) / 3));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var K1 = calcCoeffK(attacker.polymorphDex, attacker.level);&lt;br /&gt;
  var K2 = calcCoeffK(victim.polymorphDex, attacker.level);&lt;br /&gt;
&lt;br /&gt;
  var AR = (K1 + 210) / 300;&lt;br /&gt;
  var ER = (((2 * K2 + 5) / (K2 + 95)) * 3) / 10;&lt;br /&gt;
&lt;br /&gt;
  return truncateNumber(AR - ER, 8);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcMainAttackValue(attacker) {&lt;br /&gt;
  var leadership = 0;&lt;br /&gt;
  var weaponGrowth = 0;&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker)) {&lt;br /&gt;
    weaponGrowth = attacker.weapon.growth;&lt;br /&gt;
    leadership = attacker.leadership;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return 2 * (attacker.level + weaponGrowth) + leadership;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcStatAttackValue(character) {&lt;br /&gt;
  switch (character.race) {&lt;br /&gt;
    case &amp;quot;warrior&amp;quot;:&lt;br /&gt;
    case &amp;quot;sura&amp;quot;:&lt;br /&gt;
      return 2 * character.str;&lt;br /&gt;
    case &amp;quot;ninja&amp;quot;:&lt;br /&gt;
      return Math.floor((1 / 4) * (character.str + 7 * character.dex));&lt;br /&gt;
    case &amp;quot;shaman&amp;quot;:&lt;br /&gt;
      return Math.floor((1 / 3) * (5 * character.int + character.dex));&lt;br /&gt;
    case &amp;quot;lycan&amp;quot;:&lt;br /&gt;
      return character.vit + 2 * character.dex;&lt;br /&gt;
    default:&lt;br /&gt;
      return 2 * character.str;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcPvpCriticalAttackRange(minAttackValue, maxAttackValue, growth) {&lt;br /&gt;
  return Array.from(&lt;br /&gt;
    { length: maxAttackValue - minAttackValue + 1 },&lt;br /&gt;
    (_, index) =&amp;gt; (minAttackValue + growth + index) * 2&lt;br /&gt;
  );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcSecondaryAttackValue(attacker, isPlayerVsPlayer) {&lt;br /&gt;
  let attackValueOther = 0;&lt;br /&gt;
&lt;br /&gt;
  let minAttackValue = 0;&lt;br /&gt;
  let maxAttackValue = 0;&lt;br /&gt;
&lt;br /&gt;
  let minAttackValueSlash = 0;&lt;br /&gt;
  let maxAttackValueSlash = 0;&lt;br /&gt;
&lt;br /&gt;
  let type, isSerpent, growth;&lt;br /&gt;
&lt;br /&gt;
  let criticalAttackRange;&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker)) {&lt;br /&gt;
    ({ type, isSerpent, minAttackValue, maxAttackValue, growth } =&lt;br /&gt;
      attacker.weapon);&lt;br /&gt;
&lt;br /&gt;
    if (isSerpent) {&lt;br /&gt;
      minAttackValue = Math.max(0, attacker.minAttackValueRandom - growth);&lt;br /&gt;
      maxAttackValue = Math.max(&lt;br /&gt;
        minAttackValue,&lt;br /&gt;
        attacker.maxAttackValueRandom - growth&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    minAttackValueSlash = Math.min(&lt;br /&gt;
      attacker.minAttackValueSlash,&lt;br /&gt;
      attacker.maxAttackValueSlash&lt;br /&gt;
    );&lt;br /&gt;
    maxAttackValueSlash = Math.max(&lt;br /&gt;
      attacker.minAttackValueSlash,&lt;br /&gt;
      attacker.maxAttackValueSlash&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    attackValueOther += attacker.attackValue;&lt;br /&gt;
&lt;br /&gt;
    if (isBow(type) &amp;amp;&amp;amp; !isPolymorph(attacker)) {&lt;br /&gt;
      attackValueOther += 25;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isPlayerVsPlayer) {&lt;br /&gt;
      criticalAttackRange = calcPvpCriticalAttackRange(&lt;br /&gt;
        minAttackValue,&lt;br /&gt;
        maxAttackValue,&lt;br /&gt;
        growth&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    minAttackValue = attacker.minAttackValue;&lt;br /&gt;
    maxAttackValue = attacker.maxAttackValue;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  minAttackValue += attacker.minAttackValuePolymorph;&lt;br /&gt;
  maxAttackValue += attacker.maxAttackValuePolymorph;&lt;br /&gt;
&lt;br /&gt;
  attackValueOther += attacker.statAttackValue;&lt;br /&gt;
  attackValueOther += attacker.horseAttackValue;&lt;br /&gt;
&lt;br /&gt;
  const weaponInterval = maxAttackValue - minAttackValue + 1;&lt;br /&gt;
  const slashInterval = maxAttackValueSlash - minAttackValueSlash + 1;&lt;br /&gt;
&lt;br /&gt;
  const totalCardinal = weaponInterval * slashInterval * 1_000_000;&lt;br /&gt;
  const minInterval = Math.min(weaponInterval, slashInterval);&lt;br /&gt;
&lt;br /&gt;
  minAttackValue += minAttackValueSlash;&lt;br /&gt;
  maxAttackValue += maxAttackValueSlash;&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    minAttackValue: minAttackValue,&lt;br /&gt;
    maxAttackValue: maxAttackValue,&lt;br /&gt;
    attackValueOther: attackValueOther,&lt;br /&gt;
    totalCardinal: totalCardinal,&lt;br /&gt;
    weights: calcWeights(minAttackValue, maxAttackValue, minInterval),&lt;br /&gt;
    possibleDamageCount: maxAttackValue - minAttackValue + 1,&lt;br /&gt;
    criticalAttackRange: criticalAttackRange,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcMagicAttackValue(attacker, isPlayerVsPlayer) {&lt;br /&gt;
  let minMagicAttackValueSlash = 0;&lt;br /&gt;
  let maxMagicAttackValueSlash = 0;&lt;br /&gt;
&lt;br /&gt;
  let criticalAttackRange;&lt;br /&gt;
&lt;br /&gt;
  let {&lt;br /&gt;
    isSerpent,&lt;br /&gt;
    minMagicAttackValue,&lt;br /&gt;
    maxMagicAttackValue,&lt;br /&gt;
    minAttackValue,&lt;br /&gt;
    maxAttackValue,&lt;br /&gt;
    growth,&lt;br /&gt;
  } = attacker.weapon;&lt;br /&gt;
&lt;br /&gt;
  if (isSerpent) {&lt;br /&gt;
    minMagicAttackValue = Math.max(0, attacker.minMagicAttackValueRandom);&lt;br /&gt;
    maxMagicAttackValue = Math.max(&lt;br /&gt;
      minMagicAttackValue,&lt;br /&gt;
      attacker.maxMagicAttackValueRandom&lt;br /&gt;
    );&lt;br /&gt;
    minAttackValue = Math.max(0, attacker.minAttackValueRandom - growth);&lt;br /&gt;
    maxAttackValue = Math.max(&lt;br /&gt;
      minAttackValue,&lt;br /&gt;
      attacker.maxAttackValueRandom - growth&lt;br /&gt;
    );&lt;br /&gt;
  } else {&lt;br /&gt;
    minMagicAttackValue += growth;&lt;br /&gt;
    maxMagicAttackValue += growth;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (isPlayerVsPlayer) {&lt;br /&gt;
    criticalAttackRange = calcPvpCriticalAttackRange(&lt;br /&gt;
      minAttackValue,&lt;br /&gt;
      maxAttackValue,&lt;br /&gt;
      growth&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  minMagicAttackValueSlash = Math.min(&lt;br /&gt;
    attacker.minMagicAttackValueSlash,&lt;br /&gt;
    attacker.maxMagicAttackValueSlash&lt;br /&gt;
  );&lt;br /&gt;
  maxMagicAttackValueSlash = Math.max(&lt;br /&gt;
    attacker.minMagicAttackValueSlash,&lt;br /&gt;
    attacker.maxMagicAttackValueSlash&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  const weaponInterval = maxMagicAttackValue - minMagicAttackValue + 1;&lt;br /&gt;
  const slashInterval = maxMagicAttackValueSlash - minMagicAttackValueSlash + 1;&lt;br /&gt;
&lt;br /&gt;
  const totalCardinal = weaponInterval * slashInterval * 1_000_000;&lt;br /&gt;
  const minInterval = Math.min(weaponInterval, slashInterval);&lt;br /&gt;
&lt;br /&gt;
  minMagicAttackValue += minMagicAttackValueSlash;&lt;br /&gt;
  maxMagicAttackValue += maxMagicAttackValueSlash;&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    minMagicAttackValue: minMagicAttackValue,&lt;br /&gt;
    maxMagicAttackValue: maxMagicAttackValue,&lt;br /&gt;
    magicAttackValueAugmentation: getMagicAttackValueAugmentation(&lt;br /&gt;
      minMagicAttackValue,&lt;br /&gt;
      maxMagicAttackValue,&lt;br /&gt;
      attacker.magicAttackValue&lt;br /&gt;
    ),&lt;br /&gt;
    totalCardinal: totalCardinal,&lt;br /&gt;
    weights: calcWeights(minMagicAttackValue, maxMagicAttackValue, minInterval),&lt;br /&gt;
    possibleDamageCount: maxMagicAttackValue - minMagicAttackValue + 1,&lt;br /&gt;
    criticalAttackRange: criticalAttackRange,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getPolymorphPower(polymorphPoint, polymorphPowerTable) {&lt;br /&gt;
  return polymorphPowerTable[polymorphPoint];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSkillPower(skillPoint, skillPowerTable) {&lt;br /&gt;
  return skillPowerTable[skillPoint];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getMarriageBonusValue(character, marriageTable, itemName) {&lt;br /&gt;
  let index;&lt;br /&gt;
  const lovePoint = character.lovePoint;&lt;br /&gt;
&lt;br /&gt;
  if (lovePoint &amp;lt; 65) {&lt;br /&gt;
    index = 0;&lt;br /&gt;
  } else if (lovePoint &amp;lt; 80) {&lt;br /&gt;
    index = 1;&lt;br /&gt;
  } else if (lovePoint &amp;lt; 100) {&lt;br /&gt;
    index = 2;&lt;br /&gt;
  } else {&lt;br /&gt;
    index = 3;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return marriageTable[itemName][index];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcDamageWithPrimaryBonuses(damage, bonusValues) {&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.attackValueCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  damage += bonusValues.attackValueMarriage;&lt;br /&gt;
&lt;br /&gt;
  damage = Math.floor(&lt;br /&gt;
    (damage * bonusValues.monsterResistanceMarriageCoeff) / 100&lt;br /&gt;
  );&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.monsterResistanceCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  damage += Math.floor((damage * bonusValues.typeBonusCoeff) / 100);&lt;br /&gt;
  damage +=&lt;br /&gt;
    Math.floor((damage * bonusValues.raceBonusCoeff) / 100) -&lt;br /&gt;
    Math.floor((damage * bonusValues.raceResistanceCoeff) / 100);&lt;br /&gt;
  damage += Math.floor((damage * bonusValues.stoneBonusCoeff) / 100);&lt;br /&gt;
  damage += Math.floor((damage * bonusValues.monsterBonusCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  const elementBonusCoeff = bonusValues.elementBonusCoeff;&lt;br /&gt;
&lt;br /&gt;
  damage +=&lt;br /&gt;
    Math.trunc((damage * elementBonusCoeff[0]) / 10000) +&lt;br /&gt;
    Math.trunc((damage * elementBonusCoeff[1]) / 10000) +&lt;br /&gt;
    Math.trunc((damage * elementBonusCoeff[2]) / 10000) +&lt;br /&gt;
    Math.trunc((damage * elementBonusCoeff[3]) / 10000) +&lt;br /&gt;
    Math.trunc((damage * elementBonusCoeff[4]) / 10000) +&lt;br /&gt;
    Math.trunc((damage * elementBonusCoeff[5]) / 10000);&lt;br /&gt;
&lt;br /&gt;
  damage = Math.floor(damage * bonusValues.damageMultiplier);&lt;br /&gt;
&lt;br /&gt;
  return damage;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcFinalDamage(&lt;br /&gt;
  finalDamage,&lt;br /&gt;
  minPiercingDamage,&lt;br /&gt;
  tempDamage,&lt;br /&gt;
  bonusValues,&lt;br /&gt;
  criticalAttackRange,&lt;br /&gt;
  damageByType&lt;br /&gt;
) {&lt;br /&gt;
  for (let criticalIndex = 0; criticalIndex &amp;lt; 2; criticalIndex++) {&lt;br /&gt;
    if (bonusValues.skipCriticalStep[criticalIndex]) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
    let beforeCriticalDamage = finalDamage;&lt;br /&gt;
    let damageValues = criticalIndex&lt;br /&gt;
      ? criticalAttackRange || [finalDamage]&lt;br /&gt;
      : [0];&lt;br /&gt;
&lt;br /&gt;
    for (let index = 0, len = damageValues.length; index &amp;lt; len; index++) {&lt;br /&gt;
      let afterCriticalDamage = beforeCriticalDamage + damageValues[index];&lt;br /&gt;
&lt;br /&gt;
      for (let piercingIndex = 0; piercingIndex &amp;lt; 2; piercingIndex++) {&lt;br /&gt;
        if (bonusValues.skipPiercingStep[piercingIndex]) {&lt;br /&gt;
          continue;&lt;br /&gt;
        }&lt;br /&gt;
        let damage = afterCriticalDamage;&lt;br /&gt;
&lt;br /&gt;
        if (piercingIndex) {&lt;br /&gt;
          damage += bonusValues.defenseBoost + Math.min(0, minPiercingDamage);&lt;br /&gt;
          damage += Math.floor(&lt;br /&gt;
            (tempDamage * bonusValues.extraPiercingHitCoeff) / 1000&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        damage = Math.floor((damage * bonusValues.averageDamageCoeff) / 100);&lt;br /&gt;
        damage = Math.floor(&lt;br /&gt;
          (damage * bonusValues.averageDamageResistanceCoeff) / 100&lt;br /&gt;
        );&lt;br /&gt;
        damage = Math.floor((damage * bonusValues.skillDamageCoeff) / 100);&lt;br /&gt;
        damage = Math.floor(&lt;br /&gt;
          (damage * bonusValues.skillDamageResistanceCoeff) / 100&lt;br /&gt;
        );&lt;br /&gt;
        damage = Math.floor((damage * bonusValues.rankBonusCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
        if (bonusValues.useDarkProtection) {&lt;br /&gt;
          const { darkProtectionPoint, darkProtectionSp } = bonusValues;&lt;br /&gt;
&lt;br /&gt;
          const damageReduction = Math.floor(damage / 3);&lt;br /&gt;
          const spAbsorption = Math.floor(&lt;br /&gt;
            (damageReduction * darkProtectionPoint) / 100&lt;br /&gt;
          );&lt;br /&gt;
&lt;br /&gt;
          if (spAbsorption &amp;lt;= darkProtectionSp) {&lt;br /&gt;
            damage -= damageReduction;&lt;br /&gt;
          } else {&lt;br /&gt;
            damage -= Math.floor(&lt;br /&gt;
              (darkProtectionSp * 100) / darkProtectionPoint&lt;br /&gt;
            );&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        damage = Math.max(0, damage + bonusValues.defensePercent);&lt;br /&gt;
        damage += Math.min(&lt;br /&gt;
          300,&lt;br /&gt;
          Math.floor((damage * bonusValues.damageBonusCoeff) / 100)&lt;br /&gt;
        );&lt;br /&gt;
        damage = Math.floor((damage * bonusValues.empireMalusCoeff) / 10);&lt;br /&gt;
        damage = Math.floor((damage * bonusValues.sungMaStrBonusCoeff) / 10000);&lt;br /&gt;
        damage -= Math.floor(damage * bonusValues.sungmaStrMalusCoeff);&lt;br /&gt;
&lt;br /&gt;
        damage = Math.floor(&lt;br /&gt;
          (damage * bonusValues.whiteDragonElixirCoeff) / 100&lt;br /&gt;
        );&lt;br /&gt;
        damage = Math.floor(&lt;br /&gt;
          (damage * bonusValues.steelDragonElixirCoeff) / 100&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        damageByType[criticalIndex + 2 * piercingIndex].push(damage);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveFinalDamage(&lt;br /&gt;
  damage,&lt;br /&gt;
  minPiercingDamage,&lt;br /&gt;
  damageWithPrimaryBonuses,&lt;br /&gt;
  bonusValues,&lt;br /&gt;
  criticalAttackRange,&lt;br /&gt;
  damageByType&lt;br /&gt;
) {&lt;br /&gt;
  damage = Math.floor(damage * bonusValues.magicResistanceCoeff);&lt;br /&gt;
  damage = Math.trunc((damage * bonusValues.weaponDefenseCoeff) / 100);&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.tigerStrengthCoeff) / 100);&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.berserkBonusCoeff) / 100);&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.fearBonusCoeff) / 100);&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.blessingBonusCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  calcFinalDamage(&lt;br /&gt;
    damage,&lt;br /&gt;
    minPiercingDamage,&lt;br /&gt;
    damageWithPrimaryBonuses,&lt;br /&gt;
    bonusValues,&lt;br /&gt;
    criticalAttackRange,&lt;br /&gt;
    damageByType&lt;br /&gt;
  );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveFinalSkillDamage(&lt;br /&gt;
  damage,&lt;br /&gt;
  minPiercingDamage,&lt;br /&gt;
  bonusValues,&lt;br /&gt;
  criticalAttackRange,&lt;br /&gt;
  damageByType&lt;br /&gt;
) {&lt;br /&gt;
  damage = Math.floor(damage * bonusValues.magicResistanceCoeff);&lt;br /&gt;
  damage = Math.trunc((damage * bonusValues.weaponDefenseCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  damage -= bonusValues.defense;&lt;br /&gt;
&lt;br /&gt;
  damage = floorMultiplication(damage, bonusValues.skillWardCoeff);&lt;br /&gt;
  damage = floorMultiplication(damage, bonusValues.skillBonusCoeff);&lt;br /&gt;
&lt;br /&gt;
  const tempDamage = Math.floor(&lt;br /&gt;
    (damage * bonusValues.skillBonusByBonusCoeff) / 100&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  damage = Math.floor(&lt;br /&gt;
    (tempDamage * bonusValues.magicAttackValueCoeff) / 100 + 0.5&lt;br /&gt;
  );&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.tigerStrengthCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  calcFinalDamage(&lt;br /&gt;
    damage,&lt;br /&gt;
    minPiercingDamage,&lt;br /&gt;
    tempDamage,&lt;br /&gt;
    bonusValues,&lt;br /&gt;
    criticalAttackRange,&lt;br /&gt;
    damageByType&lt;br /&gt;
  );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function computePolymorphPoint(attacker, victim, polymorphPowerTable) {&lt;br /&gt;
  attacker.polymorphDex = attacker.dex;&lt;br /&gt;
  victim.polymorphDex = victim.dex;&lt;br /&gt;
&lt;br /&gt;
  attacker.minAttackValuePolymorph = 0;&lt;br /&gt;
  attacker.maxAttackValuePolymorph = 0;&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker) &amp;amp;&amp;amp; isPolymorph(attacker)) {&lt;br /&gt;
    var polymorphPowerPct =&lt;br /&gt;
      getPolymorphPower(attacker.polymorphPoint, polymorphPowerTable) / 100;&lt;br /&gt;
    var polymorphMonster = createMonster(&lt;br /&gt;
      attacker.polymorphMonster,&lt;br /&gt;
      null,&lt;br /&gt;
      null,&lt;br /&gt;
      true&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    var polymorphStr = floorMultiplication(&lt;br /&gt;
      polymorphPowerPct,&lt;br /&gt;
      polymorphMonster.str&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    attacker.polymorphDex += floorMultiplication(&lt;br /&gt;
      polymorphPowerPct,&lt;br /&gt;
      polymorphMonster.dex&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    attacker.minAttackValuePolymorph = floorMultiplication(&lt;br /&gt;
      polymorphPowerPct,&lt;br /&gt;
      polymorphMonster.minAttackValue&lt;br /&gt;
    );&lt;br /&gt;
    attacker.maxAttackValuePolymorph = floorMultiplication(&lt;br /&gt;
      polymorphPowerPct,&lt;br /&gt;
      polymorphMonster.maxAttackValue&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    if (!attacker.weapon) {&lt;br /&gt;
      attacker.maxAttackValuePolymorph += 1;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    attacker.attackValue = 0;&lt;br /&gt;
&lt;br /&gt;
    if (isMagicClass(attacker)) {&lt;br /&gt;
      attacker.statAttackValue = 2 * (polymorphStr + attacker.int);&lt;br /&gt;
    } else {&lt;br /&gt;
      attacker.statAttackValue = 2 * (polymorphStr + attacker.str);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function computeHorse(attacker) {&lt;br /&gt;
  attacker.horseAttackValue = 0;&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker) &amp;amp;&amp;amp; isRiding(attacker) &amp;amp;&amp;amp; !isPolymorph(attacker)) {&lt;br /&gt;
    var horseConstant = 30;&lt;br /&gt;
&lt;br /&gt;
    if (attacker.class === &amp;quot;weaponary&amp;quot;) {&lt;br /&gt;
      horseConstant = 60;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    attacker.horseAttackValue = floorMultiplication(&lt;br /&gt;
      2 * attacker.level + attacker.statAttackValue,&lt;br /&gt;
      attacker.horsePoint / horseConstant&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getRankBonus(attacker) {&lt;br /&gt;
  if (!isChecked(attacker.lowRank)) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  switch (attacker.rank) {&lt;br /&gt;
    case &amp;quot;aggressive&amp;quot;:&lt;br /&gt;
      return 1;&lt;br /&gt;
    case &amp;quot;fraudulent&amp;quot;:&lt;br /&gt;
      return 2;&lt;br /&gt;
    case &amp;quot;malicious&amp;quot;:&lt;br /&gt;
      return 3;&lt;br /&gt;
    case &amp;quot;cruel&amp;quot;:&lt;br /&gt;
      return 5;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcElementCoeffPvP(elementBonus, mapping, attacker, victim) {&lt;br /&gt;
  var minElementMalus = 0;&lt;br /&gt;
  var maxDifference = 0;&lt;br /&gt;
  var savedElementDifferences = [];&lt;br /&gt;
  var elementBonusIndex = 0;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; elementBonus.length; index++) {&lt;br /&gt;
    if (!attacker[mapping.elementBonus[index]]) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var elementDifference =&lt;br /&gt;
      attacker[mapping.elementBonus[index]] -&lt;br /&gt;
      victim[mapping.elementResistance[index]];&lt;br /&gt;
&lt;br /&gt;
    if (elementDifference &amp;gt;= 0) {&lt;br /&gt;
      elementBonus[elementBonusIndex] = 10 * elementDifference;&lt;br /&gt;
      minElementMalus -= elementDifference;&lt;br /&gt;
      maxDifference = Math.max(maxDifference, elementDifference);&lt;br /&gt;
      elementBonusIndex++;&lt;br /&gt;
    } else {&lt;br /&gt;
      savedElementDifferences.push(elementDifference);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (!savedElementDifferences.length) {&lt;br /&gt;
    return;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  minElementMalus += maxDifference;&lt;br /&gt;
  savedElementDifferences.sort(compareNumbers);&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; savedElementDifferences.length; index++) {&lt;br /&gt;
    var elementDifference = savedElementDifferences[index];&lt;br /&gt;
&lt;br /&gt;
    elementBonus[elementBonusIndex + index] =&lt;br /&gt;
      10 * Math.max(minElementMalus, elementDifference);&lt;br /&gt;
&lt;br /&gt;
    minElementMalus = Math.min(&lt;br /&gt;
      0,&lt;br /&gt;
      Math.max(minElementMalus, minElementMalus - elementDifference)&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcCriticalHitChance(criticalHitPercentage) {&lt;br /&gt;
  if (criticalHitPercentage &amp;lt;= 9) {&lt;br /&gt;
    return Math.floor((criticalHitPercentage + 5) / 5);&lt;br /&gt;
  }&lt;br /&gt;
  return Math.floor((criticalHitPercentage + 5) / 6);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcCriticalSkillChance(criticalHitPercentage) {&lt;br /&gt;
  if (criticalHitPercentage === 0) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  } else if (criticalHitPercentage &amp;lt;= 9) {&lt;br /&gt;
    return Math.floor((criticalHitPercentage + 7) / 3);&lt;br /&gt;
  }&lt;br /&gt;
  return Math.floor((criticalHitPercentage + 5) / 3);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcPiercingSkillChance(piercingHitPercentage) {&lt;br /&gt;
  if (piercingHitPercentage &amp;lt;= 9) {&lt;br /&gt;
    return Math.floor(piercingHitPercentage / 2);&lt;br /&gt;
  }&lt;br /&gt;
  return 5 + Math.floor((piercingHitPercentage - 10) / 4);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function magicResistanceToCoeff(magicResistance) {&lt;br /&gt;
  if (magicResistance) {&lt;br /&gt;
    return 2000 / (6 * magicResistance + 1000) - 1;&lt;br /&gt;
  }&lt;br /&gt;
  return 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createBattleValues(attacker, victim, battle, skillType) {&lt;br /&gt;
  var {&lt;br /&gt;
    mapping,&lt;br /&gt;
    constants: { polymorphPowerTable, skillPowerTable, marriageTable },&lt;br /&gt;
  } = battle;&lt;br /&gt;
  var calcAttackValues;&lt;br /&gt;
&lt;br /&gt;
  var missPercentage = 0;&lt;br /&gt;
  var attackValueMeleeMagic = 0;&lt;br /&gt;
  var attackValueMarriage = 0;&lt;br /&gt;
  var monsterResistanceMarriage = 0;&lt;br /&gt;
  var monsterResistance = 0;&lt;br /&gt;
  var typeBonus = 0;&lt;br /&gt;
  var raceBonus = 0;&lt;br /&gt;
  var raceResistance = 0;&lt;br /&gt;
  var stoneBonus = 0;&lt;br /&gt;
  var monsterBonus = 0;&lt;br /&gt;
  var elementBonus = [0, 0, 0, 0, 0, 0]; // fire, ice, lightning, earth, darkness, wind, order doesn't matter&lt;br /&gt;
  var defenseMarriage = 0;&lt;br /&gt;
  var damageMultiplier = 1;&lt;br /&gt;
  var useDamage = 1;&lt;br /&gt;
  var defense = victim.defense;&lt;br /&gt;
  var defenseBoost = defense;&lt;br /&gt;
  var magicResistance = 0;&lt;br /&gt;
  var weaponDefense = 0;&lt;br /&gt;
  var tigerStrength = 0;&lt;br /&gt;
  var berserkBonus = 0;&lt;br /&gt;
  var blessingBonus = 0;&lt;br /&gt;
  var fearBonus = 0;&lt;br /&gt;
  var magicAttackValueMeleeMagic = 0;&lt;br /&gt;
  var criticalHitPercentage = attacker.criticalHit;&lt;br /&gt;
  var isPlayerVsPlayer = false;&lt;br /&gt;
  var piercingHitPercentage = attacker.piercingHit;&lt;br /&gt;
  var extraPiercingHitPercentage = Math.max(0, piercingHitPercentage - 100);&lt;br /&gt;
  var averageDamage = 0;&lt;br /&gt;
  var averageDamageResistance = 0;&lt;br /&gt;
  var skillDamage = 0;&lt;br /&gt;
  var skillDamageResistance = 0;&lt;br /&gt;
  var rankBonus = 0;&lt;br /&gt;
  var useDarkProtection = false;&lt;br /&gt;
  var darkProtectionPoint = 0;&lt;br /&gt;
  var defensePercent = 0;&lt;br /&gt;
  var damageBonus = 0;&lt;br /&gt;
  var empireMalus = 0;&lt;br /&gt;
  var sungMaStrBonus = 0;&lt;br /&gt;
  var sungmaStrMalus = 0;&lt;br /&gt;
  var whiteDragonElixir = 0;&lt;br /&gt;
  var steelDragonElixir = 0;&lt;br /&gt;
&lt;br /&gt;
  attacker.statAttackValue = calcStatAttackValue(attacker);&lt;br /&gt;
&lt;br /&gt;
  computePolymorphPoint(attacker, victim, polymorphPowerTable);&lt;br /&gt;
  computeHorse(attacker);&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker)) {&lt;br /&gt;
    if (weaponData.hasOwnProperty(attacker.weapon)) {&lt;br /&gt;
      attacker.weapon = createWeapon(attacker.weapon);&lt;br /&gt;
    } else {&lt;br /&gt;
      attacker.weapon = createWeapon(0);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    attacker.weapon.getValues(attacker.weaponUpgrade);&lt;br /&gt;
&lt;br /&gt;
    attackValueMeleeMagic =&lt;br /&gt;
      attacker.attackValuePercent + Math.min(100, attacker.attackMeleeMagic);&lt;br /&gt;
&lt;br /&gt;
    var weaponType = attacker.weapon.type;&lt;br /&gt;
&lt;br /&gt;
    if (skillType &amp;amp;&amp;amp; attacker.class === &amp;quot;archery&amp;quot;) {&lt;br /&gt;
      if (weaponType !== 2) {&lt;br /&gt;
        useDamage = 0;&lt;br /&gt;
        weaponType = 2;&lt;br /&gt;
      }&lt;br /&gt;
      defense = 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var weaponDefenseName = mapping.defenseWeapon[weaponType];&lt;br /&gt;
    var weaponDefenseBreakName = mapping.breakWeapon[weaponType];&lt;br /&gt;
&lt;br /&gt;
    if (victim.hasOwnProperty(weaponDefenseName)) {&lt;br /&gt;
      weaponDefense = victim[weaponDefenseName];&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isChecked(attacker.whiteDragonElixir)) {&lt;br /&gt;
      whiteDragonElixir = 10;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isPC(victim)) {&lt;br /&gt;
      isPlayerVsPlayer = true;&lt;br /&gt;
&lt;br /&gt;
      if (!skillType) {&lt;br /&gt;
        if (weaponType === 2 &amp;amp;&amp;amp; !isPolymorph(attacker)) {&lt;br /&gt;
          missPercentage = victim.arrowBlock;&lt;br /&gt;
        } else {&lt;br /&gt;
          missPercentage = victim.meleeBlock;&lt;br /&gt;
        }&lt;br /&gt;
        missPercentage +=&lt;br /&gt;
          victim.meleeArrowBlock -&lt;br /&gt;
          (missPercentage * victim.meleeArrowBlock) / 100;&lt;br /&gt;
&lt;br /&gt;
        criticalHitPercentage = calcCriticalHitChance(criticalHitPercentage);&lt;br /&gt;
        berserkBonus = calcBerserkBonus(skillPowerTable, victim);&lt;br /&gt;
        blessingBonus = calcBlessingBonus(skillPowerTable, victim);&lt;br /&gt;
        fearBonus = calcFearBonus(skillPowerTable, victim);&lt;br /&gt;
        averageDamageResistance = victim.averageDamageResistance;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      typeBonus = Math.max(1, attacker.humanBonus - victim.humanResistance);&lt;br /&gt;
      raceBonus = attacker[mapping.raceBonus[victim.race]];&lt;br /&gt;
      raceResistance = victim[mapping.raceResistance[attacker.race]];&lt;br /&gt;
&lt;br /&gt;
      calcElementCoeffPvP(elementBonus, mapping, attacker, victim);&lt;br /&gt;
&lt;br /&gt;
      if (weaponType !== 2 &amp;amp;&amp;amp; attacker.hasOwnProperty(weaponDefenseBreakName)) {&lt;br /&gt;
        weaponDefense -= attacker[weaponDefenseBreakName];&lt;br /&gt;
      }&lt;br /&gt;
    } else {&lt;br /&gt;
      if (isChecked(attacker.isMarried)) {&lt;br /&gt;
        if (isChecked(attacker.loveNecklace)) {&lt;br /&gt;
          attackValueMarriage = getMarriageBonusValue(&lt;br /&gt;
            attacker,&lt;br /&gt;
            marriageTable,&lt;br /&gt;
            &amp;quot;loveNecklace&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isChecked(attacker.loveEarrings)) {&lt;br /&gt;
          criticalHitPercentage += getMarriageBonusValue(&lt;br /&gt;
            attacker,&lt;br /&gt;
            marriageTable,&lt;br /&gt;
            &amp;quot;loveEarrings&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isChecked(attacker.harmonyEarrings)) {&lt;br /&gt;
          piercingHitPercentage += getMarriageBonusValue(&lt;br /&gt;
            attacker,&lt;br /&gt;
            marriageTable,&lt;br /&gt;
            &amp;quot;harmonyEarrings&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (isChecked(attacker.tigerStrength)) {&lt;br /&gt;
        tigerStrength = 40;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      for (var index = 0; index &amp;lt; elementBonus.length; index++) {&lt;br /&gt;
        var elementBonusName = mapping.elementBonus[index];&lt;br /&gt;
        var elementResistanceName = mapping.elementResistance[index];&lt;br /&gt;
&lt;br /&gt;
        if (attacker[elementBonusName] &amp;amp;&amp;amp; victim[elementBonusName]) {&lt;br /&gt;
          elementBonus[index] =&lt;br /&gt;
            50 * (attacker[elementBonusName] - victim[elementResistanceName]);&lt;br /&gt;
        } else {&lt;br /&gt;
          elementBonus[index] = 5 * attacker[elementBonusName];&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      var victimType = victim.type;&lt;br /&gt;
&lt;br /&gt;
      if (victimType !== -1) {&lt;br /&gt;
        typeBonus = attacker[mapping.typeFlag[victimType]];&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      monsterBonus = attacker.monsterBonus;&lt;br /&gt;
&lt;br /&gt;
      if (isStone(victim)) {&lt;br /&gt;
        stoneBonus = attacker.stoneBonus;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (isBoss(victim)) {&lt;br /&gt;
        if (skillType) {&lt;br /&gt;
          skillDamage += attacker.skillBossDamage;&lt;br /&gt;
        } else {&lt;br /&gt;
          averageDamage += attacker.bossDamage;&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (isChecked(attacker.onYohara)) {&lt;br /&gt;
        var sungmaStrDifference = attacker.sungmaStr - attacker.sungmaStrMalus;&lt;br /&gt;
&lt;br /&gt;
        if (sungmaStrDifference &amp;gt;= 0) {&lt;br /&gt;
          sungMaStrBonus = sungmaStrDifference;&lt;br /&gt;
        } else {&lt;br /&gt;
          sungmaStrMalus = 0.5;&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (skillType) {&lt;br /&gt;
      skillDamage += attacker.skillDamage;&lt;br /&gt;
    } else {&lt;br /&gt;
      averageDamage += attacker.averageDamage;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    rankBonus = getRankBonus(attacker);&lt;br /&gt;
    damageBonus = attacker.damageBonus;&lt;br /&gt;
&lt;br /&gt;
    if (isChecked(attacker.empireMalus)) {&lt;br /&gt;
      empireMalus = 1;&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    if (isPC(victim)) {&lt;br /&gt;
      if (isChecked(victim.isMarried)) {&lt;br /&gt;
        if (isChecked(victim.harmonyBracelet)) {&lt;br /&gt;
          monsterResistanceMarriage = getMarriageBonusValue(&lt;br /&gt;
            victim,&lt;br /&gt;
            marriageTable,&lt;br /&gt;
            &amp;quot;harmonyBracelet&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isChecked(victim.harmonyNecklace) &amp;amp;&amp;amp; !skillType) {&lt;br /&gt;
          defenseMarriage = getMarriageBonusValue(&lt;br /&gt;
            victim,&lt;br /&gt;
            marriageTable,&lt;br /&gt;
            &amp;quot;harmonyNecklace&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      monsterResistance = victim.monsterResistance;&lt;br /&gt;
&lt;br /&gt;
      for (var index = 0; index &amp;lt; elementBonus.length; index++) {&lt;br /&gt;
        var elementBonusName = mapping.elementBonus[index];&lt;br /&gt;
        var elementResistanceName = mapping.elementResistance[index];&lt;br /&gt;
&lt;br /&gt;
        if (attacker[elementBonusName]) {&lt;br /&gt;
          elementBonus[index] =&lt;br /&gt;
            80 * (attacker[elementBonusName] - victim[elementResistanceName]);&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (!skillType) {&lt;br /&gt;
        if (isMeleeAttacker(attacker)) {&lt;br /&gt;
          missPercentage = victim.meleeBlock;&lt;br /&gt;
          averageDamageResistance = victim.averageDamageResistance;&lt;br /&gt;
          berserkBonus = calcBerserkBonus(skillPowerTable, victim);&lt;br /&gt;
          blessingBonus = calcBlessingBonus(skillPowerTable, victim);&lt;br /&gt;
          fearBonus = calcFearBonus(skillPowerTable, victim);&lt;br /&gt;
        } else if (isRangeAttacker(attacker)) {&lt;br /&gt;
          missPercentage = victim.arrowBlock;&lt;br /&gt;
          weaponDefense = victim.arrowDefense;&lt;br /&gt;
          averageDamageResistance = victim.averageDamageResistance;&lt;br /&gt;
          berserkBonus = calcBerserkBonus(skillPowerTable, victim);&lt;br /&gt;
          blessingBonus = calcBlessingBonus(skillPowerTable, victim);&lt;br /&gt;
          fearBonus = calcFearBonus(skillPowerTable, victim);&lt;br /&gt;
        } else if (isMagicAttacker(attacker)) {&lt;br /&gt;
          missPercentage = victim.arrowBlock;&lt;br /&gt;
          skillDamageResistance = victim.skillDamageResistance;&lt;br /&gt;
          magicResistance = victim.magicResistance;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        missPercentage +=&lt;br /&gt;
          victim.meleeArrowBlock -&lt;br /&gt;
          (missPercentage * victim.meleeArrowBlock) / 100;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    typeBonus = 1;&lt;br /&gt;
    damageMultiplier = attacker.damageMultiplier;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillType) {&lt;br /&gt;
    criticalHitPercentage = calcCriticalSkillChance(criticalHitPercentage);&lt;br /&gt;
    piercingHitPercentage = calcPiercingSkillChance(piercingHitPercentage);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (isPC(victim)) {&lt;br /&gt;
    if (!skillType &amp;amp;&amp;amp; isChecked(victim.biologist70)) {&lt;br /&gt;
      defenseBoost = Math.floor((defenseBoost * 110) / 100);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    criticalHitPercentage = Math.max(&lt;br /&gt;
      0,&lt;br /&gt;
      criticalHitPercentage - victim.criticalHitResistance&lt;br /&gt;
    );&lt;br /&gt;
    piercingHitPercentage = Math.max(&lt;br /&gt;
      0,&lt;br /&gt;
      piercingHitPercentage - victim.piercingHitResistance&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    if (skillType) {&lt;br /&gt;
      skillDamageResistance = victim.skillDamageResistance;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      victim.useDarkProtection &amp;amp;&amp;amp;&lt;br /&gt;
      victim.class === &amp;quot;black_magic&amp;quot; &amp;amp;&amp;amp;&lt;br /&gt;
      victim.skillDarkProtection&lt;br /&gt;
    ) {&lt;br /&gt;
      useDarkProtection = true;&lt;br /&gt;
      darkProtectionPoint = calcDarkProtectionPoint(skillPowerTable, victim);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isMagicClass(victim)) {&lt;br /&gt;
      defensePercent = (-2 * victim.magicDefense * victim.defensePercent) / 100;&lt;br /&gt;
    } else {&lt;br /&gt;
      defensePercent = (-2 * defenseBoost * victim.defensePercent) / 100;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isChecked(victim.steelDragonElixir)) {&lt;br /&gt;
      steelDragonElixir = 10;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillType === &amp;quot;magic&amp;quot;) {&lt;br /&gt;
    attackValueMeleeMagic = 0;&lt;br /&gt;
    magicAttackValueMeleeMagic =&lt;br /&gt;
      attacker.attackMagic + Math.min(100, attacker.attackMeleeMagic);&lt;br /&gt;
    attackValueMarriage = 0;&lt;br /&gt;
    defense = 0;&lt;br /&gt;
    if (isDispell(attacker, 6)) {&lt;br /&gt;
      typeBonus = 0;&lt;br /&gt;
      raceBonus = 0;&lt;br /&gt;
      raceResistance = 0;&lt;br /&gt;
      stoneBonus = 0;&lt;br /&gt;
      monsterBonus = 0;&lt;br /&gt;
      for (var index = 0; index &amp;lt; elementBonus.length; index++) {&lt;br /&gt;
        elementBonus[index] = 0;&lt;br /&gt;
      }&lt;br /&gt;
    } else {&lt;br /&gt;
      magicResistance = victim.magicResistance;&lt;br /&gt;
    }&lt;br /&gt;
    weaponDefense = 0;&lt;br /&gt;
    calcAttackValues = calcMagicAttackValue;&lt;br /&gt;
  } else {&lt;br /&gt;
    calcAttackValues = calcSecondaryAttackValue;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  missPercentage = Math.min(100, missPercentage);&lt;br /&gt;
  criticalHitPercentage = Math.min(criticalHitPercentage, 100);&lt;br /&gt;
  piercingHitPercentage = Math.min(piercingHitPercentage, 100);&lt;br /&gt;
&lt;br /&gt;
  const bonusValues = {&lt;br /&gt;
    missPercentage: missPercentage,&lt;br /&gt;
    skipCriticalStep: [&lt;br /&gt;
      !Boolean(100 - criticalHitPercentage),&lt;br /&gt;
      !Boolean(criticalHitPercentage),&lt;br /&gt;
    ],&lt;br /&gt;
    skipPiercingStep: [&lt;br /&gt;
      !Boolean(100 - piercingHitPercentage),&lt;br /&gt;
      !Boolean(piercingHitPercentage),&lt;br /&gt;
    ],&lt;br /&gt;
    weaponBonusCoeff: 1,&lt;br /&gt;
    attackValueCoeff: 100 + attackValueMeleeMagic,&lt;br /&gt;
    attackValueMarriage: attackValueMarriage,&lt;br /&gt;
    monsterResistanceMarriageCoeff: 100 - monsterResistanceMarriage,&lt;br /&gt;
    monsterResistanceCoeff: 100 - monsterResistance,&lt;br /&gt;
    typeBonusCoeff: typeBonus,&lt;br /&gt;
    raceBonusCoeff: raceBonus,&lt;br /&gt;
    raceResistanceCoeff: raceResistance,&lt;br /&gt;
    stoneBonusCoeff: stoneBonus,&lt;br /&gt;
    monsterBonusCoeff: monsterBonus,&lt;br /&gt;
    elementBonusCoeff: elementBonus,&lt;br /&gt;
    damageMultiplier: damageMultiplier,&lt;br /&gt;
    useDamage: useDamage,&lt;br /&gt;
    defense: defense,&lt;br /&gt;
    defenseBoost: defenseBoost,&lt;br /&gt;
    defenseMarriage: defenseMarriage,&lt;br /&gt;
    tigerStrengthCoeff: 100 + tigerStrength,&lt;br /&gt;
    magicResistanceCoeff: magicResistanceToCoeff(magicResistance),&lt;br /&gt;
    weaponDefenseCoeff: 100 - weaponDefense,&lt;br /&gt;
    berserkBonusCoeff: 100 + berserkBonus,&lt;br /&gt;
    blessingBonusCoeff: 100 - blessingBonus,&lt;br /&gt;
    fearBonusCoeff: 100 - fearBonus,&lt;br /&gt;
    magicAttackValueCoeff: 100 + magicAttackValueMeleeMagic,&lt;br /&gt;
    extraPiercingHitCoeff: 5 * extraPiercingHitPercentage,&lt;br /&gt;
    averageDamageCoeff: 100 + averageDamage,&lt;br /&gt;
    averageDamageResistanceCoeff: 100 - Math.min(99, averageDamageResistance),&lt;br /&gt;
    skillDamageCoeff: 100 + skillDamage,&lt;br /&gt;
    skillDamageResistanceCoeff: 100 - Math.min(99, skillDamageResistance),&lt;br /&gt;
    useDarkProtection: useDarkProtection,&lt;br /&gt;
    darkProtectionPoint: darkProtectionPoint,&lt;br /&gt;
    darkProtectionSp: victim.darkProtectionSp,&lt;br /&gt;
    rankBonusCoeff: 100 + rankBonus,&lt;br /&gt;
    defensePercent: Math.floor(defensePercent),&lt;br /&gt;
    damageBonusCoeff: Math.min(20, damageBonus),&lt;br /&gt;
    empireMalusCoeff: 10 - empireMalus,&lt;br /&gt;
    sungMaStrBonusCoeff: 10000 + sungMaStrBonus,&lt;br /&gt;
    sungmaStrMalusCoeff: sungmaStrMalus,&lt;br /&gt;
    whiteDragonElixirCoeff: 100 + whiteDragonElixir,&lt;br /&gt;
    steelDragonElixirCoeff: 100 - steelDragonElixir,&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  const damageTypeWeights = [&lt;br /&gt;
    (100 - criticalHitPercentage) *&lt;br /&gt;
      (100 - piercingHitPercentage) *&lt;br /&gt;
      (100 - missPercentage),&lt;br /&gt;
    criticalHitPercentage *&lt;br /&gt;
      (100 - piercingHitPercentage) *&lt;br /&gt;
      (100 - missPercentage),&lt;br /&gt;
    (100 - criticalHitPercentage) *&lt;br /&gt;
      piercingHitPercentage *&lt;br /&gt;
      (100 - missPercentage),&lt;br /&gt;
    criticalHitPercentage * piercingHitPercentage * (100 - missPercentage),&lt;br /&gt;
  ];&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    attacker: attacker,&lt;br /&gt;
    victim: victim,&lt;br /&gt;
    attackFactor: calcAttackFactor(attacker, victim),&lt;br /&gt;
    mainAttackValue: calcMainAttackValue(attacker),&lt;br /&gt;
    attackValues: calcAttackValues(attacker, isPlayerVsPlayer),&lt;br /&gt;
    bonusValues: bonusValues,&lt;br /&gt;
    damageTypeWeights: damageTypeWeights,&lt;br /&gt;
    attackTypeMapping: mapping.attackType,&lt;br /&gt;
    damageWeightedByType: {&lt;br /&gt;
      normalHit: {},&lt;br /&gt;
      criticalHit: {},&lt;br /&gt;
      piercingHit: {},&lt;br /&gt;
      criticalPiercingHit: {},&lt;br /&gt;
    },&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateBattleValues(battleValues, skillFormula, skillInfo) {&lt;br /&gt;
  var weaponBonus = 0;&lt;br /&gt;
  var skillWard = 0;&lt;br /&gt;
  var skillBonus = 0;&lt;br /&gt;
  var skillBonusByBonus = 0;&lt;br /&gt;
  var { attacker: attacker, bonusValues: bonusValues } = battleValues;&lt;br /&gt;
  var {&lt;br /&gt;
    range: [minVariation, maxVariation],&lt;br /&gt;
  } = skillInfo;&lt;br /&gt;
  var variationLength = maxVariation - minVariation + 1;&lt;br /&gt;
&lt;br /&gt;
  if (skillInfo.hasOwnProperty(&amp;quot;weaponBonus&amp;quot;)) {&lt;br /&gt;
    var [weaponType, weaponBonusValue] = skillInfo.weaponBonus;&lt;br /&gt;
&lt;br /&gt;
    if (weaponType === attacker.weapon.type) {&lt;br /&gt;
      weaponBonus = weaponBonusValue;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillInfo.skillBonus) {&lt;br /&gt;
    skillBonus = skillInfo.skillBonus;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillInfo.skillWard) {&lt;br /&gt;
    skillWard = skillInfo.skillWard;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillInfo.skillBonusByBonus) {&lt;br /&gt;
    skillBonusByBonus = skillInfo.skillBonusByBonus;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillInfo.removeWeaponReduction) {&lt;br /&gt;
    bonusValues.weaponDefenseCoeff = 100;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  bonusValues.weaponBonusCoeff = 100 + weaponBonus;&lt;br /&gt;
  bonusValues.skillWardCoeff = 1 - skillWard / 100;&lt;br /&gt;
  bonusValues.skillBonusCoeff = 1 + skillBonus / 100;&lt;br /&gt;
  bonusValues.skillBonusByBonusCoeff = 100 + skillBonusByBonus;&lt;br /&gt;
&lt;br /&gt;
  battleValues.skillFormula = skillFormula;&lt;br /&gt;
  battleValues.skillRange = skillInfo.range;&lt;br /&gt;
  battleValues.attackValues.totalCardinal *= variationLength;&lt;br /&gt;
  battleValues.attackValues.possibleDamageCount *= variationLength;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcWeights(minValue, maxValue, minInterval) {&lt;br /&gt;
  var firstWeightLimit = minValue + minInterval - 1;&lt;br /&gt;
  var lastWeightsLimit = maxValue - minInterval + 1;&lt;br /&gt;
  var weights = [];&lt;br /&gt;
&lt;br /&gt;
  for (var value = minValue; value &amp;lt; firstWeightLimit; value++) {&lt;br /&gt;
    weights.push(value - minValue + 1);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (var value = firstWeightLimit; value &amp;lt;= lastWeightsLimit; value++) {&lt;br /&gt;
    weights.push(minInterval);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (var value = lastWeightsLimit + 1; value &amp;lt;= maxValue; value++) {&lt;br /&gt;
    weights.push(maxValue - value + 1);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return weights;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcBerserkBonus(skillPowerTable, victim) {&lt;br /&gt;
  if (!isChecked(victim.useBerserk) || victim.class !== &amp;quot;body&amp;quot;) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var skillPower = getSkillPower(victim.skillBerserk, skillPowerTable);&lt;br /&gt;
&lt;br /&gt;
  if (!skillPower) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var berserkBonus = Math.floor(skillPower * 25);&lt;br /&gt;
&lt;br /&gt;
  return berserkBonus;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcBlessingBonus(skillPowerTable, victim) {&lt;br /&gt;
  if (!isChecked(victim.isBlessed)) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var int = victim.intBlessing;&lt;br /&gt;
  var dex = victim.dexBlessing;&lt;br /&gt;
  var skillPower = getSkillPower(victim.skillBlessing, skillPowerTable);&lt;br /&gt;
&lt;br /&gt;
  if (!skillPower) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var blessingBonus = floorMultiplication(&lt;br /&gt;
    ((int * 0.3 + 5) * (2 * skillPower + 0.5) + 0.3 * dex) / (skillPower + 2.3),&lt;br /&gt;
    1&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  if (victim.class === &amp;quot;dragon&amp;quot; &amp;amp;&amp;amp; isChecked(victim.blessingOnself)) {&lt;br /&gt;
    blessingBonus = floorMultiplication(blessingBonus, 1.1);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return blessingBonus;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcFearBonus(skillPowerTable, victim) {&lt;br /&gt;
  if (!isChecked(victim.useFear) || victim.class !== &amp;quot;weaponary&amp;quot;) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var skillPower = getSkillPower(victim.skillFear, skillPowerTable);&lt;br /&gt;
&lt;br /&gt;
  if (!skillPower) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var fearBonus = 5 + Math.floor(skillPower * 20);&lt;br /&gt;
&lt;br /&gt;
  return fearBonus;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcDarkProtectionPoint(skillPowerTable, victim) {&lt;br /&gt;
  var skillPower = getSkillPower(victim.skillDarkProtection, skillPowerTable);&lt;br /&gt;
&lt;br /&gt;
  return floorMultiplication(100 - victim.int * 0.84 * skillPower, 1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSkillFormula(battle, skillId, battleValues, removeSkillVariation) {&lt;br /&gt;
  var { attacker, victim, attackFactor } = battleValues;&lt;br /&gt;
  var skillPowerTable = battle.constants.skillPowerTable;&lt;br /&gt;
&lt;br /&gt;
  var skillFormula;&lt;br /&gt;
  var skillInfo = { range: [0, 0] };&lt;br /&gt;
&lt;br /&gt;
  var { class: attackerClass, level: lv, vit, str, int, dex } = attacker;&lt;br /&gt;
&lt;br /&gt;
  if (skillId &amp;lt;= 9) {&lt;br /&gt;
    var skillPower = getSkillPower(&lt;br /&gt;
      attacker[&amp;quot;attackSkill&amp;quot; + skillId],&lt;br /&gt;
      skillPowerTable&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    var improvedBySkillBonus = false;&lt;br /&gt;
    var improvedByBonus = false;&lt;br /&gt;
&lt;br /&gt;
    if (attackerClass === &amp;quot;body&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Triple lacération&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.1 * atk + (0.5 * atk + 1.5 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Moulinet à l'épée&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              3 * atk + (0.8 * atk + 5 * str + 3 * dex + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Accélération&lt;br /&gt;
        case 5:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * atk + (atk + dex * 3 + str * 7 + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Volonté de vivre&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              (3 * atk + (atk + 1.5 * str) * skillPower) * 1.07,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          break;&lt;br /&gt;
        // Tremblement de terre&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              3 * atk +&lt;br /&gt;
                (0.9 * atk + variation + 5 * str + 3 * dex + lv) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;mental&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Attaque de l'esprit&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2.3 * atk + (4 * atk + 4 * str + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Attaque de la paume&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2.3 * atk + (3 * atk + 4 * str + 3 * vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Charge&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * atk + (2 * atk + 2 * dex + 2 * vit + 4 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          break;&lt;br /&gt;
        // Coup d'épée&lt;br /&gt;
        case 5:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * atk + (atk + 3 * dex + 5 * str + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Orbe de l'épée&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              (2 * atk + (2 * atk + 2 * dex + 2 * vit + 4 * str) * skillPower) *&lt;br /&gt;
                1.1,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          break;&lt;br /&gt;
        // Tremblement de terre&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              3 * atk +&lt;br /&gt;
                (0.9 * atk + variation + 5 * str + 3 * dex + lv) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;blade_fight&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Embuscade&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk + (1.2 * atk + variation + 4 * dex + 4 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [1, 50];&lt;br /&gt;
          skillInfo.range = [500, 700];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Attaque rapide&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk + (1.6 * atk + variation + 7 * dex + 7 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [1, 35];&lt;br /&gt;
          skillInfo.range = [200, 300];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Dague filante&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * atk + (0.5 * atk + 9 * dex + 7 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Brume empoisonnée&lt;br /&gt;
        case 5:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * lv + (atk + 3 * str + 18 * dex) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Poison insidieux&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              (2 * lv + (atk + 3 * str + 18 * dex) * skillPower) * 1.1,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          break;&lt;br /&gt;
        // Étoiles brillantes&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk + (1.7 * atk + variation + 6 * dex + 5 * lv) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;archery&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Tir à répétition&lt;br /&gt;
        // case 1:&lt;br /&gt;
        //   skillFormula = function (atk) {&lt;br /&gt;
        //     return floorMultiplication(&lt;br /&gt;
        //       atk + 0.2 * atk * Math.floor(2 + 6 * skillPower) + (0.8 * atk + 8 * dex * attackFactor + 2 * int) * skillPower,&lt;br /&gt;
        //       1&lt;br /&gt;
        //     );&lt;br /&gt;
        //   };&lt;br /&gt;
        //   improvedByBonus = true;&lt;br /&gt;
        //   break;&lt;br /&gt;
        // Pluie de flèches&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk + (1.7 * atk + 5 * dex + str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Flèche de feu&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.5 * atk + (2.6 * atk + 0.9 * int + variation) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [100, 300];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Foulée de plume&lt;br /&gt;
        case 4:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              (3 * dex + 200 + 2 * str + 2 * int) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.removeWeaponReduction = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Flèche empoisonnée&lt;br /&gt;
        case 5:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk +&lt;br /&gt;
                (1.4 * atk + variation + 7 * dex + 4 * str + 4 * int) *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [100, 200];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Coup étincelant&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              (atk +&lt;br /&gt;
                (1.2 * atk + variation + 6 * dex + 3 * str + 3 * int) *&lt;br /&gt;
                  skillPower) *&lt;br /&gt;
                1.2,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [100, 200];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Tir tempête&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.9 * atk + (2.6 * atk + variation) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;weaponary&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Toucher brûlant&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk +&lt;br /&gt;
                2 * lv +&lt;br /&gt;
                2 * int +&lt;br /&gt;
                (2 * atk + 4 * str + 14 * int) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Tourbillon du dragon&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.1 * atk +&lt;br /&gt;
                2 * lv +&lt;br /&gt;
                2 * int +&lt;br /&gt;
                (1.5 * atk + str + 12 * int) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Contre-sort&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              40 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                2 * int +&lt;br /&gt;
                (10 * int + 7 * mav + variation) * attackFactor * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [50, 100];&lt;br /&gt;
          break;&lt;br /&gt;
        // Coup démoniaque&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.9 * atk + (2.6 * atk + variation) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;black_magic&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Attaque des ténèbres&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              40 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                2 * int +&lt;br /&gt;
                (13 * int + 6 * mav + variation) * attackFactor * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [50, 100];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Attaque de flammes&lt;br /&gt;
        // case 2:&lt;br /&gt;
        //   skillFormula = function (mav, variation) {&lt;br /&gt;
        //     return floorMultiplication(&lt;br /&gt;
        //       5 * lv + 2 * int + (7 * int + 8 * mav + 4 * str + 2 * vit + variation) * skillPower,&lt;br /&gt;
        //       1&lt;br /&gt;
        //     );&lt;br /&gt;
        //   };&lt;br /&gt;
        //   skillInfo.range = [180, 100];&lt;br /&gt;
        //   improvedByBonus = true;&lt;br /&gt;
        //   break;&lt;br /&gt;
        // Esprit de flammes&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              30 +&lt;br /&gt;
                2 * lv +&lt;br /&gt;
                2 * int +&lt;br /&gt;
                (7 * int + 6 * mav + variation) * attackFactor * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [200, 500];&lt;br /&gt;
          break;&lt;br /&gt;
        // Frappe de l'esprit&lt;br /&gt;
        // case 5:&lt;br /&gt;
        //   skillFormula = function (mav, variation) {&lt;br /&gt;
        //     return floorMultiplication(&lt;br /&gt;
        //       40 + 2 * lv + 2 * int + (2 * vit + 2 * dex + 13 * int + 6 * mav + variation) * attackFactor * skillPower,&lt;br /&gt;
        //       1&lt;br /&gt;
        //     );&lt;br /&gt;
        //   };&lt;br /&gt;
        //   skillInfo.range = [180, 200];&lt;br /&gt;
        //   break;&lt;br /&gt;
        // Orbe des ténèbres&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (mav) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              120 +&lt;br /&gt;
                6 * lv +&lt;br /&gt;
                (5 * vit + 5 * dex + 29 * int + 9 * mav) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Vague mortelle&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              120 +&lt;br /&gt;
                6 * lv +&lt;br /&gt;
                (5 * vit + 5 * dex + 30 * int + variation + 9 * mav) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;dragon&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Talisman volant&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (mav) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              70 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                (18 * int + 7 * str + 5 * mav + 50) * attackFactor * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [4, 10];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Dragon chassant&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (mav) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              60 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                (16 * int + 6 * dex + 6 * mav + 120) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [4, 10];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Rugissement du dragon&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (mav) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              70 +&lt;br /&gt;
                3 * lv +&lt;br /&gt;
                (20 * int + 3 * str + 10 * mav + 100) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [4, 10];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Météore&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              120 +&lt;br /&gt;
                6 * lv +&lt;br /&gt;
                (5 * vit + 5 * dex + 30 * int + variation + 9 * mav) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;heal&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Jet de foudre&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              60 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                (8 * int + 2 * dex + 8 * mav + variation) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [6, 10];&lt;br /&gt;
          skillInfo.range = [5 * int, 15 * int];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Invocation de foudre&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              40 +&lt;br /&gt;
                4 * lv +&lt;br /&gt;
                (13 * int + 2 * str + 10 * mav + variation) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [6, 10];&lt;br /&gt;
          skillInfo.range = [5 * int, 16 * int];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Griffe de foudre&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              50 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                (8 * int + 2 * str + 8 * mav + variation) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 800];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;lycan&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Déchiqueter&lt;br /&gt;
        // case 1:&lt;br /&gt;
        //   skillFormula = function (atk) {&lt;br /&gt;
        //     return floorMultiplication(&lt;br /&gt;
        //       1.1 * atk + (0.3 * atk + 1.5 * str) * skillPower,&lt;br /&gt;
        //       1&lt;br /&gt;
        //     );&lt;br /&gt;
        //   };&lt;br /&gt;
        //   skillInfo.weaponBonus = [5, 54];&lt;br /&gt;
        //   improvedByBonus = true;&lt;br /&gt;
        //   break;&lt;br /&gt;
        // Souffle de loup&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * atk + (atk + 3 * dex + 5 * str + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [5, 35];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Bond de loup&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk + (1.6 * atk + 200 + 7 * dex + 7 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [5, 35];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Griffe de loup&lt;br /&gt;
        case 4:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              3 * atk + (0.8 * atk + 6 * str + 2 * dex + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Tempête cinglante&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.8 * atk +&lt;br /&gt;
                (atk + 6 * dex + variation + 3 * str + lv) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
    if (improvedBySkillBonus) {&lt;br /&gt;
      skillInfo.skillBonus =&lt;br /&gt;
        16 * getSkillPower(attacker.skillBonus, skillPowerTable);&lt;br /&gt;
&lt;br /&gt;
      var skillWardChoice = victim.skillWardChoice;&lt;br /&gt;
&lt;br /&gt;
      if (skillWardChoice &amp;amp;&amp;amp; skillWardChoice === attackerClass) {&lt;br /&gt;
        skillInfo.skillWard =&lt;br /&gt;
          24 * getSkillPower(victim.skillWard, skillPowerTable);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (improvedByBonus) {&lt;br /&gt;
      skillInfo.skillBonusByBonus = attacker[&amp;quot;skillBonus&amp;quot; + skillId];&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (removeSkillVariation) {&lt;br /&gt;
      var averageVariation = (skillInfo.range[0] + skillInfo.range[0]) / 2;&lt;br /&gt;
      skillInfo.range = [averageVariation, averageVariation];&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    var skillPower = getSkillPower(&lt;br /&gt;
      attacker[&amp;quot;horseSkill&amp;quot; + skillId],&lt;br /&gt;
      skillPowerTable&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    switch (skillId) {&lt;br /&gt;
      // Combat équestre&lt;br /&gt;
      case 137:&lt;br /&gt;
        skillFormula = function (atk) {&lt;br /&gt;
          return floorMultiplication(atk + 2 * atk * skillPower, 1);&lt;br /&gt;
        };&lt;br /&gt;
        break;&lt;br /&gt;
      // Charge à cheval&lt;br /&gt;
      case 138:&lt;br /&gt;
        skillFormula = function (atk) {&lt;br /&gt;
          return floorMultiplication(&lt;br /&gt;
            2.4 * (200 + 1.5 * lv) + 600 * skillPower,&lt;br /&gt;
            1&lt;br /&gt;
          );&lt;br /&gt;
        };&lt;br /&gt;
        break;&lt;br /&gt;
      // Vague de Pouvoir&lt;br /&gt;
      case 139:&lt;br /&gt;
        skillFormula = function (atk) {&lt;br /&gt;
          return floorMultiplication(&lt;br /&gt;
            2 * (200 + 1.5 * lv) + 600 * skillPower,&lt;br /&gt;
            1&lt;br /&gt;
          );&lt;br /&gt;
        };&lt;br /&gt;
        break;&lt;br /&gt;
      // Grêle de flèches&lt;br /&gt;
      case 140:&lt;br /&gt;
        skillFormula = function (atk) {&lt;br /&gt;
          return floorMultiplication(atk + 2 * atk * skillPower, 1);&lt;br /&gt;
        };&lt;br /&gt;
        break;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  updateBattleValues(battleValues, skillFormula, skillInfo);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcMagicAttackValueAugmentation(&lt;br /&gt;
  magicAttackValueWeapon,&lt;br /&gt;
  magicAttackValueBonus&lt;br /&gt;
) {&lt;br /&gt;
  if (magicAttackValueBonus) {&lt;br /&gt;
    return Math.max(&lt;br /&gt;
      1,&lt;br /&gt;
      0.0025056 *&lt;br /&gt;
        magicAttackValueBonus ** 0.602338 *&lt;br /&gt;
        magicAttackValueWeapon ** 1.20476&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
  return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getMagicAttackValueAugmentation(&lt;br /&gt;
  minMagicAttackValue,&lt;br /&gt;
  maxMagicAttackValue,&lt;br /&gt;
  magicAttackValueBonus&lt;br /&gt;
) {&lt;br /&gt;
  var magicAttackValueAugmentation = [];&lt;br /&gt;
&lt;br /&gt;
  for (&lt;br /&gt;
    var magicAttackValue = minMagicAttackValue;&lt;br /&gt;
    magicAttackValue &amp;lt;= maxMagicAttackValue;&lt;br /&gt;
    magicAttackValue++&lt;br /&gt;
  ) {&lt;br /&gt;
    magicAttackValueAugmentation.push(&lt;br /&gt;
      calcMagicAttackValueAugmentation(magicAttackValue, magicAttackValueBonus)&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return magicAttackValueAugmentation;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcPhysicalDamage(battleValues) {&lt;br /&gt;
  const {&lt;br /&gt;
    attackFactor,&lt;br /&gt;
    mainAttackValue,&lt;br /&gt;
    attackValues: {&lt;br /&gt;
      minAttackValue,&lt;br /&gt;
      maxAttackValue,&lt;br /&gt;
      attackValueOther,&lt;br /&gt;
      weights,&lt;br /&gt;
      criticalAttackRange,&lt;br /&gt;
    },&lt;br /&gt;
    bonusValues,&lt;br /&gt;
    damageWeightedByType,&lt;br /&gt;
  } = battleValues;&lt;br /&gt;
&lt;br /&gt;
  const savedDamage = {};&lt;br /&gt;
&lt;br /&gt;
  if (bonusValues.missPercentage) {&lt;br /&gt;
    damageWeightedByType.miss = bonusValues.missPercentage / 100;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (&lt;br /&gt;
    let attackValue = minAttackValue;&lt;br /&gt;
    attackValue &amp;lt;= maxAttackValue;&lt;br /&gt;
    attackValue++&lt;br /&gt;
  ) {&lt;br /&gt;
    const weight = weights[attackValue - minAttackValue];&lt;br /&gt;
    const damageByType = [[], [], [], []];&lt;br /&gt;
    const currentDamageInfo = [weight, damageByType];&lt;br /&gt;
&lt;br /&gt;
    const secondaryAttackValue = 2 * attackValue + attackValueOther;&lt;br /&gt;
    const rawDamage =&lt;br /&gt;
      mainAttackValue + floorMultiplication(attackFactor, secondaryAttackValue);&lt;br /&gt;
&lt;br /&gt;
    const damageWithPrimaryBonuses = calcDamageWithPrimaryBonuses(&lt;br /&gt;
      rawDamage,&lt;br /&gt;
      bonusValues&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    const minPiercingDamage =&lt;br /&gt;
      damageWithPrimaryBonuses -&lt;br /&gt;
      bonusValues.defenseBoost -&lt;br /&gt;
      bonusValues.defenseMarriage;&lt;br /&gt;
&lt;br /&gt;
    const damageValues =&lt;br /&gt;
      minPiercingDamage &amp;lt;= 2 ? [1, 2, 3, 4, 5] : [minPiercingDamage];&lt;br /&gt;
&lt;br /&gt;
    for (const damage of damageValues) {&lt;br /&gt;
      saveFinalDamage(&lt;br /&gt;
        damage,&lt;br /&gt;
        minPiercingDamage,&lt;br /&gt;
        damageWithPrimaryBonuses,&lt;br /&gt;
        bonusValues,&lt;br /&gt;
        criticalAttackRange,&lt;br /&gt;
        damageByType&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    savedDamage[attackValue] = currentDamageInfo;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  processSavedDamage(savedDamage, damageWeightedByType, battleValues);&lt;br /&gt;
&lt;br /&gt;
  return damageWeightedByType;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcPhysicalSkillDamage(battleValues) {&lt;br /&gt;
  const {&lt;br /&gt;
    attackFactor,&lt;br /&gt;
    mainAttackValue,&lt;br /&gt;
    attackValues: {&lt;br /&gt;
      minAttackValue,&lt;br /&gt;
      maxAttackValue,&lt;br /&gt;
      attackValueOther,&lt;br /&gt;
      weights,&lt;br /&gt;
      criticalAttackRange,&lt;br /&gt;
    },&lt;br /&gt;
    bonusValues,&lt;br /&gt;
    damageWeightedByType,&lt;br /&gt;
    skillFormula,&lt;br /&gt;
    skillRange: [minVariation, maxVariation],&lt;br /&gt;
  } = battleValues;&lt;br /&gt;
&lt;br /&gt;
  const savedDamage = {};&lt;br /&gt;
&lt;br /&gt;
  for (&lt;br /&gt;
    let attackValue = minAttackValue;&lt;br /&gt;
    attackValue &amp;lt;= maxAttackValue;&lt;br /&gt;
    attackValue++&lt;br /&gt;
  ) {&lt;br /&gt;
    const weight = weights[attackValue - minAttackValue];&lt;br /&gt;
&lt;br /&gt;
    const secondaryAttackValue = 2 * attackValue + attackValueOther;&lt;br /&gt;
    const rawDamage =&lt;br /&gt;
      mainAttackValue + floorMultiplication(attackFactor, secondaryAttackValue);&lt;br /&gt;
&lt;br /&gt;
    const damageWithPrimaryBonuses = calcDamageWithPrimaryBonuses(&lt;br /&gt;
      rawDamage,&lt;br /&gt;
      bonusValues&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    const damageValues =&lt;br /&gt;
      damageWithPrimaryBonuses &amp;lt;= 2&lt;br /&gt;
        ? [1, 2, 3, 4, 5]&lt;br /&gt;
        : [damageWithPrimaryBonuses];&lt;br /&gt;
&lt;br /&gt;
    for (let variation = minVariation; variation &amp;lt;= maxVariation; variation++) {&lt;br /&gt;
      for (const damage of damageValues) {&lt;br /&gt;
        const damageWithFormula = skillFormula(&lt;br /&gt;
          damage * bonusValues.useDamage,&lt;br /&gt;
          variation&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        let damageKey = damageWithFormula;&lt;br /&gt;
&lt;br /&gt;
        if (damageWithPrimaryBonuses &amp;lt; 0) {&lt;br /&gt;
          damageKey = `${damageWithFormula}_${Math.abs(&lt;br /&gt;
            damageWithPrimaryBonuses&lt;br /&gt;
          )}`;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        const entry = savedDamage[damageKey];&lt;br /&gt;
&lt;br /&gt;
        if (entry) {&lt;br /&gt;
          entry[0] += weight;&lt;br /&gt;
          continue;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        const damageByType = [[], [], [], []];&lt;br /&gt;
        const currentDamageInfo = [weight, damageByType];&lt;br /&gt;
&lt;br /&gt;
        const finalDamage = Math.floor(&lt;br /&gt;
          (damageWithFormula * bonusValues.weaponBonusCoeff) / 100&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        saveFinalSkillDamage(&lt;br /&gt;
          finalDamage,&lt;br /&gt;
          damageWithPrimaryBonuses,&lt;br /&gt;
          bonusValues,&lt;br /&gt;
          criticalAttackRange,&lt;br /&gt;
          damageByType&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        savedDamage[damageKey] = currentDamageInfo;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  processSavedDamage(savedDamage, damageWeightedByType, battleValues);&lt;br /&gt;
&lt;br /&gt;
  return damageWeightedByType;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcMagicSkillDamage(battleValues) {&lt;br /&gt;
  const {&lt;br /&gt;
    attackValues: {&lt;br /&gt;
      minMagicAttackValue,&lt;br /&gt;
      maxMagicAttackValue,&lt;br /&gt;
      magicAttackValueAugmentation,&lt;br /&gt;
      weights,&lt;br /&gt;
      criticalAttackRange,&lt;br /&gt;
    },&lt;br /&gt;
    bonusValues,&lt;br /&gt;
    damageWeightedByType,&lt;br /&gt;
    skillFormula,&lt;br /&gt;
    skillRange: [minVariation, maxVariation],&lt;br /&gt;
  } = battleValues;&lt;br /&gt;
&lt;br /&gt;
  const savedDamage = {};&lt;br /&gt;
&lt;br /&gt;
  for (&lt;br /&gt;
    let magicAttackValue = minMagicAttackValue;&lt;br /&gt;
    magicAttackValue &amp;lt;= maxMagicAttackValue;&lt;br /&gt;
    magicAttackValue++&lt;br /&gt;
  ) {&lt;br /&gt;
    const index = magicAttackValue - minMagicAttackValue;&lt;br /&gt;
    const weight = weights[index];&lt;br /&gt;
&lt;br /&gt;
    for (let variation = minVariation; variation &amp;lt;= maxVariation; variation++) {&lt;br /&gt;
      const rawDamage = skillFormula(&lt;br /&gt;
        magicAttackValue + magicAttackValueAugmentation[index],&lt;br /&gt;
        variation&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      const entry = savedDamage[rawDamage];&lt;br /&gt;
&lt;br /&gt;
      if (entry) {&lt;br /&gt;
        entry[0] += weight;&lt;br /&gt;
        continue;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      const damageByType = [[], [], [], []];&lt;br /&gt;
      const currentDamageInfo = [weight, damageByType];&lt;br /&gt;
&lt;br /&gt;
      let damageWithPrimaryBonuses = Math.floor(&lt;br /&gt;
        (rawDamage * bonusValues.weaponBonusCoeff) / 100&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      damageWithPrimaryBonuses = calcDamageWithPrimaryBonuses(&lt;br /&gt;
        damageWithPrimaryBonuses,&lt;br /&gt;
        bonusValues&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      const damageValues =&lt;br /&gt;
        damageWithPrimaryBonuses &amp;lt;= 2&lt;br /&gt;
          ? [1, 2, 3, 4, 5]&lt;br /&gt;
          : [damageWithPrimaryBonuses];&lt;br /&gt;
&lt;br /&gt;
      for (const damage of damageValues) {&lt;br /&gt;
        saveFinalSkillDamage(&lt;br /&gt;
          damage,&lt;br /&gt;
          damageWithPrimaryBonuses,&lt;br /&gt;
          bonusValues,&lt;br /&gt;
          criticalAttackRange,&lt;br /&gt;
          damageByType&lt;br /&gt;
        );&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      savedDamage[rawDamage] = currentDamageInfo;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  processSavedDamage(savedDamage, damageWeightedByType, battleValues);&lt;br /&gt;
&lt;br /&gt;
  return damageWeightedByType;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcDamage(&lt;br /&gt;
  attacker,&lt;br /&gt;
  victim,&lt;br /&gt;
  attackType,&lt;br /&gt;
  battle,&lt;br /&gt;
  removeSkillVariation&lt;br /&gt;
) {&lt;br /&gt;
  var damageCalculator, skillId, skillType;&lt;br /&gt;
&lt;br /&gt;
  if (attackType === &amp;quot;physical&amp;quot;) {&lt;br /&gt;
    damageCalculator = calcPhysicalDamage;&lt;br /&gt;
  } else if (attackType.startsWith(&amp;quot;attackSkill&amp;quot;)) {&lt;br /&gt;
    skillId = Number(attackType.split(&amp;quot;attackSkill&amp;quot;)[1]);&lt;br /&gt;
&lt;br /&gt;
    if (isMagicClass(attacker) || isDispell(attacker, skillId)) {&lt;br /&gt;
      skillType = &amp;quot;magic&amp;quot;;&lt;br /&gt;
      damageCalculator = calcMagicSkillDamage;&lt;br /&gt;
    } else {&lt;br /&gt;
      skillType = &amp;quot;physical&amp;quot;;&lt;br /&gt;
      damageCalculator = calcPhysicalSkillDamage;&lt;br /&gt;
    }&lt;br /&gt;
  } else if (attackType.startsWith(&amp;quot;horseSkill&amp;quot;)) {&lt;br /&gt;
    skillType = &amp;quot;physical&amp;quot;;&lt;br /&gt;
    skillId = Number(attackType.split(&amp;quot;horseSkill&amp;quot;)[1]);&lt;br /&gt;
    damageCalculator = calcPhysicalSkillDamage;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var battleValues = createBattleValues(attacker, victim, battle, skillType);&lt;br /&gt;
&lt;br /&gt;
  if (skillId) {&lt;br /&gt;
    getSkillFormula(battle, skillId, battleValues, removeSkillVariation);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    damageWeightedByType: damageCalculator(battleValues),&lt;br /&gt;
    attackValues: battleValues.attackValues,&lt;br /&gt;
    skillType: skillType,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function damageWithoutVariation(&lt;br /&gt;
  attacker,&lt;br /&gt;
  victim,&lt;br /&gt;
  attackType,&lt;br /&gt;
  battle,&lt;br /&gt;
  characters&lt;br /&gt;
) {&lt;br /&gt;
  var startDamageTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
  var { damageWeightedByType, attackValues, skillType } = calcDamage(&lt;br /&gt;
    attacker,&lt;br /&gt;
    victim,&lt;br /&gt;
    attackType,&lt;br /&gt;
    battle&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  var endDamageTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
  displayResults(&lt;br /&gt;
    attackValues,&lt;br /&gt;
    damageWeightedByType,&lt;br /&gt;
    battle,&lt;br /&gt;
    attacker.name,&lt;br /&gt;
    victim.name&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  var endDisplayTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
  displayFightInfo(&lt;br /&gt;
    attackValues.possibleDamageCount,&lt;br /&gt;
    endDamageTime - startDamageTime,&lt;br /&gt;
    endDisplayTime - endDamageTime,&lt;br /&gt;
    battle&lt;br /&gt;
  );&lt;br /&gt;
  addPotentialErrorInformation(&lt;br /&gt;
    battle.errorInformation,&lt;br /&gt;
    attacker,&lt;br /&gt;
    victim,&lt;br /&gt;
    skillType,&lt;br /&gt;
    characters&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  hideElement(battle.bonusVariationResultContainer);&lt;br /&gt;
  showElement(battle.fightResultTitle);&lt;br /&gt;
  showElement(battle.fightResultContainer);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function damageWithVariation(&lt;br /&gt;
  attacker,&lt;br /&gt;
  victim,&lt;br /&gt;
  attackType,&lt;br /&gt;
  battle,&lt;br /&gt;
  entity,&lt;br /&gt;
  entityVariation&lt;br /&gt;
) {&lt;br /&gt;
  var startTime = performance.now();&lt;br /&gt;
  var damageByBonus = [];&lt;br /&gt;
  var augmentationByBonus = [];&lt;br /&gt;
  var {&lt;br /&gt;
    bonusVariationMinValue: minVariation,&lt;br /&gt;
    bonusVariationMaxValue: maxVariation,&lt;br /&gt;
  } = entity;&lt;br /&gt;
  var step = Math.ceil((maxVariation - minVariation + 1) / 500);&lt;br /&gt;
  var simulationCount = 0;&lt;br /&gt;
  var simulationTime;&lt;br /&gt;
  var firstDamage = 1;&lt;br /&gt;
&lt;br /&gt;
  for (&lt;br /&gt;
    var bonusValue = minVariation;&lt;br /&gt;
    bonusValue &amp;lt;= maxVariation;&lt;br /&gt;
    bonusValue += step&lt;br /&gt;
  ) {&lt;br /&gt;
    entity[entityVariation] = bonusValue;&lt;br /&gt;
&lt;br /&gt;
    var {&lt;br /&gt;
      damageWeightedByType,&lt;br /&gt;
      attackValues: { totalCardinal },&lt;br /&gt;
    } = calcDamage(&lt;br /&gt;
      copyObject(attacker),&lt;br /&gt;
      copyObject(victim),&lt;br /&gt;
      attackType,&lt;br /&gt;
      battle,&lt;br /&gt;
      true&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    var meanDamage = calcMeanDamage(damageWeightedByType, totalCardinal);&lt;br /&gt;
&lt;br /&gt;
    if (bonusValue === minVariation) {&lt;br /&gt;
      firstDamage = Math.max(meanDamage, 1e-3);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    damageByBonus.push({ x: bonusValue, y: meanDamage });&lt;br /&gt;
    augmentationByBonus.push({&lt;br /&gt;
      x: bonusValue,&lt;br /&gt;
      y: meanDamage / firstDamage - 1,&lt;br /&gt;
    });&lt;br /&gt;
    simulationCount++;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var endTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
  battle.damageByBonus = damageByBonus.concat(entityVariation);&lt;br /&gt;
&lt;br /&gt;
  addToBonusVariationChart(&lt;br /&gt;
    damageByBonus,&lt;br /&gt;
    augmentationByBonus,&lt;br /&gt;
    entity.bonusVariationName,&lt;br /&gt;
    battle.bonusVariationChart&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  simulationCount = battle.numberFormats.default.format(simulationCount);&lt;br /&gt;
  simulationTime = battle.numberFormats.second.format(&lt;br /&gt;
    (endTime - startTime) / 1000&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  battle.simulationCounter.textContent = simulationCount;&lt;br /&gt;
  battle.simulationTime.textContent = simulationTime;&lt;br /&gt;
&lt;br /&gt;
  hideElement(battle.fightResultContainer);&lt;br /&gt;
  showElement(battle.fightResultTitle);&lt;br /&gt;
  showElement(battle.bonusVariationResultContainer);&lt;br /&gt;
&lt;br /&gt;
  if (&lt;br /&gt;
    isChecked(attacker.useBonusVariation) &amp;amp;&amp;amp;&lt;br /&gt;
    isChecked(victim.useBonusVariation)&lt;br /&gt;
  ) {&lt;br /&gt;
    showElement(battle.errorInformation[&amp;quot;attacker-victim-variation&amp;quot;]);&lt;br /&gt;
  } else {&lt;br /&gt;
    hideElement(battle.errorInformation[&amp;quot;attacker-victim-variation&amp;quot;]);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function changeMonsterValues(monster, instance, attacker) {&lt;br /&gt;
  switch (instance) {&lt;br /&gt;
    case &amp;quot;SungMahiTower&amp;quot;:&lt;br /&gt;
      var sungMahiFloor = 1;&lt;br /&gt;
      var sungMahiStep = 1;&lt;br /&gt;
      var rawDefense = 120;&lt;br /&gt;
&lt;br /&gt;
      if (isPC(attacker)) {&lt;br /&gt;
        sungMahiFloor = attacker.sungMahiFloor;&lt;br /&gt;
        sungMahiStep = attacker.sungMahiStep;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (monster.rank === 5) {&lt;br /&gt;
        monster.level = 121;&lt;br /&gt;
        monster.dex = 75;&lt;br /&gt;
        rawDefense += 1;&lt;br /&gt;
      } else if (monster.rank === 6) {&lt;br /&gt;
        monster.level = 123;&lt;br /&gt;
        monster.dex = 75;&lt;br /&gt;
        rawDefense += 1;&lt;br /&gt;
      } else {&lt;br /&gt;
        monster.level = 120;&lt;br /&gt;
        monster.dex = 68;&lt;br /&gt;
      }&lt;br /&gt;
      monster.vit = 100;&lt;br /&gt;
      monster.rawDefense = rawDefense + (sungMahiStep - 1) * 6;&lt;br /&gt;
      monster.fistDefense = 0;&lt;br /&gt;
      monster.swordDefense = 0;&lt;br /&gt;
      monster.twoHandedSwordDefense = 0;&lt;br /&gt;
      monster.daggerDefense = 0;&lt;br /&gt;
      monster.bellDefense = 0;&lt;br /&gt;
      monster.fanDefense = 0;&lt;br /&gt;
      monster.arrowDefense = 0;&lt;br /&gt;
      monster.clawDefense = 0;&lt;br /&gt;
      monster.magicResistance = 0;&lt;br /&gt;
      monster.fireResistance = -20;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  // Alastor&lt;br /&gt;
  if (monster.vnum === 6790) {&lt;br /&gt;
    monster.iceResistance = 0;&lt;br /&gt;
    monster.iceBonus = 0;&lt;br /&gt;
    monster.lightningResistance = -10;&lt;br /&gt;
    monster.lightningBonus = 65;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createWeapon(vnum) {&lt;br /&gt;
  var weapon = copyObject(weaponData[vnum]);&lt;br /&gt;
  var serpentVnums = [360, 380, 1210, 2230, 3250, 5200, 6150, 7330];&lt;br /&gt;
  var weaponValues = weapon[1];&lt;br /&gt;
  var isSerpent = isValueInArray(Number(vnum), serpentVnums);&lt;br /&gt;
  var isSpecial = Array.isArray(weaponValues[0]);&lt;br /&gt;
  var isMagic;&lt;br /&gt;
&lt;br /&gt;
  if (isSpecial) {&lt;br /&gt;
    isMagic = weaponValues[0][1] &amp;gt; 0;&lt;br /&gt;
  } else {&lt;br /&gt;
    isMagic = weaponValues[1] &amp;gt; 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    type: weapon[0],&lt;br /&gt;
    maxUpgrade: weapon[2].length - 1,&lt;br /&gt;
    isSerpent: isSerpent,&lt;br /&gt;
    isMagic: isMagic,&lt;br /&gt;
    getValues: function (upgrade) {&lt;br /&gt;
      var currentWeaponValues = weaponValues;&lt;br /&gt;
&lt;br /&gt;
      if (upgrade === undefined) {&lt;br /&gt;
        // rare bug when weaponUpgrade is deleted&lt;br /&gt;
        console.warn(&amp;quot;WeaponUpgrade is missing.&amp;quot;);&lt;br /&gt;
        upgrade = this.maxUpgrade;&lt;br /&gt;
      }&lt;br /&gt;
      upgrade = Math.min(upgrade, this.maxUpgrade);&lt;br /&gt;
&lt;br /&gt;
      if (isSpecial) {&lt;br /&gt;
        currentWeaponValues = weaponValues[upgrade];&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      this.minAttackValue = currentWeaponValues[2];&lt;br /&gt;
      this.maxAttackValue = currentWeaponValues[3];&lt;br /&gt;
      this.minMagicAttackValue = currentWeaponValues[0];&lt;br /&gt;
      this.maxMagicAttackValue = currentWeaponValues[1];&lt;br /&gt;
      this.growth = weapon[2][upgrade];&lt;br /&gt;
    },&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createMonster(&lt;br /&gt;
  monsterVnum,&lt;br /&gt;
  translateMonster,&lt;br /&gt;
  attacker,&lt;br /&gt;
  polymorphMonster&lt;br /&gt;
) {&lt;br /&gt;
  var monsterAttributes = monsterData[monsterVnum];&lt;br /&gt;
&lt;br /&gt;
  var monster = {&lt;br /&gt;
    vnum: Number(monsterVnum),&lt;br /&gt;
    name: translateMonster&lt;br /&gt;
      ? getTranslatedMonsterName(monsterVnum)&lt;br /&gt;
      : monsterAttributes[36],&lt;br /&gt;
    rank: monsterAttributes[0],&lt;br /&gt;
    race: monsterAttributes[1],&lt;br /&gt;
    attack: monsterAttributes[2],&lt;br /&gt;
    level: monsterAttributes[3],&lt;br /&gt;
    type: monsterAttributes[4],&lt;br /&gt;
    str: monsterAttributes[5],&lt;br /&gt;
    dex: monsterAttributes[6],&lt;br /&gt;
    vit: monsterAttributes[7],&lt;br /&gt;
    int: monsterAttributes[8],&lt;br /&gt;
    minAttackValue: monsterAttributes[9],&lt;br /&gt;
    maxAttackValue: monsterAttributes[10],&lt;br /&gt;
    rawDefense: monsterAttributes[11],&lt;br /&gt;
    criticalHit: monsterAttributes[12],&lt;br /&gt;
    piercingHit: monsterAttributes[13],&lt;br /&gt;
    fistDefense: monsterAttributes[14],&lt;br /&gt;
    swordDefense: monsterAttributes[15],&lt;br /&gt;
    twoHandedSwordDefense: monsterAttributes[16],&lt;br /&gt;
    daggerDefense: monsterAttributes[17],&lt;br /&gt;
    bellDefense: monsterAttributes[18],&lt;br /&gt;
    fanDefense: monsterAttributes[19],&lt;br /&gt;
    arrowDefense: monsterAttributes[20],&lt;br /&gt;
    clawDefense: monsterAttributes[21],&lt;br /&gt;
    fireResistance: monsterAttributes[22],&lt;br /&gt;
    lightningResistance: monsterAttributes[23],&lt;br /&gt;
    magicResistance: monsterAttributes[24],&lt;br /&gt;
    windResistance: monsterAttributes[25],&lt;br /&gt;
    lightningBonus: monsterAttributes[26],&lt;br /&gt;
    fireBonus: monsterAttributes[27],&lt;br /&gt;
    iceBonus: monsterAttributes[28],&lt;br /&gt;
    windBonus: monsterAttributes[29],&lt;br /&gt;
    earthBonus: monsterAttributes[30],&lt;br /&gt;
    darknessBonus: monsterAttributes[31],&lt;br /&gt;
    darknessResistance: monsterAttributes[32],&lt;br /&gt;
    iceResistance: monsterAttributes[33],&lt;br /&gt;
    earthResistance: monsterAttributes[34],&lt;br /&gt;
    damageMultiplier: monsterAttributes[35],&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  // monster.instance = 0;&lt;br /&gt;
&lt;br /&gt;
  // if (attacker &amp;amp;&amp;amp; monster.instance === 0) {&lt;br /&gt;
  //   changeMonsterValues(monster, &amp;quot;SungMahiTower&amp;quot;, attacker);&lt;br /&gt;
  // }&lt;br /&gt;
  if (!polymorphMonster) {&lt;br /&gt;
    changeMonsterValues(monster);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  monster.defense = monster.rawDefense + monster.level + monster.vit;&lt;br /&gt;
&lt;br /&gt;
  return monster;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addPotentialErrorInformation(&lt;br /&gt;
  errorInformation,&lt;br /&gt;
  attacker,&lt;br /&gt;
  victim,&lt;br /&gt;
  skillType,&lt;br /&gt;
  characters&lt;br /&gt;
) {&lt;br /&gt;
  for (var error of Object.values(errorInformation)) {&lt;br /&gt;
    hideElement(error);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker)) {&lt;br /&gt;
    if (isRiding(attacker)) {&lt;br /&gt;
      if (attacker.horsePoint === 0) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;horse-level&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
      showElement(errorInformation[&amp;quot;horse-stat&amp;quot;]);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isPolymorph(attacker)) {&lt;br /&gt;
      if (attacker.polymorphPoint === 0) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;polymorph-level&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (&lt;br /&gt;
        (attacker.polymorphPoint &amp;lt;= 39 &amp;amp;&amp;amp; attacker.attackValuePercent &amp;lt;= 199) ||&lt;br /&gt;
        (attacker.polymorphPoint === 40 &amp;amp;&amp;amp; attacker.attackValuePercent &amp;lt;= 299)&lt;br /&gt;
      ) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;polymorph-bonus&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
    if (skillType === &amp;quot;magic&amp;quot;) {&lt;br /&gt;
      if (attacker.magicAttackValue) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;magic-attack-value-bonus&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
      if (victim.magicResistance) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;magic-resistance&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    showElement(errorInformation[&amp;quot;monster-attacker&amp;quot;]);&lt;br /&gt;
    if (isMagicAttacker(attacker) &amp;amp;&amp;amp; victim.magicResistance) {&lt;br /&gt;
      showElement(errorInformation[&amp;quot;magic-resistance&amp;quot;]);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (isPC(victim)) {&lt;br /&gt;
    if (isRiding(victim)) {&lt;br /&gt;
      showElement(errorInformation[&amp;quot;horse-stat&amp;quot;]);&lt;br /&gt;
    }&lt;br /&gt;
    if (isPolymorph(victim)) {&lt;br /&gt;
      if (attacker.polymorphPoint === 0) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;polymorph-level&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
      showElement(errorInformation[&amp;quot;polymorph-defense&amp;quot;]);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (characters.unsavedChanges) {&lt;br /&gt;
    showElement(errorInformation[&amp;quot;save&amp;quot;]);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function reduceChartPointsListener(battle) {&lt;br /&gt;
  var {&lt;br /&gt;
    reduceChartPointsContainer,&lt;br /&gt;
    reduceChartPoints,&lt;br /&gt;
    numberFormats: { second: numberFormat },&lt;br /&gt;
    displayTime,&lt;br /&gt;
  } = battle;&lt;br /&gt;
&lt;br /&gt;
  reduceChartPoints.addEventListener(&amp;quot;change&amp;quot;, function () {&lt;br /&gt;
    reduceChartPoints.disabled = true;&lt;br /&gt;
&lt;br /&gt;
    var startDisplayTime = performance.now();&lt;br /&gt;
    var scatterDataByType = battle.scatterDataByType;&lt;br /&gt;
    var {&lt;br /&gt;
      chart,&lt;br /&gt;
      maxPoints,&lt;br /&gt;
      chart: {&lt;br /&gt;
        data: { datasets },&lt;br /&gt;
      },&lt;br /&gt;
    } = battle.damageChart;&lt;br /&gt;
    var addAnimations = false;&lt;br /&gt;
&lt;br /&gt;
    for (var index = 0; index &amp;lt; datasets.length; index++) {&lt;br /&gt;
      var dataset = datasets[index];&lt;br /&gt;
      var scatterData = scatterDataByType[dataset.name];&lt;br /&gt;
&lt;br /&gt;
      if (dataset.canBeReduced &amp;amp;&amp;amp; reduceChartPoints.checked) {&lt;br /&gt;
        dataset.data = aggregateDamage(scatterData, maxPoints);&lt;br /&gt;
        addAnimations = true;&lt;br /&gt;
      } else {&lt;br /&gt;
        dataset.data = scatterData;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    handleChartAnimations(chart, addAnimations);&lt;br /&gt;
    chart.update();&lt;br /&gt;
&lt;br /&gt;
    displayTime.textContent = numberFormat.format(&lt;br /&gt;
      (performance.now() - startDisplayTime) / 1000&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    setTimeout(function () {&lt;br /&gt;
      reduceChartPoints.disabled = false;&lt;br /&gt;
    }, 1000);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  reduceChartPointsContainer.addEventListener(&amp;quot;pointerup&amp;quot;, function (event) {&lt;br /&gt;
    if (event.pointerType === &amp;quot;mouse&amp;quot;) {&lt;br /&gt;
      if (event.target.closest(&amp;quot;label&amp;quot;)) {&lt;br /&gt;
        return;&lt;br /&gt;
      }&lt;br /&gt;
      reduceChartPoints.click();&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function downloadRawDataListener(battle) {&lt;br /&gt;
  var { downLoadRawData, downLoadRawDataVariation } = battle;&lt;br /&gt;
  var fileType = &amp;quot;text/csv;charset=utf-8;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  downLoadRawData.addEventListener(&amp;quot;click&amp;quot;, function () {&lt;br /&gt;
    var damageWeightedByType = battle.damageWeightedByType;&lt;br /&gt;
    var filename = &amp;quot;raw_damage.csv&amp;quot;;&lt;br /&gt;
    var csvContent = &amp;quot;damage,probabilities,damageType\n&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    for (var damageType in damageWeightedByType) {&lt;br /&gt;
      var damageWeighted = damageWeightedByType[damageType];&lt;br /&gt;
&lt;br /&gt;
      for (var damage in damageWeighted) {&lt;br /&gt;
        csvContent +=&lt;br /&gt;
          damage + &amp;quot;,&amp;quot; + damageWeighted[damage] + &amp;quot;,&amp;quot; + damageType + &amp;quot;\n&amp;quot;;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    downloadData(csvContent, fileType, filename);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  downLoadRawDataVariation.addEventListener(&amp;quot;click&amp;quot;, function () {&lt;br /&gt;
    var damageByBonus = battle.damageByBonus;&lt;br /&gt;
    var damageByBonusLength = damageByBonus.length;&lt;br /&gt;
    var filename = &amp;quot;damage_variation.csv&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    if (!damageByBonusLength) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var csvContent =&lt;br /&gt;
      damageByBonus[damageByBonusLength - 1] + &amp;quot;,averageDamage\n&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    for (var index = 0; index &amp;lt; damageByBonusLength - 1; index++) {&lt;br /&gt;
      var row = damageByBonus[index];&lt;br /&gt;
&lt;br /&gt;
      csvContent += row.x + &amp;quot;,&amp;quot; + row.y + &amp;quot;\n&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    downloadData(csvContent, fileType, filename);&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function displayResults(&lt;br /&gt;
  attackValues,&lt;br /&gt;
  damageWeightedByType,&lt;br /&gt;
  battle,&lt;br /&gt;
  attackerName,&lt;br /&gt;
  victimName&lt;br /&gt;
) {&lt;br /&gt;
  var [meanDamage, minDamage, maxDamage, scatterDataByType, uniqueDamageCount] =&lt;br /&gt;
    prepareDamageData(damageWeightedByType, attackValues);&lt;br /&gt;
&lt;br /&gt;
  addToDamageChart(&lt;br /&gt;
    scatterDataByType,&lt;br /&gt;
    battle.damageChart,&lt;br /&gt;
    battle.reduceChartPoints.checked&lt;br /&gt;
  );&lt;br /&gt;
  updateDamageChartDescription(&lt;br /&gt;
    battle.uniqueDamageCounters,&lt;br /&gt;
    uniqueDamageCount,&lt;br /&gt;
    battle.numberFormats.default&lt;br /&gt;
  );&lt;br /&gt;
  displayFightResults(&lt;br /&gt;
    battle,&lt;br /&gt;
    attackerName,&lt;br /&gt;
    victimName,&lt;br /&gt;
    meanDamage,&lt;br /&gt;
    minDamage,&lt;br /&gt;
    maxDamage&lt;br /&gt;
  );&lt;br /&gt;
  battle.damageWeightedByType = damageWeightedByType;&lt;br /&gt;
  battle.scatterDataByType = scatterDataByType;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function displayFightResults(&lt;br /&gt;
  battle,&lt;br /&gt;
  attackerName,&lt;br /&gt;
  victimName,&lt;br /&gt;
  meanDamage,&lt;br /&gt;
  minDamage,&lt;br /&gt;
  maxDamage&lt;br /&gt;
) {&lt;br /&gt;
  var {&lt;br /&gt;
    tableResultFight,&lt;br /&gt;
    tableResultHistory,&lt;br /&gt;
    savedFights,&lt;br /&gt;
    numberFormats: { default: numberFormat },&lt;br /&gt;
    deleteFightTemplate,&lt;br /&gt;
  } = battle;&lt;br /&gt;
&lt;br /&gt;
  hideElement(tableResultHistory.rows[1]);&lt;br /&gt;
&lt;br /&gt;
  var valuesToDisplay = [&lt;br /&gt;
    attackerName,&lt;br /&gt;
    victimName,&lt;br /&gt;
    battle.battleChoice.attackType.selectedText,&lt;br /&gt;
    meanDamage,&lt;br /&gt;
    minDamage,&lt;br /&gt;
    maxDamage,&lt;br /&gt;
  ];&lt;br /&gt;
&lt;br /&gt;
  savedFights.push(valuesToDisplay);&lt;br /&gt;
  updateSavedFights(savedFights);&lt;br /&gt;
&lt;br /&gt;
  editTableResultRow(tableResultFight.rows[1], valuesToDisplay, numberFormat);&lt;br /&gt;
  addRowToTableResultHistory(&lt;br /&gt;
    tableResultHistory,&lt;br /&gt;
    valuesToDisplay,&lt;br /&gt;
    deleteFightTemplate,&lt;br /&gt;
    numberFormat&lt;br /&gt;
  );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function displayFightInfo(&lt;br /&gt;
  possibleDamageCount,&lt;br /&gt;
  damageTimeDuration,&lt;br /&gt;
  displayTimeDuration,&lt;br /&gt;
  battle&lt;br /&gt;
) {&lt;br /&gt;
  var container = battle.possibleDamageCounter.parentElement;&lt;br /&gt;
&lt;br /&gt;
  if (possibleDamageCount &amp;lt;= 1) {&lt;br /&gt;
    hideElement(container);&lt;br /&gt;
    return;&lt;br /&gt;
  } else {&lt;br /&gt;
    showElement(container);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var { numberFormats, possibleDamageCounter, damageTime, displayTime } =&lt;br /&gt;
    battle;&lt;br /&gt;
&lt;br /&gt;
  possibleDamageCount = numberFormats.default.format(possibleDamageCount);&lt;br /&gt;
  damageTimeDuration = numberFormats.second.format(damageTimeDuration / 1000);&lt;br /&gt;
  displayTimeDuration = numberFormats.second.format(displayTimeDuration / 1000);&lt;br /&gt;
&lt;br /&gt;
  possibleDamageCounter.textContent = possibleDamageCount;&lt;br /&gt;
  damageTime.textContent = damageTimeDuration;&lt;br /&gt;
  displayTime.textContent = displayTimeDuration;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function parseTypeAndName(data) {&lt;br /&gt;
  var [type, nameOrVnum] = splitFirst(data, &amp;quot;-&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    type: type,&lt;br /&gt;
    nameOrVnum: nameOrVnum,&lt;br /&gt;
    isCharacter: type === &amp;quot;character&amp;quot;,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isCharacterSelected(characterName, selected) {&lt;br /&gt;
  if (!selected) {&lt;br /&gt;
    return false;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var { nameOrVnum, isCharacter } = parseTypeAndName(selected);&lt;br /&gt;
&lt;br /&gt;
  return nameOrVnum === characterName &amp;amp;&amp;amp; isCharacter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function useBonusVariationMode(character, variation) {&lt;br /&gt;
  return (&lt;br /&gt;
    isChecked(character.useBonusVariation) &amp;amp;&amp;amp;&lt;br /&gt;
    character.hasOwnProperty(variation) &amp;amp;&amp;amp;&lt;br /&gt;
    character.bonusVariationMinValue &amp;lt; character.bonusVariationMaxValue&lt;br /&gt;
  );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createBattle(characters, battle) {&lt;br /&gt;
  var battleChoice = battle.battleChoice;&lt;br /&gt;
  var battleForm = battleChoice.form;&lt;br /&gt;
  var lastInvalidTime = 0;&lt;br /&gt;
&lt;br /&gt;
  battleForm.addEventListener(&amp;quot;change&amp;quot;, handleBattleFormChange);&lt;br /&gt;
  battleForm.addEventListener(&amp;quot;invalid&amp;quot;, handleBattleFormInvalid, true);&lt;br /&gt;
  battleForm.addEventListener(&amp;quot;submit&amp;quot;, handleBattleFormSubmit);&lt;br /&gt;
&lt;br /&gt;
  function handleBattleFormChange(event) {&lt;br /&gt;
    var target = event.target;&lt;br /&gt;
    var { name: targetName, value: targetValue, type: targetType } = target;&lt;br /&gt;
&lt;br /&gt;
    if (targetType !== &amp;quot;radio&amp;quot;) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (targetName === &amp;quot;attackType&amp;quot;) {&lt;br /&gt;
      battleChoice.attackType.selectedText =&lt;br /&gt;
        target.previousElementSibling.textContent;&lt;br /&gt;
    } else {&lt;br /&gt;
      updateBattleChoiceButton(battleChoice, targetName, targetValue);&lt;br /&gt;
&lt;br /&gt;
      if (targetName === &amp;quot;attacker&amp;quot;) {&lt;br /&gt;
        filterAttackTypeSelection(characters, battleChoice, targetValue);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function handleBattleFormInvalid(event) {&lt;br /&gt;
    var currentTime = Date.now();&lt;br /&gt;
&lt;br /&gt;
    if (currentTime - lastInvalidTime &amp;lt; 100) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    lastInvalidTime = currentTime;&lt;br /&gt;
&lt;br /&gt;
    var target = event.target;&lt;br /&gt;
    var modal = target.closest(&amp;quot;.modal&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (!modal) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var dataModal = modal.dataset.modal;&lt;br /&gt;
&lt;br /&gt;
    if (!dataModal) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var category = dataModal.split(&amp;quot;-&amp;quot;)[0];&lt;br /&gt;
&lt;br /&gt;
    if (isValueInArray(category, battleChoice.categories)) {&lt;br /&gt;
      battleChoice[category].button.click();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function handleBattleFormSubmit(event) {&lt;br /&gt;
    event.preventDefault();&lt;br /&gt;
&lt;br /&gt;
    // auto save&lt;br /&gt;
    if (characters.unsavedChanges) {&lt;br /&gt;
      characters.saveButton.click();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var battleInfo = new FormData(event.target);&lt;br /&gt;
    var attackerData = battleInfo.get(&amp;quot;attacker&amp;quot;);&lt;br /&gt;
    var attackType = battleInfo.get(&amp;quot;attackType&amp;quot;);&lt;br /&gt;
    var victimData = battleInfo.get(&amp;quot;victim&amp;quot;);&lt;br /&gt;
    var attackerVariation;&lt;br /&gt;
    var victimVariation;&lt;br /&gt;
&lt;br /&gt;
    if (!attackerData &amp;amp;&amp;amp; !attackType &amp;amp;&amp;amp; !victimData) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var { nameOrVnum: attackerNameOrVnum, isCharacter: attackerIsPlayer } =&lt;br /&gt;
      parseTypeAndName(attackerData);&lt;br /&gt;
    var { nameOrVnum: victimNameOrVnum, isCharacter: victimIsPlayer } =&lt;br /&gt;
      parseTypeAndName(victimData);&lt;br /&gt;
&lt;br /&gt;
    if (attackerIsPlayer) {&lt;br /&gt;
      var attacker = copyObject(characters.savedCharacters[attackerNameOrVnum]);&lt;br /&gt;
      attackerVariation = attacker.bonusVariation;&lt;br /&gt;
    } else {&lt;br /&gt;
      var attacker = createMonster(&lt;br /&gt;
        attackerNameOrVnum,&lt;br /&gt;
        characters.translateMonsters&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (victimIsPlayer) {&lt;br /&gt;
      var victim = copyObject(characters.savedCharacters[victimNameOrVnum]);&lt;br /&gt;
      victimVariation = victim.bonusVariation;&lt;br /&gt;
    } else {&lt;br /&gt;
      var victim = createMonster(&lt;br /&gt;
        victimNameOrVnum,&lt;br /&gt;
        characters.translateMonsters,&lt;br /&gt;
        attacker&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (useBonusVariationMode(attacker, attackerVariation)) {&lt;br /&gt;
      damageWithVariation(&lt;br /&gt;
        attacker,&lt;br /&gt;
        victim,&lt;br /&gt;
        attackType,&lt;br /&gt;
        battle,&lt;br /&gt;
        attacker,&lt;br /&gt;
        attackerVariation&lt;br /&gt;
      );&lt;br /&gt;
    } else if (useBonusVariationMode(victim, victimVariation)) {&lt;br /&gt;
      damageWithVariation(&lt;br /&gt;
        attacker,&lt;br /&gt;
        victim,&lt;br /&gt;
        attackType,&lt;br /&gt;
        battle,&lt;br /&gt;
        victim,&lt;br /&gt;
        victimVariation&lt;br /&gt;
      );&lt;br /&gt;
    } else {&lt;br /&gt;
      damageWithoutVariation(attacker, victim, attackType, battle, characters);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createMapping() {&lt;br /&gt;
  return {&lt;br /&gt;
    typeFlag: [&lt;br /&gt;
      &amp;quot;animalBonus&amp;quot;, // 0&lt;br /&gt;
      &amp;quot;humanBonus&amp;quot;, // 1&lt;br /&gt;
      &amp;quot;orcBonus&amp;quot;, // 2&lt;br /&gt;
      &amp;quot;mysticBonus&amp;quot;, // 3&lt;br /&gt;
      &amp;quot;undeadBonus&amp;quot;, // 4&lt;br /&gt;
      &amp;quot;insectBonus&amp;quot;, // 5&lt;br /&gt;
      &amp;quot;desertBonus&amp;quot;, // 6&lt;br /&gt;
      &amp;quot;devilBonus&amp;quot;, // 7&lt;br /&gt;
    ],&lt;br /&gt;
    raceBonus: {&lt;br /&gt;
      warrior: &amp;quot;warriorBonus&amp;quot;,&lt;br /&gt;
      sura: &amp;quot;suraBonus&amp;quot;,&lt;br /&gt;
      ninja: &amp;quot;ninjaBonus&amp;quot;,&lt;br /&gt;
      shaman: &amp;quot;shamanBonus&amp;quot;,&lt;br /&gt;
      lycan: &amp;quot;lycanBonus&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    raceResistance: {&lt;br /&gt;
      warrior: &amp;quot;warriorResistance&amp;quot;,&lt;br /&gt;
      sura: &amp;quot;suraResistance&amp;quot;,&lt;br /&gt;
      ninja: &amp;quot;ninjaResistance&amp;quot;,&lt;br /&gt;
      shaman: &amp;quot;shamanResistance&amp;quot;,&lt;br /&gt;
      lycan: &amp;quot;lycanResistance&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    defenseWeapon: [&lt;br /&gt;
      &amp;quot;swordDefense&amp;quot;, // 0&lt;br /&gt;
      &amp;quot;daggerDefense&amp;quot;, // 1&lt;br /&gt;
      &amp;quot;arrowDefense&amp;quot;, // 2&lt;br /&gt;
      &amp;quot;twoHandedSwordDefense&amp;quot;, // 3&lt;br /&gt;
      &amp;quot;bellDefense&amp;quot;, // 4&lt;br /&gt;
      &amp;quot;clawDefense&amp;quot;, // 5&lt;br /&gt;
      &amp;quot;fanDefense&amp;quot;, // 6&lt;br /&gt;
      &amp;quot;swordDefense&amp;quot;, // 7&lt;br /&gt;
      &amp;quot;fistDefense&amp;quot;, // 8&lt;br /&gt;
    ],&lt;br /&gt;
    breakWeapon: [&lt;br /&gt;
      &amp;quot;breakSwordDefense&amp;quot;, // 0&lt;br /&gt;
      &amp;quot;breakDaggerDefense&amp;quot;, // 1&lt;br /&gt;
      &amp;quot;breakArrowDefense&amp;quot;, // 2&lt;br /&gt;
      &amp;quot;breakTwoHandedSwordDefense&amp;quot;, // 3&lt;br /&gt;
      &amp;quot;breakBellDefense&amp;quot;, // 4&lt;br /&gt;
      &amp;quot;breakClawDefense&amp;quot;, // 5&lt;br /&gt;
      &amp;quot;breakFanDefense&amp;quot;, // 6&lt;br /&gt;
      &amp;quot;breakSwordDefense&amp;quot;, // 7&lt;br /&gt;
    ],&lt;br /&gt;
    elementBonus: [&lt;br /&gt;
      &amp;quot;fireBonus&amp;quot;, // 0&lt;br /&gt;
      &amp;quot;iceBonus&amp;quot;, // 1&lt;br /&gt;
      &amp;quot;windBonus&amp;quot;, // 2&lt;br /&gt;
      &amp;quot;lightningBonus&amp;quot;, // 3&lt;br /&gt;
      &amp;quot;earthBonus&amp;quot;, // 4&lt;br /&gt;
      &amp;quot;darknessBonus&amp;quot;, // 5&lt;br /&gt;
    ],&lt;br /&gt;
    elementResistance: [&lt;br /&gt;
      &amp;quot;fireResistance&amp;quot;, // 0&lt;br /&gt;
      &amp;quot;iceResistance&amp;quot;, // 1&lt;br /&gt;
      &amp;quot;windResistance&amp;quot;, // 2&lt;br /&gt;
      &amp;quot;lightningResistance&amp;quot;, // 3&lt;br /&gt;
      &amp;quot;earthResistance&amp;quot;, // 4&lt;br /&gt;
      &amp;quot;darknessResistance&amp;quot;, // 5&lt;br /&gt;
    ],&lt;br /&gt;
    attackType: [&lt;br /&gt;
      &amp;quot;normalHit&amp;quot;,&lt;br /&gt;
      &amp;quot;criticalHit&amp;quot;,&lt;br /&gt;
      &amp;quot;piercingHit&amp;quot;,&lt;br /&gt;
      &amp;quot;criticalPiercingHit&amp;quot;,&lt;br /&gt;
    ],&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createConstants() {&lt;br /&gt;
  var constants = {&lt;br /&gt;
    polymorphPowerTable: [&lt;br /&gt;
      10, 11, 11, 12, 13, 13, 14, 15, 16, 17, 18, 19, 20, 22, 23, 24, 26, 27,&lt;br /&gt;
      29, 31, 33, 35, 37, 39, 41, 44, 46, 49, 52, 55, 59, 62, 66, 70, 74, 79,&lt;br /&gt;
      84, 89, 94, 100, 0,&lt;br /&gt;
    ],&lt;br /&gt;
    skillPowerTable: [&lt;br /&gt;
      0, 0.05, 0.06, 0.08, 0.1, 0.12, 0.14, 0.16, 0.18, 0.2, 0.22, 0.24, 0.26,&lt;br /&gt;
      0.28, 0.3, 0.32, 0.34, 0.36, 0.38, 0.4, 0.5, 0.52, 0.54, 0.56, 0.58, 0.6,&lt;br /&gt;
      0.63, 0.66, 0.69, 0.72, 0.82, 0.85, 0.88, 0.91, 0.94, 0.98, 1.02, 1.06,&lt;br /&gt;
      1.1, 1.15, 1.25,&lt;br /&gt;
    ],&lt;br /&gt;
    marriageTable: {&lt;br /&gt;
      harmonyEarrings: [4, 5, 6, 8],&lt;br /&gt;
      loveEarrings: [4, 5, 6, 8],&lt;br /&gt;
      harmonyBracelet: [4, 5, 6, 8],&lt;br /&gt;
      loveNecklace: [20, 25, 30, 40],&lt;br /&gt;
      harmonyNecklace: [12, 16, 20, 30],&lt;br /&gt;
    },&lt;br /&gt;
    allowedWeaponsPerRace: {&lt;br /&gt;
      warrior: [0, 3, 8],&lt;br /&gt;
      ninja: [0, 1, 2, 8],&lt;br /&gt;
      sura: [0, 7, 8],&lt;br /&gt;
      shaman: [4, 6, 8],&lt;br /&gt;
      lycan: [5, 8],&lt;br /&gt;
    },&lt;br /&gt;
  };&lt;br /&gt;
  return constants;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initResultTableHistory(battle) {&lt;br /&gt;
  var {&lt;br /&gt;
    tableResultHistory,&lt;br /&gt;
    savedFights,&lt;br /&gt;
    deleteFightTemplate,&lt;br /&gt;
    numberFormats: { default: numberFormat },&lt;br /&gt;
  } = battle;&lt;br /&gt;
  var startIndex = 3;&lt;br /&gt;
&lt;br /&gt;
  if (savedFights.length) {&lt;br /&gt;
    hideElement(tableResultHistory.rows[1]);&lt;br /&gt;
&lt;br /&gt;
    for (var savedFight of savedFights) {&lt;br /&gt;
      addRowToTableResultHistory(&lt;br /&gt;
        tableResultHistory,&lt;br /&gt;
        savedFight,&lt;br /&gt;
        deleteFightTemplate,&lt;br /&gt;
        numberFormat&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  tableResultHistory.addEventListener(&amp;quot;click&amp;quot;, function (event) {&lt;br /&gt;
    var deleteButton = event.target.closest(&amp;quot;.svg-icon-delete&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (deleteButton) {&lt;br /&gt;
      var row = deleteButton.closest(&amp;quot;tr&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
      if (row) {&lt;br /&gt;
        savedFights.splice(row.rowIndex - startIndex, 1);&lt;br /&gt;
        updateSavedFights(savedFights);&lt;br /&gt;
&lt;br /&gt;
        row.remove();&lt;br /&gt;
&lt;br /&gt;
        if (tableResultHistory.rows.length === startIndex) {&lt;br /&gt;
          showElement(tableResultHistory.rows[1]);&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initDamageChart(battle, currentLanguage, defaultText) {&lt;br /&gt;
  const { reduceChartPointsContainer, reduceChartPoints } = battle;&lt;br /&gt;
  const percentFormat = battle.numberFormats.percent;&lt;br /&gt;
  const customPlugins = {&lt;br /&gt;
    id: &amp;quot;customPlugins&amp;quot;,&lt;br /&gt;
    afterDraw(chart) {&lt;br /&gt;
      const missPercentage = chart.data.missPercentage;&lt;br /&gt;
&lt;br /&gt;
      if (!missPercentage) {&lt;br /&gt;
        return;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      const {&lt;br /&gt;
        ctx,&lt;br /&gt;
        chartArea: { top, right },&lt;br /&gt;
      } = chart;&lt;br /&gt;
      ctx.save();&lt;br /&gt;
      const text =&lt;br /&gt;
        defaultText.miss + &amp;quot; : &amp;quot; + percentFormat.format(missPercentage);&lt;br /&gt;
      const padding = 4;&lt;br /&gt;
      const fontSize = 14;&lt;br /&gt;
&lt;br /&gt;
      ctx.font = fontSize + &amp;quot;px Helvetica Neue&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
      const textWidth = ctx.measureText(text).width;&lt;br /&gt;
      const xPosition = right - textWidth - 5;&lt;br /&gt;
      const yPosition = top + 5;&lt;br /&gt;
&lt;br /&gt;
      ctx.fillStyle = &amp;quot;rgba(255, 0, 0, 0.2)&amp;quot;;&lt;br /&gt;
      ctx.fillRect(&lt;br /&gt;
        xPosition - padding,&lt;br /&gt;
        yPosition - padding,&lt;br /&gt;
        textWidth + 2 * padding,&lt;br /&gt;
        fontSize + 2 * padding&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      ctx.strokeStyle = &amp;quot;red&amp;quot;;&lt;br /&gt;
      ctx.strokeRect(&lt;br /&gt;
        xPosition - padding,&lt;br /&gt;
        yPosition - padding,&lt;br /&gt;
        textWidth + 2 * padding,&lt;br /&gt;
        fontSize + 2 * padding&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      ctx.fillStyle = &amp;quot;#666&amp;quot;;&lt;br /&gt;
      ctx.textBaseline = &amp;quot;top&amp;quot;;&lt;br /&gt;
      ctx.fillText(text, xPosition, yPosition + 1);&lt;br /&gt;
&lt;br /&gt;
      ctx.restore();&lt;br /&gt;
    },&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  Chart.register(customPlugins);&lt;br /&gt;
&lt;br /&gt;
  const ctx = battle.plotDamage.getContext(&amp;quot;2d&amp;quot;);&lt;br /&gt;
  const maxLabelsInTooltip = 10;&lt;br /&gt;
  const nullLabelText = &amp;quot; ...&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  const chart = new Chart(ctx, {&lt;br /&gt;
    type: &amp;quot;scatter&amp;quot;,&lt;br /&gt;
    data: {&lt;br /&gt;
      missPercentage: 0,&lt;br /&gt;
      datasets: [],&lt;br /&gt;
    },&lt;br /&gt;
    options: {&lt;br /&gt;
      locale: currentLanguage,&lt;br /&gt;
      responsive: true,&lt;br /&gt;
      maintainAspectRatio: false,&lt;br /&gt;
      plugins: {&lt;br /&gt;
        legend: {&lt;br /&gt;
          display: true,&lt;br /&gt;
          onHover: function (e) {&lt;br /&gt;
            e.native.target.style.cursor = &amp;quot;pointer&amp;quot;;&lt;br /&gt;
          },&lt;br /&gt;
          onLeave: function (e) {&lt;br /&gt;
            e.native.target.style.cursor = &amp;quot;default&amp;quot;;&lt;br /&gt;
          },&lt;br /&gt;
          onClick: function (e, legendItem, legend) {&lt;br /&gt;
            const currentIndex = legendItem.datasetIndex;&lt;br /&gt;
            const ci = legend.chart;&lt;br /&gt;
            const isCurrentDatasetVisible = ci.isDatasetVisible(currentIndex);&lt;br /&gt;
            const datasets = ci.data.datasets;&lt;br /&gt;
            const hideReducePoints = true;&lt;br /&gt;
            const isReducePointsChecked = reduceChartPoints.checked;&lt;br /&gt;
&lt;br /&gt;
            datasets[currentIndex].hidden = isCurrentDatasetVisible;&lt;br /&gt;
            legendItem.hidden = isCurrentDatasetVisible;&lt;br /&gt;
&lt;br /&gt;
            for (const index in datasets) {&lt;br /&gt;
              if (ci.isDatasetVisible(index) &amp;amp;&amp;amp; datasets[index].canBeReduced) {&lt;br /&gt;
                showElement(reduceChartPointsContainer);&lt;br /&gt;
                hideReducePoints = false;&lt;br /&gt;
                break;&lt;br /&gt;
              }&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            if (hideReducePoints) {&lt;br /&gt;
              hideElement(reduceChartPointsContainer);&lt;br /&gt;
              handleChartAnimations(ci, true);&lt;br /&gt;
            } else {&lt;br /&gt;
              handleChartAnimations(ci, isReducePointsChecked);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            ci.update();&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        title: {&lt;br /&gt;
          display: true,&lt;br /&gt;
          text: defaultText.damageRepartition,&lt;br /&gt;
          font: {&lt;br /&gt;
            size: 20,&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        tooltip: {&lt;br /&gt;
          callbacks: {&lt;br /&gt;
            label: function (context) {&lt;br /&gt;
              if (context.label === null) {&lt;br /&gt;
                return nullLabelText;&lt;br /&gt;
              }&lt;br /&gt;
&lt;br /&gt;
              const xValue = battle.numberFormats.default.format(&lt;br /&gt;
                context.parsed.x&lt;br /&gt;
              );&lt;br /&gt;
              const yValue = battle.numberFormats.percent.format(&lt;br /&gt;
                context.parsed.y&lt;br /&gt;
              );&lt;br /&gt;
              const label =&lt;br /&gt;
                &amp;quot; &amp;quot; +&lt;br /&gt;
                context.dataset.label +&lt;br /&gt;
                &amp;quot; : (&amp;quot; +&lt;br /&gt;
                xValue +&lt;br /&gt;
                &amp;quot;, &amp;quot; +&lt;br /&gt;
                yValue +&lt;br /&gt;
                &amp;quot;)&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
              return label;&lt;br /&gt;
            },&lt;br /&gt;
            beforeBody: function (tooltipItems) {&lt;br /&gt;
              if (tooltipItems.length &amp;gt; maxLabelsInTooltip + 1) {&lt;br /&gt;
                tooltipItems.splice(maxLabelsInTooltip + 1);&lt;br /&gt;
                tooltipItems[maxLabelsInTooltip].label = null;&lt;br /&gt;
              }&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          caretPadding: 10,&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
      scales: {&lt;br /&gt;
        x: {&lt;br /&gt;
          type: &amp;quot;linear&amp;quot;,&lt;br /&gt;
          position: &amp;quot;bottom&amp;quot;,&lt;br /&gt;
          title: {&lt;br /&gt;
            display: true,&lt;br /&gt;
            text: defaultText.damage,&lt;br /&gt;
            font: {&lt;br /&gt;
              size: 16,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          ticks: {&lt;br /&gt;
            callback: function (value) {&lt;br /&gt;
              return Number.isInteger(value) ? value : &amp;quot;&amp;quot;;&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        y: {&lt;br /&gt;
          title: {&lt;br /&gt;
            display: true,&lt;br /&gt;
            text: defaultText.percentage,&lt;br /&gt;
            font: {&lt;br /&gt;
              size: 16,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          ticks: {&lt;br /&gt;
            format: {&lt;br /&gt;
              style: &amp;quot;percent&amp;quot;,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
      elements: {&lt;br /&gt;
        point: {&lt;br /&gt;
          borderWidth: 1,&lt;br /&gt;
          radius: 3,&lt;br /&gt;
          hitRadius: 3,&lt;br /&gt;
          hoverRadius: 6,&lt;br /&gt;
          hoverBorderWidth: 2,&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
    },&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  const datasetsStyle = [&lt;br /&gt;
    {&lt;br /&gt;
      name: &amp;quot;normalHit&amp;quot;,&lt;br /&gt;
      canBeReduced: false,&lt;br /&gt;
      label: defaultText.normalHit,&lt;br /&gt;
      backgroundColor: &amp;quot;rgba(75, 192, 192, 0.2)&amp;quot;,&lt;br /&gt;
      borderColor: &amp;quot;rgba(75, 192, 192, 1)&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      name: &amp;quot;piercingHit&amp;quot;,&lt;br /&gt;
      canBeReduced: false,&lt;br /&gt;
      label: defaultText.piercingHit,&lt;br /&gt;
      backgroundColor: &amp;quot;rgba(192, 192, 75, 0.2)&amp;quot;,&lt;br /&gt;
      borderColor: &amp;quot;rgba(192, 192, 75, 1)&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      name: &amp;quot;criticalHit&amp;quot;,&lt;br /&gt;
      canBeReduced: false,&lt;br /&gt;
      label: defaultText.criticalHit,&lt;br /&gt;
      backgroundColor: &amp;quot;rgba(192, 75, 192, 0.2)&amp;quot;,&lt;br /&gt;
      borderColor: &amp;quot;rgba(192, 75, 192, 1)&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      name: &amp;quot;criticalPiercingHit&amp;quot;,&lt;br /&gt;
      canBeReduced: false,&lt;br /&gt;
      label: defaultText.criticalPiercingHit,&lt;br /&gt;
      backgroundColor: &amp;quot;rgba(75, 75, 192, 0.2)&amp;quot;,&lt;br /&gt;
      borderColor: &amp;quot;rgba(75, 75, 192, 1)&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
  ];&lt;br /&gt;
  battle.damageChart = {&lt;br /&gt;
    chart: chart,&lt;br /&gt;
    datasetsStyle: datasetsStyle,&lt;br /&gt;
    maxPoints: 500,&lt;br /&gt;
    reduceChartPointsContainer: reduceChartPointsContainer,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initBonusVariationChart(battle, currentLanguage, defaultText) {&lt;br /&gt;
  const { plotBonusVariation } = battle;&lt;br /&gt;
&lt;br /&gt;
  const ctx = plotBonusVariation.getContext(&amp;quot;2d&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  const chart = new Chart(ctx, {&lt;br /&gt;
    type: &amp;quot;line&amp;quot;,&lt;br /&gt;
    data: {&lt;br /&gt;
      datasets: [&lt;br /&gt;
        {&lt;br /&gt;
          label: defaultText.averageDamage,&lt;br /&gt;
          backgroundColor: &amp;quot;rgba(75, 192, 192, 0.2)&amp;quot;,&lt;br /&gt;
          borderColor: &amp;quot;rgba(75, 192, 192, 1)&amp;quot;,&lt;br /&gt;
          fill: true,&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          label: defaultText.damageAugmentation,&lt;br /&gt;
          backgroundColor: &amp;quot;rgba(192, 192, 75, 0.2)&amp;quot;,&lt;br /&gt;
          borderColor: &amp;quot;rgba(192, 192, 75, 1)&amp;quot;,&lt;br /&gt;
          hidden: true,&lt;br /&gt;
          yTicksFormat: { style: &amp;quot;percent&amp;quot; },&lt;br /&gt;
          fill: true,&lt;br /&gt;
        },&lt;br /&gt;
      ],&lt;br /&gt;
    },&lt;br /&gt;
    options: {&lt;br /&gt;
      locale: currentLanguage,&lt;br /&gt;
      responsive: true,&lt;br /&gt;
      maintainAspectRatio: false,&lt;br /&gt;
      plugins: {&lt;br /&gt;
        legend: {&lt;br /&gt;
          display: true,&lt;br /&gt;
          onHover: function (e) {&lt;br /&gt;
            e.native.target.style.cursor = &amp;quot;pointer&amp;quot;;&lt;br /&gt;
          },&lt;br /&gt;
          onLeave: function (e) {&lt;br /&gt;
            e.native.target.style.cursor = &amp;quot;default&amp;quot;;&lt;br /&gt;
          },&lt;br /&gt;
          onClick: function (e, legendItem, legend) {&lt;br /&gt;
            var currentIndex = legendItem.datasetIndex;&lt;br /&gt;
            var ci = legend.chart;&lt;br /&gt;
            var datasets = ci.data.datasets;&lt;br /&gt;
            var isCurrentDatasetVisible = ci.isDatasetVisible(currentIndex);&lt;br /&gt;
            var yAxis = ci.options.scales.y;&lt;br /&gt;
&lt;br /&gt;
            var otherIndex = currentIndex === 0 ? 1 : 0;&lt;br /&gt;
            var visibleDataset = isCurrentDatasetVisible&lt;br /&gt;
              ? datasets[otherIndex]&lt;br /&gt;
              : datasets[currentIndex];&lt;br /&gt;
&lt;br /&gt;
            datasets[currentIndex].hidden = isCurrentDatasetVisible;&lt;br /&gt;
            datasets[otherIndex].hidden = !isCurrentDatasetVisible;&lt;br /&gt;
&lt;br /&gt;
            yAxis.title.text = visibleDataset.label;&lt;br /&gt;
            yAxis.ticks.format = visibleDataset.yTicksFormat;&lt;br /&gt;
&lt;br /&gt;
            ci.update();&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        title: {&lt;br /&gt;
          display: true,&lt;br /&gt;
          text: defaultText.bonusVariationTitle.split(&amp;quot;[[]]&amp;quot;),&lt;br /&gt;
          font: {&lt;br /&gt;
            size: 18,&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        tooltip: {&lt;br /&gt;
          caretPadding: 10,&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
      scales: {&lt;br /&gt;
        x: {&lt;br /&gt;
          type: &amp;quot;linear&amp;quot;,&lt;br /&gt;
          position: &amp;quot;bottom&amp;quot;,&lt;br /&gt;
          title: {&lt;br /&gt;
            display: true,&lt;br /&gt;
            text: &amp;quot;Bonus&amp;quot;,&lt;br /&gt;
            font: {&lt;br /&gt;
              size: 16,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          ticks: {&lt;br /&gt;
            callback: function (value) {&lt;br /&gt;
              if (Number.isInteger(value)) {&lt;br /&gt;
                return Number(value);&lt;br /&gt;
              }&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        y: {&lt;br /&gt;
          title: {&lt;br /&gt;
            display: true,&lt;br /&gt;
            text: defaultText.averageDamage,&lt;br /&gt;
            font: {&lt;br /&gt;
              size: 16,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
      elements: {&lt;br /&gt;
        point: {&lt;br /&gt;
          borderWidth: 1,&lt;br /&gt;
          radius: 3,&lt;br /&gt;
          hitRadius: 3,&lt;br /&gt;
          hoverRadius: 6,&lt;br /&gt;
          hoverBorderWidth: 2,&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
    },&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  battle.bonusVariationChart = chart;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterAttackTypeSelection(characters, battleChoice, targetValue) {&lt;br /&gt;
  var { nameOrVnum: attackerNameOrVnum, isCharacter: isAttackerPlayer } =&lt;br /&gt;
    parseTypeAndName(targetValue);&lt;br /&gt;
&lt;br /&gt;
  if (isAttackerPlayer) {&lt;br /&gt;
    var attacker = characters.savedCharacters[attackerNameOrVnum];&lt;br /&gt;
    filterAttackTypeSelectionCharacter(attacker, battleChoice.attackType);&lt;br /&gt;
  } else {&lt;br /&gt;
    filterAttackTypeSelectionMonster(battleChoice.attackType);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addBattleData(battle) {&lt;br /&gt;
  var errorElements = document.querySelectorAll(&amp;quot;[data-error]&amp;quot;);&lt;br /&gt;
  var { elements: attackTypeElements, container: attackTypeContainer } =&lt;br /&gt;
    battle.battleChoice.attackType;&lt;br /&gt;
  var attackTypeChilds = attackTypeContainer.children;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; errorElements.length; index++) {&lt;br /&gt;
    var errorElement = errorElements[index];&lt;br /&gt;
    battle.errorInformation[errorElement.dataset.error] = errorElement;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (var index = 1; index &amp;lt; attackTypeChilds.length - 1; index++) {&lt;br /&gt;
    var attackTypeChild = attackTypeChilds[index];&lt;br /&gt;
    var input = attackTypeChild.querySelector(&amp;quot;input&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    attackTypeElements.push({&lt;br /&gt;
      container: attackTypeChild,&lt;br /&gt;
      input: input,&lt;br /&gt;
      inputClass: input.dataset.class,&lt;br /&gt;
      inputValue: input.value,&lt;br /&gt;
    });&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createDamageCalculatorInformation(&lt;br /&gt;
  defaultLang,&lt;br /&gt;
  currentLanguage,&lt;br /&gt;
  defaultText&lt;br /&gt;
) {&lt;br /&gt;
  const characters = {&lt;br /&gt;
    unsavedChanges: false,&lt;br /&gt;
    savedCharacters: {},&lt;br /&gt;
    currentCharacter: null,&lt;br /&gt;
    savedMonsters: getSavedMonsters(),&lt;br /&gt;
    monsterElements: {},&lt;br /&gt;
    characterCreation: document.getElementById(&amp;quot;character-creation&amp;quot;),&lt;br /&gt;
    addNewCharacterButton: document.getElementById(&amp;quot;add-new-character&amp;quot;),&lt;br /&gt;
    dropZone: document.getElementById(&amp;quot;character-drop-zone&amp;quot;),&lt;br /&gt;
    characterInput: document.getElementById(&amp;quot;character-input&amp;quot;),&lt;br /&gt;
    newCharacterTemplate: document.getElementById(&amp;quot;new-character-template&amp;quot;)&lt;br /&gt;
      .children[0],&lt;br /&gt;
    charactersContainer: document.getElementById(&amp;quot;characters-container&amp;quot;),&lt;br /&gt;
    monsterButtonTemplates: document.getElementById(&amp;quot;monster-button-templates&amp;quot;),&lt;br /&gt;
    monsterTemplate: document.getElementById(&amp;quot;new-monster-template&amp;quot;)&lt;br /&gt;
      .children[0],&lt;br /&gt;
    monstersContainer: document.getElementById(&amp;quot;monsters-container&amp;quot;),&lt;br /&gt;
    monsteriFrame: document.getElementById(&amp;quot;monster-iframe&amp;quot;),&lt;br /&gt;
    stoneiFrame: document.getElementById(&amp;quot;stone-iframe&amp;quot;),&lt;br /&gt;
    saveButton: document.getElementById(&amp;quot;save-character&amp;quot;),&lt;br /&gt;
    weaponCategory: document.getElementById(&amp;quot;weapon-category&amp;quot;),&lt;br /&gt;
    weaponDisplay: document.getElementById(&amp;quot;weapon-display&amp;quot;),&lt;br /&gt;
    randomAttackValue: document.getElementById(&amp;quot;random-attack-value&amp;quot;),&lt;br /&gt;
    randomMagicAttackValue: document.getElementById(&lt;br /&gt;
      &amp;quot;random-magic-attack-value&amp;quot;&lt;br /&gt;
    ),&lt;br /&gt;
    toggleSiblings: {},&lt;br /&gt;
    polymorphDisplay: document.getElementById(&amp;quot;polymorph-display&amp;quot;),&lt;br /&gt;
    bonusVariation: {&lt;br /&gt;
      tabButton: document.getElementById(&amp;quot;Variation&amp;quot;),&lt;br /&gt;
      checkbox: document.getElementById(&amp;quot;use-bonus-variation&amp;quot;),&lt;br /&gt;
      input: document.getElementById(&amp;quot;bonus-variation&amp;quot;),&lt;br /&gt;
      inputName: document.getElementById(&amp;quot;bonus-variation-name&amp;quot;),&lt;br /&gt;
      container: document.getElementById(&amp;quot;bonus-variation-creation&amp;quot;),&lt;br /&gt;
      minValue: document.getElementById(&amp;quot;bonus-variation-min-value&amp;quot;),&lt;br /&gt;
      maxValue: document.getElementById(&amp;quot;bonus-variation-max-value&amp;quot;),&lt;br /&gt;
      disabledText: document.getElementById(&amp;quot;bonus-variation-disabled&amp;quot;),&lt;br /&gt;
      selectedText: document.getElementById(&amp;quot;bonus-variation-selected&amp;quot;),&lt;br /&gt;
      displaySpan: document.getElementById(&amp;quot;bonus-variation-display&amp;quot;),&lt;br /&gt;
    },&lt;br /&gt;
    skillElementsToFilter: document.querySelectorAll(&lt;br /&gt;
      &amp;quot;#skill-container [data-class]&amp;quot;&lt;br /&gt;
    ),&lt;br /&gt;
    currentLanguage: currentLanguage,&lt;br /&gt;
    translateMonsters: defaultLang !== currentLanguage,&lt;br /&gt;
    defaultText: defaultText,&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  for (const [pseudo, character] of Object.entries(getSavedCharacters())) {&lt;br /&gt;
    characters.savedCharacters[pseudo] = character;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  document.querySelectorAll(&amp;quot;.toggle-sibling&amp;quot;).forEach(function (element) {&lt;br /&gt;
    const target = element.dataset.target;&lt;br /&gt;
    const sibling = document.getElementById(target);&lt;br /&gt;
    characters.toggleSiblings[element.name] = sibling;&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  const constants = createConstants();&lt;br /&gt;
&lt;br /&gt;
  const battle = {&lt;br /&gt;
    savedFights: getSavedFights(),&lt;br /&gt;
    battleChoice: {&lt;br /&gt;
      resetAttackType: false,&lt;br /&gt;
      form: document.getElementById(&amp;quot;create-battle&amp;quot;),&lt;br /&gt;
      template: document.getElementById(&amp;quot;battle-selection-template&amp;quot;)&lt;br /&gt;
        .children[0],&lt;br /&gt;
      raceToImage: {&lt;br /&gt;
        warrior: &amp;quot;/images/0/0f/Bandeaurougehomme.png&amp;quot;,&lt;br /&gt;
        ninja: &amp;quot;/images/0/0e/Queuedechevalclair.png&amp;quot;,&lt;br /&gt;
        sura: &amp;quot;/images/3/37/Couperespectablerouge.png&amp;quot;,&lt;br /&gt;
        shaman: &amp;quot;/images/6/6a/Coupeeleganteclairfemme.png&amp;quot;,&lt;br /&gt;
        lycan: &amp;quot;/images/4/4e/Protectionfrontalerouge.png&amp;quot;,&lt;br /&gt;
      },&lt;br /&gt;
      categories: [&amp;quot;attacker&amp;quot;, &amp;quot;victim&amp;quot;],&lt;br /&gt;
      translateMonsters: defaultLang !== currentLanguage,&lt;br /&gt;
      attacker: {&lt;br /&gt;
        character: {&lt;br /&gt;
          count: 0,&lt;br /&gt;
          container: document.getElementById(&amp;quot;attacker-selection-characters&amp;quot;),&lt;br /&gt;
          elements: {},&lt;br /&gt;
        },&lt;br /&gt;
        monster: {&lt;br /&gt;
          count: 0,&lt;br /&gt;
          container: document.getElementById(&amp;quot;attacker-selection-monsters&amp;quot;),&lt;br /&gt;
          elements: {},&lt;br /&gt;
        },&lt;br /&gt;
        button: document.getElementById(&amp;quot;attacker-trigger&amp;quot;),&lt;br /&gt;
        defaultButtonContent: document.getElementById(&lt;br /&gt;
          &amp;quot;attacker-default-button-content&amp;quot;&lt;br /&gt;
        ),&lt;br /&gt;
        buttonContent: document.getElementById(&amp;quot;attacker-button-content&amp;quot;),&lt;br /&gt;
        container: document.getElementById(&amp;quot;attacker-selection&amp;quot;),&lt;br /&gt;
        selected: null,&lt;br /&gt;
      },&lt;br /&gt;
      victim: {&lt;br /&gt;
        character: {&lt;br /&gt;
          count: 0,&lt;br /&gt;
          container: document.getElementById(&amp;quot;victim-selection-characters&amp;quot;),&lt;br /&gt;
          elements: {},&lt;br /&gt;
        },&lt;br /&gt;
        monster: {&lt;br /&gt;
          count: 0,&lt;br /&gt;
          container: document.getElementById(&amp;quot;victim-selection-monsters&amp;quot;),&lt;br /&gt;
          elements: {},&lt;br /&gt;
        },&lt;br /&gt;
        stone: {&lt;br /&gt;
          count: 0,&lt;br /&gt;
          container: document.getElementById(&amp;quot;victim-selection-stones&amp;quot;),&lt;br /&gt;
          elements: {},&lt;br /&gt;
        },&lt;br /&gt;
        button: document.getElementById(&amp;quot;victim-trigger&amp;quot;),&lt;br /&gt;
        defaultButtonContent: document.getElementById(&lt;br /&gt;
          &amp;quot;victim-default-button-content&amp;quot;&lt;br /&gt;
        ),&lt;br /&gt;
        buttonContent: document.getElementById(&amp;quot;victim-button-content&amp;quot;),&lt;br /&gt;
        selected: null,&lt;br /&gt;
      },&lt;br /&gt;
      attackType: {&lt;br /&gt;
        container: document.getElementById(&amp;quot;attack-type-selection&amp;quot;),&lt;br /&gt;
        elements: [],&lt;br /&gt;
        defaultInput: document.getElementById(&amp;quot;physical-attack&amp;quot;),&lt;br /&gt;
        selectedText: &amp;quot;&amp;quot;,&lt;br /&gt;
      },&lt;br /&gt;
    },&lt;br /&gt;
    damageWeightedByType: {},&lt;br /&gt;
    scatterDataByType: {},&lt;br /&gt;
    damageByBonus: [],&lt;br /&gt;
    tableResultFight: document.getElementById(&amp;quot;result-table-fight&amp;quot;),&lt;br /&gt;
    tableResultHistory: document.getElementById(&amp;quot;result-table-history&amp;quot;),&lt;br /&gt;
    deleteFightTemplate: document.getElementById(&amp;quot;delete-fight-template&amp;quot;)&lt;br /&gt;
      .children[0],&lt;br /&gt;
    errorInformation: {},&lt;br /&gt;
    fightResultTitle: document.getElementById(&amp;quot;fight-result-title&amp;quot;),&lt;br /&gt;
    fightResultContainer: document.getElementById(&amp;quot;fight-result-container&amp;quot;),&lt;br /&gt;
    downLoadRawData: document.getElementById(&amp;quot;download-raw-data&amp;quot;),&lt;br /&gt;
    downLoadRawDataVariation: document.getElementById(&lt;br /&gt;
      &amp;quot;download-raw-data-variation&amp;quot;&lt;br /&gt;
    ),&lt;br /&gt;
    bonusVariationResultContainer: document.getElementById(&lt;br /&gt;
      &amp;quot;bonus-variation-result-container&amp;quot;&lt;br /&gt;
    ),&lt;br /&gt;
    reduceChartPointsContainer: document.getElementById(&lt;br /&gt;
      &amp;quot;reduce-chart-points-container&amp;quot;&lt;br /&gt;
    ),&lt;br /&gt;
    reduceChartPoints: document.getElementById(&amp;quot;reduce-chart-points&amp;quot;),&lt;br /&gt;
    plotDamage: document.getElementById(&amp;quot;plot-damage&amp;quot;),&lt;br /&gt;
    plotBonusVariation: document.getElementById(&amp;quot;plot-bonus-variation&amp;quot;),&lt;br /&gt;
    uniqueDamageCounters: document.querySelectorAll(&amp;quot;.unique-damage-counter&amp;quot;),&lt;br /&gt;
    possibleDamageCounter: document.getElementById(&amp;quot;possible-damage-counter&amp;quot;),&lt;br /&gt;
    damageTime: document.getElementById(&amp;quot;damage-time&amp;quot;),&lt;br /&gt;
    displayTime: document.getElementById(&amp;quot;display-time&amp;quot;),&lt;br /&gt;
    simulationCounter: document.getElementById(&amp;quot;simulation-counter&amp;quot;),&lt;br /&gt;
    simulationTime: document.getElementById(&amp;quot;simulation-time&amp;quot;),&lt;br /&gt;
    numberFormats: {&lt;br /&gt;
      default: new Intl.NumberFormat(currentLanguage, {&lt;br /&gt;
        minimumFractionDigits: 0,&lt;br /&gt;
        maximumFractionDigits: 1,&lt;br /&gt;
      }),&lt;br /&gt;
      percent: new Intl.NumberFormat(currentLanguage, {&lt;br /&gt;
        style: &amp;quot;percent&amp;quot;,&lt;br /&gt;
        maximumFractionDigits: 3,&lt;br /&gt;
      }),&lt;br /&gt;
      second: new Intl.NumberFormat(currentLanguage, {&lt;br /&gt;
        style: &amp;quot;unit&amp;quot;,&lt;br /&gt;
        unit: &amp;quot;second&amp;quot;,&lt;br /&gt;
        unitDisplay: &amp;quot;long&amp;quot;,&lt;br /&gt;
        maximumFractionDigits: 3,&lt;br /&gt;
      }),&lt;br /&gt;
    },&lt;br /&gt;
    mapping: createMapping(),&lt;br /&gt;
    constants: constants,&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  addBattleData(battle);&lt;br /&gt;
  initResultTableHistory(battle);&lt;br /&gt;
  initDamageChart(battle, currentLanguage, defaultText);&lt;br /&gt;
  initBonusVariationChart(battle, currentLanguage, defaultText);&lt;br /&gt;
  reduceChartPointsListener(battle);&lt;br /&gt;
  downloadRawDataListener(battle);&lt;br /&gt;
&lt;br /&gt;
  return [characters, battle];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function parseText(input) {&lt;br /&gt;
  const regex = /\[\[(.*?)\]\]|([^\[]+)/g;&lt;br /&gt;
  const result = [];&lt;br /&gt;
&lt;br /&gt;
  input.replace(regex, (_, matchA, matchText) =&amp;gt; {&lt;br /&gt;
    if (matchA !== undefined) {&lt;br /&gt;
      result.push({&lt;br /&gt;
        text: matchA,&lt;br /&gt;
        category: matchA === &amp;quot;&amp;quot; ? &amp;quot;NOTRANSLATE&amp;quot; : &amp;quot;A&amp;quot;,&lt;br /&gt;
      });&lt;br /&gt;
    } else if (matchText) {&lt;br /&gt;
      result.push({ text: matchText, category: &amp;quot;#text&amp;quot; });&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  return result;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function translateText(general) {&lt;br /&gt;
  const nodesToTranslate = [&amp;quot;A&amp;quot;, &amp;quot;I&amp;quot;, &amp;quot;B&amp;quot;];&lt;br /&gt;
&lt;br /&gt;
  for (const element of document.querySelectorAll(&amp;quot;[data-t]&amp;quot;)) {&lt;br /&gt;
    const translateText = general[element.dataset.t];&lt;br /&gt;
&lt;br /&gt;
    if (!translateText) continue;&lt;br /&gt;
&lt;br /&gt;
    const childNodes = element.childNodes;&lt;br /&gt;
&lt;br /&gt;
    if (childNodes.length === 1) {&lt;br /&gt;
      childNodes[0].textContent = translateText;&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    const parsedText = parseText(translateText);&lt;br /&gt;
&lt;br /&gt;
    let childIndex = 0;&lt;br /&gt;
    let textIndex = 0;&lt;br /&gt;
&lt;br /&gt;
    while (childIndex &amp;lt; childNodes.length) {&lt;br /&gt;
      const child = childNodes[childIndex];&lt;br /&gt;
      const parsed = parsedText[textIndex];&lt;br /&gt;
&lt;br /&gt;
      let childName = child.nodeName;&lt;br /&gt;
      const isNodeToTranslate = nodesToTranslate.includes(childName);&lt;br /&gt;
&lt;br /&gt;
      if (&lt;br /&gt;
        (childName === &amp;quot;A&amp;quot; &amp;amp;&amp;amp; child.firstChild?.nodeName === &amp;quot;IMG&amp;quot;) ||&lt;br /&gt;
        !(isNodeToTranslate || childName === &amp;quot;#text&amp;quot;) ||&lt;br /&gt;
        child.dataset?.notranslate&lt;br /&gt;
      ) {&lt;br /&gt;
        childName = &amp;quot;NOTRANSLATE&amp;quot;;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (&lt;br /&gt;
        childName === parsed.category ||&lt;br /&gt;
        (parsed.category === &amp;quot;A&amp;quot; &amp;amp;&amp;amp; isNodeToTranslate)&lt;br /&gt;
      ) {&lt;br /&gt;
        if (childName !== &amp;quot;NOTRANSLATE&amp;quot;) {&lt;br /&gt;
          child.textContent = parsed.text;&lt;br /&gt;
        }&lt;br /&gt;
        childIndex++;&lt;br /&gt;
        textIndex++;&lt;br /&gt;
      } else if (childName === &amp;quot;NOTRANSLATE&amp;quot;) {&lt;br /&gt;
        childIndex++;&lt;br /&gt;
      } else if (isNodeToTranslate) {&lt;br /&gt;
        element.insertBefore(document.createTextNode(parsed.text), child);&lt;br /&gt;
        textIndex++;&lt;br /&gt;
      } else {&lt;br /&gt;
        child.textContent = &amp;quot;&amp;quot;;&lt;br /&gt;
        childIndex++;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (textIndex &amp;lt; parsedText.length) {&lt;br /&gt;
      const textNode = document.createTextNode(parsedText[textIndex].text);&lt;br /&gt;
      element.appendChild(textNode);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function translateWeapons(weapons) {&lt;br /&gt;
  const characterCreation = document.getElementById(&amp;quot;character-creation&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  for (const weaponInput of characterCreation.elements[&amp;quot;weapon&amp;quot;]) {&lt;br /&gt;
    const weaponTranslation = weapons[weaponInput.value];&lt;br /&gt;
&lt;br /&gt;
    if (weaponTranslation) {&lt;br /&gt;
      weaponInput.parentElement.lastElementChild.textContent =&lt;br /&gt;
        weaponTranslation;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleSpecialIndexes(generalTranslations, specialIndexes) {&lt;br /&gt;
  const specialTranslations = {};&lt;br /&gt;
&lt;br /&gt;
  translation.special = specialTranslations;&lt;br /&gt;
&lt;br /&gt;
  for (const [generalIndex, specialKey] of Object.entries(specialIndexes)) {&lt;br /&gt;
    const translatedValue = generalTranslations[generalIndex];&lt;br /&gt;
&lt;br /&gt;
    if (translatedValue) {&lt;br /&gt;
      specialTranslations[specialKey] = translatedValue;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  translation.mapping = {&lt;br /&gt;
    &amp;quot;Demi-humain&amp;quot;: specialTranslations.halfHuman,&lt;br /&gt;
    Mal: specialTranslations.devil,&lt;br /&gt;
    Désert: specialTranslations.desert,&lt;br /&gt;
    Animal: specialTranslations.animal,&lt;br /&gt;
    Orc: specialTranslations.orc,&lt;br /&gt;
    Mystique: specialTranslations.mystic,&lt;br /&gt;
    &amp;quot;Mort-vivant&amp;quot;: specialTranslations.undead,&lt;br /&gt;
    Insecte: specialTranslations.insect,&lt;br /&gt;
    Zodiaque: specialTranslations.zodiac,&lt;br /&gt;
    &amp;quot;Aucun type&amp;quot;: specialTranslations.noType,&lt;br /&gt;
    Mêlée: specialTranslations.melee,&lt;br /&gt;
    Flèche: specialTranslations.arrow,&lt;br /&gt;
    Magique: specialTranslations.magic,&lt;br /&gt;
    DC: specialTranslations.skill,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function translateTitle() {&lt;br /&gt;
  const translatedTitle = translation.special.pageTitle;&lt;br /&gt;
&lt;br /&gt;
  if (translatedTitle) {&lt;br /&gt;
    document.querySelector(&amp;quot;h1&amp;quot;).textContent = translatedTitle;&lt;br /&gt;
    document.querySelector(&amp;quot;ul.subpage&amp;quot;).lastElementChild.textContent =&lt;br /&gt;
      translatedTitle;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function translateSummary() {&lt;br /&gt;
  const tocContainer = document.getElementById(&amp;quot;toc&amp;quot;);&lt;br /&gt;
  const { toc, hide } = translation.special;&lt;br /&gt;
&lt;br /&gt;
  if (tocContainer) {&lt;br /&gt;
    if (toc) {&lt;br /&gt;
      tocContainer.querySelector(&amp;quot;h2&amp;quot;).textContent = toc;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (hide) {&lt;br /&gt;
      tocContainer.querySelector(&amp;quot;a.togglelink&amp;quot;).textContent = hide;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    for (const link of tocContainer.querySelectorAll(&amp;quot;ul a&amp;quot;)) {&lt;br /&gt;
      const hash = link.hash.substr(1);&lt;br /&gt;
      const title = document.getElementById(hash);&lt;br /&gt;
&lt;br /&gt;
      if (title) {&lt;br /&gt;
        const toctext = link.querySelector(&amp;quot;span.toctext&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        if (toctext) {&lt;br /&gt;
          toctext.firstElementChild.textContent = title.textContent;&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function translateDefaultText(defaultText) {&lt;br /&gt;
  const specialTranslations = translation.special;&lt;br /&gt;
&lt;br /&gt;
  for (const key of Object.keys(defaultText)) {&lt;br /&gt;
    if (specialTranslations.hasOwnProperty(key)) {&lt;br /&gt;
      defaultText[key] = specialTranslations[key];&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function translatePage(defaultText, currentLanguage) {&lt;br /&gt;
  const mwContent = document.querySelector(&amp;quot;.mw-content-ltr&amp;quot;);&lt;br /&gt;
  const { general, weapons } = translation;&lt;br /&gt;
  const specialIndexes = {&lt;br /&gt;
    471: &amp;quot;placeholder&amp;quot;,&lt;br /&gt;
    473: &amp;quot;boss&amp;quot;,&lt;br /&gt;
    474: &amp;quot;pageTitle&amp;quot;,&lt;br /&gt;
    475: &amp;quot;toc&amp;quot;,&lt;br /&gt;
    476: &amp;quot;hide&amp;quot;,&lt;br /&gt;
    502: &amp;quot;unsavedWarning&amp;quot;,&lt;br /&gt;
    503: &amp;quot;deleteWarning&amp;quot;,&lt;br /&gt;
    504: &amp;quot;pseudo&amp;quot;,&lt;br /&gt;
    481: &amp;quot;damage&amp;quot;,&lt;br /&gt;
    505: &amp;quot;percentage&amp;quot;,&lt;br /&gt;
    506: &amp;quot;miss&amp;quot;,&lt;br /&gt;
    507: &amp;quot;normalHit&amp;quot;,&lt;br /&gt;
    508: &amp;quot;criticalHit&amp;quot;,&lt;br /&gt;
    509: &amp;quot;piercingHit&amp;quot;,&lt;br /&gt;
    510: &amp;quot;criticalPiercingHit&amp;quot;,&lt;br /&gt;
    511: &amp;quot;damageRepartition&amp;quot;,&lt;br /&gt;
    512: &amp;quot;averageDamage&amp;quot;,&lt;br /&gt;
    513: &amp;quot;damageAugmentation&amp;quot;,&lt;br /&gt;
    514: &amp;quot;bonusVariationTitle&amp;quot;,&lt;br /&gt;
    489: &amp;quot;halfHuman&amp;quot;,&lt;br /&gt;
    490: &amp;quot;devil&amp;quot;,&lt;br /&gt;
    491: &amp;quot;desert&amp;quot;,&lt;br /&gt;
    492: &amp;quot;animal&amp;quot;,&lt;br /&gt;
    493: &amp;quot;orc&amp;quot;,&lt;br /&gt;
    494: &amp;quot;mystic&amp;quot;,&lt;br /&gt;
    495: &amp;quot;undead&amp;quot;,&lt;br /&gt;
    496: &amp;quot;insect&amp;quot;,&lt;br /&gt;
    497: &amp;quot;zodiac&amp;quot;,&lt;br /&gt;
    515: &amp;quot;noType&amp;quot;,&lt;br /&gt;
    498: &amp;quot;melee&amp;quot;,&lt;br /&gt;
    499: &amp;quot;arrow&amp;quot;,&lt;br /&gt;
    500: &amp;quot;magic&amp;quot;,&lt;br /&gt;
    516: &amp;quot;skill&amp;quot;,&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  translateText(general);&lt;br /&gt;
  translateWeapons(weapons);&lt;br /&gt;
  handleSpecialIndexes(general, specialIndexes);&lt;br /&gt;
  translateTitle();&lt;br /&gt;
  translateSummary();&lt;br /&gt;
  translateDefaultText(defaultText);&lt;br /&gt;
&lt;br /&gt;
  if (mwContent) {&lt;br /&gt;
    mwContent.setAttribute(&amp;quot;lang&amp;quot;, currentLanguage);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getDefaultText() {&lt;br /&gt;
  return {&lt;br /&gt;
    unsavedWarning:&lt;br /&gt;
      &amp;quot;Voulez-vous continuer ? Les dernières modifications ne seront pas sauvegardées.&amp;quot;,&lt;br /&gt;
    deleteWarning:&lt;br /&gt;
      &amp;quot;Voulez-vous vraiment supprimer définitivement le personnage [[]] ?&amp;quot;,&lt;br /&gt;
    pseudo: &amp;quot;Pseudo&amp;quot;,&lt;br /&gt;
    damage: &amp;quot;Dégâts&amp;quot;,&lt;br /&gt;
    percentage: &amp;quot;Pourcentage&amp;quot;,&lt;br /&gt;
    miss: &amp;quot;Miss&amp;quot;,&lt;br /&gt;
    normalHit: &amp;quot;Coup classique&amp;quot;,&lt;br /&gt;
    criticalHit: &amp;quot;Coup critique&amp;quot;,&lt;br /&gt;
    piercingHit: &amp;quot;Coup perçant&amp;quot;,&lt;br /&gt;
    criticalPiercingHit: &amp;quot;Coup critique perçant&amp;quot;,&lt;br /&gt;
    damageRepartition: &amp;quot;Distribution des dégâts&amp;quot;,&lt;br /&gt;
    averageDamage: &amp;quot;Dégâts moyens&amp;quot;,&lt;br /&gt;
    damageAugmentation: &amp;quot;Augmentation des dégâts&amp;quot;,&lt;br /&gt;
    bonusVariationTitle:&lt;br /&gt;
      &amp;quot;Évolution des dégâts moyens[[]]par rapport à la valeur d'un bonus&amp;quot;,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setLanguage(radios, lang, url, reload = false) {&lt;br /&gt;
  url.searchParams.set(&amp;quot;lang&amp;quot;, lang);&lt;br /&gt;
  updateLastLang(lang);&lt;br /&gt;
&lt;br /&gt;
  if (reload) {&lt;br /&gt;
    window.location.href = url.toString();&lt;br /&gt;
  } else {&lt;br /&gt;
    radios.value = lang;&lt;br /&gt;
    history.replaceState(null, &amp;quot;&amp;quot;, url);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getCurrentLanguage(defaultLang) {&lt;br /&gt;
  const url = new URL(window.location.href);&lt;br /&gt;
  const URLlang = url.searchParams.get(&amp;quot;lang&amp;quot;);&lt;br /&gt;
  const lastLang = getLastLang();&lt;br /&gt;
  const browserLang = navigator.language.split(&amp;quot;-&amp;quot;)[0];&lt;br /&gt;
  const languageSelection = document.getElementById(&amp;quot;language-selection&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (!languageSelection) {&lt;br /&gt;
    return defaultLang;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  const radios = languageSelection.elements[&amp;quot;country&amp;quot;];&lt;br /&gt;
&lt;br /&gt;
  if (!radios) {&lt;br /&gt;
    return defaultLang;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  languageSelection.addEventListener(&amp;quot;change&amp;quot;, changeLanguage);&lt;br /&gt;
&lt;br /&gt;
  function changeLanguage(event) {&lt;br /&gt;
    const newLang = event.target.value;&lt;br /&gt;
    const newUrl = new URL(window.location.href);&lt;br /&gt;
    setLanguage(radios, newLang, newUrl, true);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  const allowedLanguages = Array.from(radios).map((input) =&amp;gt; input.value);&lt;br /&gt;
&lt;br /&gt;
  for (const lang of [URLlang, lastLang, browserLang]) {&lt;br /&gt;
    if (allowedLanguages.includes(lang)) {&lt;br /&gt;
      setLanguage(radios, lang, url);&lt;br /&gt;
      return lang;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return defaultLang;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadStyle(src) {&lt;br /&gt;
  var link = document.createElement(&amp;quot;link&amp;quot;);&lt;br /&gt;
  link.href = src;&lt;br /&gt;
  link.rel = &amp;quot;stylesheet&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  document.head.appendChild(link);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
async function addScript(src) {&lt;br /&gt;
  return new Promise((resolve, reject) =&amp;gt; {&lt;br /&gt;
    const script = document.createElement(&amp;quot;script&amp;quot;);&lt;br /&gt;
    script.src = src;&lt;br /&gt;
    script.async = true;&lt;br /&gt;
&lt;br /&gt;
    script.onload = () =&amp;gt; resolve();&lt;br /&gt;
    script.onerror = () =&amp;gt; reject(new Error(`Failed to load script: ${src}`));&lt;br /&gt;
&lt;br /&gt;
    document.head.appendChild(script);&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
(async function () {&lt;br /&gt;
  const basePath = &amp;quot;/index.php?title=Utilisateur:Ankhseram/&amp;quot;;&lt;br /&gt;
  const dataScript = `${basePath}WeaponsAndMonsters.js&amp;amp;action=raw&amp;amp;ctype=text/javascript`;&lt;br /&gt;
  const simulatorStyle = `${basePath}SimulatorStyle.css&amp;amp;action=raw&amp;amp;ctype=text/css`;&lt;br /&gt;
  const chartLibrary = &amp;quot;https://cdn.jsdelivr.net/npm/chart.js&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  const defaultLang = &amp;quot;fr&amp;quot;;&lt;br /&gt;
  const defaultText = getDefaultText();&lt;br /&gt;
  const currentLanguage = getCurrentLanguage(defaultLang);&lt;br /&gt;
&lt;br /&gt;
  loadStyle(simulatorStyle);&lt;br /&gt;
&lt;br /&gt;
  let translationScript;&lt;br /&gt;
&lt;br /&gt;
  if (currentLanguage !== defaultLang) {&lt;br /&gt;
    translationScript = `${basePath}Calculator/${currentLanguage}.js&amp;amp;action=raw&amp;amp;ctype=text/javascript`;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  const scriptsToLoad = [addScript(chartLibrary), addScript(dataScript)];&lt;br /&gt;
&lt;br /&gt;
  if (translationScript) {&lt;br /&gt;
    scriptsToLoad.push(addScript(translationScript));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  await Promise.all(scriptsToLoad);&lt;br /&gt;
&lt;br /&gt;
  if (translationScript) {&lt;br /&gt;
    translatePage(defaultText, currentLanguage);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  const [characters, battle] = createDamageCalculatorInformation(&lt;br /&gt;
    defaultLang,&lt;br /&gt;
    currentLanguage,&lt;br /&gt;
    defaultText&lt;br /&gt;
  );&lt;br /&gt;
  characterManagement(characters, battle);&lt;br /&gt;
  monsterManagement(characters, battle);&lt;br /&gt;
  updateBattleChoice(characters, battle.battleChoice);&lt;br /&gt;
  createBattle(characters, battle);&lt;br /&gt;
})();&lt;/div&gt;</summary>
		<author><name>Dexter</name></author>
		
	</entry>
	<entry>
		<id>https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Script/Calculator.js&amp;diff=106652</id>
		<title>MediaWiki:Script/Calculator.js</title>
		<link rel="alternate" type="text/html" href="https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Script/Calculator.js&amp;diff=106652"/>
		<updated>2025-03-05T06:24:33Z</updated>

		<summary type="html">&lt;p&gt;Dexter : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;function removeAccent(str) {&lt;br /&gt;
  return str.normalize(&amp;quot;NFD&amp;quot;).replace(/[\u0300-\u036f]/g, &amp;quot;&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function pseudoFormat(str) {&lt;br /&gt;
  return removeAccent(str).replace(/[^A-Za-z0-9 \(\)\+_-]+/g, &amp;quot;&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isValueInArray(value, array) {&lt;br /&gt;
  return array.indexOf(value) !== -1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function splitFirst(value, delimiter) {&lt;br /&gt;
  var parts = value.split(delimiter);&lt;br /&gt;
  var first = parts[0];&lt;br /&gt;
  var rest = parts.slice(1).join(delimiter);&lt;br /&gt;
  return [first, rest];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function copyObject(object) {&lt;br /&gt;
  var copy = {};&lt;br /&gt;
  for (var key in object) {&lt;br /&gt;
    copy[key] = object[key];&lt;br /&gt;
  }&lt;br /&gt;
  return copy;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function compareNumbers(a, b) {&lt;br /&gt;
  return b - a;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isChecked(attribute) {&lt;br /&gt;
  return attribute === &amp;quot;on&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function floorMultiplication(firstFactor, secondFactor) {&lt;br /&gt;
  return Math.floor((firstFactor * secondFactor).toFixed(8));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function truncateNumber(number, precision) {&lt;br /&gt;
  return Math.floor(number * 10 ** precision) / 10 ** precision;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function newChangeEvent() {&lt;br /&gt;
  return new Event(&amp;quot;change&amp;quot;, { bubbles: true });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function openTargetTab(target) {&lt;br /&gt;
  var tabberContainer = target.closest(&amp;quot;.tabber-container&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (!tabberContainer) {&lt;br /&gt;
    return;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var [buttonsContainer, tabsContainer] = tabberContainer.children;&lt;br /&gt;
  var buttons = buttonsContainer.children;&lt;br /&gt;
  var tabs = tabsContainer.children;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; tabs.length; index++) {&lt;br /&gt;
    var tab = tabs[index];&lt;br /&gt;
    if (tab.contains(target) &amp;amp;&amp;amp; !tab.checkVisibility()) {&lt;br /&gt;
      buttons[index].click();&lt;br /&gt;
      break;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function openTargetCollapsible(target) {&lt;br /&gt;
  var collapsible = target.closest(&amp;quot;.improved-collapsible&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (!collapsible) {&lt;br /&gt;
    return;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var span = collapsible.firstElementChild;&lt;br /&gt;
&lt;br /&gt;
  if (!span.classList.contains(&amp;quot;mw-collapsible-toggle-expanded&amp;quot;)) {&lt;br /&gt;
    span.click();&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function editTableResultRow(row, valuesToDisplay, numberFormat) {&lt;br /&gt;
  row.innerHTML = &amp;quot;&amp;quot;;&lt;br /&gt;
  for (var index = 0; index &amp;lt; valuesToDisplay.length; index++) {&lt;br /&gt;
    var cell = row.insertCell();&lt;br /&gt;
    var textContent;&lt;br /&gt;
&lt;br /&gt;
    if (index &amp;gt;= 3) {&lt;br /&gt;
      textContent = numberFormat.format(valuesToDisplay[index]);&lt;br /&gt;
    } else {&lt;br /&gt;
      textContent = valuesToDisplay[index];&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    cell.textContent = textContent;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return row;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addRowToTableResultHistory(&lt;br /&gt;
  tableResultHistory,&lt;br /&gt;
  valuesToDisplay,&lt;br /&gt;
  deleteFightTemplate,&lt;br /&gt;
  numberFormat&lt;br /&gt;
) {&lt;br /&gt;
  var row = tableResultHistory.insertRow();&lt;br /&gt;
  editTableResultRow(row, valuesToDisplay, numberFormat);&lt;br /&gt;
  var cell = row.insertCell();&lt;br /&gt;
  cell.appendChild(deleteFightTemplate.cloneNode(true));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function processSavedDamage(savedDamage, damageWeightedByType, battleValues) {&lt;br /&gt;
  const { damageTypeWeights, attackTypeMapping } = battleValues;&lt;br /&gt;
&lt;br /&gt;
  for (const key in savedDamage) {&lt;br /&gt;
    const [weight, damageByType] = savedDamage[key];&lt;br /&gt;
&lt;br /&gt;
    for (let index = 0; index &amp;lt; 4; index++) {&lt;br /&gt;
      const damageWeighted = damageWeightedByType[attackTypeMapping[index]];&lt;br /&gt;
      const damageByTypeIndex = damageByType[index];&lt;br /&gt;
&lt;br /&gt;
      if (damageByTypeIndex.length === 0) continue;&lt;br /&gt;
&lt;br /&gt;
      const currentWeight =&lt;br /&gt;
        (weight * damageTypeWeights[index]) / damageByTypeIndex.length;&lt;br /&gt;
&lt;br /&gt;
      for (const damage of damageByTypeIndex) {&lt;br /&gt;
        damageWeighted[damage] = (damageWeighted[damage] || 0) + currentWeight;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcMeanDamage(damageWeightedByType, totalCardinal) {&lt;br /&gt;
  var sumDamage = 0;&lt;br /&gt;
&lt;br /&gt;
  for (var damageTypeName in damageWeightedByType) {&lt;br /&gt;
    if (damageTypeName === &amp;quot;miss&amp;quot;) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var damageWeighted = damageWeightedByType[damageTypeName];&lt;br /&gt;
&lt;br /&gt;
    for (var damage in damageWeighted) {&lt;br /&gt;
      sumDamage += damage * damageWeighted[damage];&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return sumDamage / totalCardinal;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function prepareDamageData(damageWeightedByType, attackValues) {&lt;br /&gt;
  const totalCardinal = attackValues.totalCardinal;&lt;br /&gt;
  const scatterDataByType = {};&lt;br /&gt;
  const criticalAttackRange = attackValues.criticalAttackRange;&lt;br /&gt;
&lt;br /&gt;
  let minDamage = Infinity;&lt;br /&gt;
  let maxDamage = 0;&lt;br /&gt;
  let sumDamage = 0;&lt;br /&gt;
&lt;br /&gt;
  let possibleDamageCount = 0;&lt;br /&gt;
  let possibleDamageCountTemp = 0;&lt;br /&gt;
  let uniqueDamageCount = 0;&lt;br /&gt;
&lt;br /&gt;
  for (const damageTypeName in damageWeightedByType) {&lt;br /&gt;
    if (damageTypeName === &amp;quot;miss&amp;quot;) {&lt;br /&gt;
      scatterDataByType.miss = damageWeightedByType.miss;&lt;br /&gt;
      possibleDamageCount++;&lt;br /&gt;
      uniqueDamageCount++;&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
    const damageWeighted = damageWeightedByType[damageTypeName];&lt;br /&gt;
    const scatterData = [];&lt;br /&gt;
&lt;br /&gt;
    scatterDataByType[damageTypeName] = scatterData;&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      (damageTypeName === &amp;quot;criticalHit&amp;quot; ||&lt;br /&gt;
        damageTypeName === &amp;quot;criticalPiercingHit&amp;quot;) &amp;amp;&amp;amp;&lt;br /&gt;
      criticalAttackRange&lt;br /&gt;
    ) {&lt;br /&gt;
      possibleDamageCountTemp =&lt;br /&gt;
        attackValues.possibleDamageCount * criticalAttackRange.length;&lt;br /&gt;
    } else {&lt;br /&gt;
      possibleDamageCountTemp = attackValues.possibleDamageCount;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    for (let damage in damageWeighted) {&lt;br /&gt;
      damage = +damage;&lt;br /&gt;
&lt;br /&gt;
      if (damage &amp;lt; minDamage) {&lt;br /&gt;
        minDamage = damage;&lt;br /&gt;
      }&lt;br /&gt;
      if (damage &amp;gt; maxDamage) {&lt;br /&gt;
        maxDamage = damage;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      const weight = damageWeighted[damage];&lt;br /&gt;
      const probability = weight / totalCardinal;&lt;br /&gt;
&lt;br /&gt;
      sumDamage += damage * weight;&lt;br /&gt;
      damageWeighted[damage] = probability;&lt;br /&gt;
      scatterData.push({ x: damage, y: probability });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    const scatterDataLength = scatterData.length;&lt;br /&gt;
&lt;br /&gt;
    if (!scatterDataLength) {&lt;br /&gt;
      delete scatterDataByType[damageTypeName];&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    possibleDamageCount += possibleDamageCountTemp;&lt;br /&gt;
    uniqueDamageCount += scatterDataLength;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (minDamage === Infinity) {&lt;br /&gt;
    minDamage = 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  attackValues.possibleDamageCount = possibleDamageCount;&lt;br /&gt;
&lt;br /&gt;
  return [&lt;br /&gt;
    sumDamage / totalCardinal,&lt;br /&gt;
    minDamage,&lt;br /&gt;
    maxDamage,&lt;br /&gt;
    scatterDataByType,&lt;br /&gt;
    uniqueDamageCount,&lt;br /&gt;
  ];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function aggregateDamage(scatterData, maxPoints) {&lt;br /&gt;
  var dataLength = scatterData.length;&lt;br /&gt;
  var remainingData = dataLength;&lt;br /&gt;
  var aggregateScatterData = [];&lt;br /&gt;
&lt;br /&gt;
  for (var groupIndex = 0; groupIndex &amp;lt; maxPoints; groupIndex++) {&lt;br /&gt;
    var groupLength = Math.floor(remainingData / (maxPoints - groupIndex));&lt;br /&gt;
    var startIndex = dataLength - remainingData;&lt;br /&gt;
    var aggregateDamage = 0;&lt;br /&gt;
    var aggregateProbability = 0;&lt;br /&gt;
&lt;br /&gt;
    for (var index = startIndex; index &amp;lt; startIndex + groupLength; index++) {&lt;br /&gt;
      var { x: damage, y: probability } = scatterData[index];&lt;br /&gt;
      aggregateDamage += damage * probability;&lt;br /&gt;
      aggregateProbability += probability;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    aggregateScatterData.push({&lt;br /&gt;
      x: aggregateDamage / aggregateProbability,&lt;br /&gt;
      y: aggregateProbability,&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    remainingData -= groupLength;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return aggregateScatterData;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addToDamageChart(&lt;br /&gt;
  scatterDataByType,&lt;br /&gt;
  damageChart,&lt;br /&gt;
  isReducePointsChecked&lt;br /&gt;
) {&lt;br /&gt;
  var { chart, datasetsStyle, maxPoints, reduceChartPointsContainer } =&lt;br /&gt;
    damageChart;&lt;br /&gt;
  var isFirstDataset = true;&lt;br /&gt;
  var datasets = chart.data.datasets;&lt;br /&gt;
&lt;br /&gt;
  datasets.length = 0;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; datasetsStyle.length; index++) {&lt;br /&gt;
    var dataset = copyObject(datasetsStyle[index]);&lt;br /&gt;
&lt;br /&gt;
    if (!scatterDataByType.hasOwnProperty(dataset.name)) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var scatterData = scatterDataByType[dataset.name];&lt;br /&gt;
    var canBeReduced = scatterData.length &amp;gt; 2 * maxPoints;&lt;br /&gt;
&lt;br /&gt;
    dataset.hidden = !isFirstDataset;&lt;br /&gt;
    dataset.canBeReduced = canBeReduced;&lt;br /&gt;
&lt;br /&gt;
    if (canBeReduced &amp;amp;&amp;amp; isReducePointsChecked) {&lt;br /&gt;
      dataset.data = aggregateDamage(scatterData, maxPoints);&lt;br /&gt;
    } else {&lt;br /&gt;
      dataset.data = scatterData;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isFirstDataset) {&lt;br /&gt;
      isFirstDataset = false;&lt;br /&gt;
&lt;br /&gt;
      if (canBeReduced) {&lt;br /&gt;
        showElement(reduceChartPointsContainer);&lt;br /&gt;
&lt;br /&gt;
        if (!isReducePointsChecked) {&lt;br /&gt;
          handleChartAnimations(chart, false);&lt;br /&gt;
        }&lt;br /&gt;
      } else {&lt;br /&gt;
        hideElement(reduceChartPointsContainer);&lt;br /&gt;
        handleChartAnimations(chart, true);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    datasets.push(dataset);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  chart.data.missPercentage = scatterDataByType.miss;&lt;br /&gt;
  chart.update();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addToBonusVariationChart(&lt;br /&gt;
  damageByBonus,&lt;br /&gt;
  augmentationByBonus,&lt;br /&gt;
  xLabel,&lt;br /&gt;
  chart&lt;br /&gt;
) {&lt;br /&gt;
  chart.data.datasets[0].data = damageByBonus;&lt;br /&gt;
  chart.data.datasets[1].data = augmentationByBonus;&lt;br /&gt;
  chart.options.scales.x.title.text = xLabel;&lt;br /&gt;
  chart.update();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleChartAnimations(chart, addAnimations) {&lt;br /&gt;
  chart.options.animation = addAnimations;&lt;br /&gt;
  chart.options.animations.colors = addAnimations;&lt;br /&gt;
  chart.options.animations.x = addAnimations;&lt;br /&gt;
  chart.options.transitions.active.animation.duration = addAnimations * 1000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateDamageChartDescription(&lt;br /&gt;
  uniqueDamageCounters,&lt;br /&gt;
  uniqueDamageCount,&lt;br /&gt;
  formatNumber&lt;br /&gt;
) {&lt;br /&gt;
  uniqueDamageCounters.forEach(function (element) {&lt;br /&gt;
    if (uniqueDamageCount &amp;lt;= 1) {&lt;br /&gt;
      hideElement(element.parentElement);&lt;br /&gt;
    } else {&lt;br /&gt;
      showElement(element.parentElement);&lt;br /&gt;
      element.textContent = formatNumber.format(uniqueDamageCount);&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getMonsterName(monsterVnum) {&lt;br /&gt;
  var monsterAttributes = monsterData[monsterVnum];&lt;br /&gt;
  return monsterAttributes[monsterAttributes.length - 1];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getTranslatedMonsterName(monsterVnum) {&lt;br /&gt;
  return translation.monsters[monsterVnum];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterClass(selectedRace, classChoice, selectValueIsChanged = false) {&lt;br /&gt;
  for (var radioNode of classChoice) {&lt;br /&gt;
    var radioGrandParent = radioNode.parentElement.parentElement;&lt;br /&gt;
&lt;br /&gt;
    if (radioNode.getAttribute(&amp;quot;data-race&amp;quot;) === selectedRace) {&lt;br /&gt;
      if (!selectValueIsChanged) {&lt;br /&gt;
        radioNode.checked = true;&lt;br /&gt;
        selectValueIsChanged = true;&lt;br /&gt;
      }&lt;br /&gt;
      showElement(radioGrandParent);&lt;br /&gt;
    } else {&lt;br /&gt;
      hideElement(radioGrandParent);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterWeapon(&lt;br /&gt;
  selectedRace,&lt;br /&gt;
  weaponElement,&lt;br /&gt;
  weaponCategory,&lt;br /&gt;
  allowedWeaponsPerRace,&lt;br /&gt;
  selectValueIsChanged = false&lt;br /&gt;
) {&lt;br /&gt;
  var allowedWeapons = allowedWeaponsPerRace[selectedRace];&lt;br /&gt;
&lt;br /&gt;
  if (!selectValueIsChanged) {&lt;br /&gt;
    var weaponType = createWeapon(weaponElement.value).type;&lt;br /&gt;
&lt;br /&gt;
    if (!isValueInArray(weaponType, allowedWeapons)) {&lt;br /&gt;
      weaponElement.value = 0;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var children = weaponCategory.children;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; children.length; index++) {&lt;br /&gt;
    var child = children[index];&lt;br /&gt;
&lt;br /&gt;
    if (isValueInArray(index, allowedWeapons)) {&lt;br /&gt;
      showElement(child);&lt;br /&gt;
    } else {&lt;br /&gt;
      hideElement(child);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function changePolymorphValues(characterCreation, monsterVnum, monsterImage) {&lt;br /&gt;
  var { polymorphMonster, polymorphMonsterImage } = characterCreation;&lt;br /&gt;
&lt;br /&gt;
  polymorphMonster.value = monsterVnum;&lt;br /&gt;
  polymorphMonsterImage.value = monsterImage;&lt;br /&gt;
&lt;br /&gt;
  polymorphMonster.dispatchEvent(newChangeEvent());&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function resetImageFromWiki(image) {&lt;br /&gt;
  image.removeAttribute(&amp;quot;srcset&amp;quot;);&lt;br /&gt;
  image.removeAttribute(&amp;quot;data-file-width&amp;quot;);&lt;br /&gt;
  image.removeAttribute(&amp;quot;data-file-height&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleImageFromWiki(image, newSrc) {&lt;br /&gt;
  image.src = newSrc;&lt;br /&gt;
  image.alt = newSrc.split(&amp;quot;/&amp;quot;).pop();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handlePolymorphDisplay(characters, monsterVnum, monsterSrc) {&lt;br /&gt;
  var { translateMonsters, polymorphDisplay } = characters;&lt;br /&gt;
  var oldImage = polymorphDisplay.firstChild;&lt;br /&gt;
  var oldLink = oldImage.nextElementSibling;&lt;br /&gt;
  var monsterName = getMonsterName(monsterVnum);&lt;br /&gt;
  var displayName = translateMonsters&lt;br /&gt;
    ? getTranslatedMonsterName(monsterVnum)&lt;br /&gt;
    : monsterName;&lt;br /&gt;
  var newLink = createWikiLink(monsterName, displayName);&lt;br /&gt;
&lt;br /&gt;
  resetImageFromWiki(oldImage);&lt;br /&gt;
  handleImageFromWiki(oldImage, monsterSrc);&lt;br /&gt;
&lt;br /&gt;
  polymorphDisplay.replaceChild(newLink, oldLink);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createWikiLink(pageName, displayName) {&lt;br /&gt;
  var wikiLink = document.createElement(&amp;quot;a&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  wikiLink.href = mw.util.getUrl(pageName);&lt;br /&gt;
  wikiLink.title = pageName;&lt;br /&gt;
  wikiLink.textContent = displayName || pageName;&lt;br /&gt;
&lt;br /&gt;
  return wikiLink;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSelectedWeapon(weaponCategory) {&lt;br /&gt;
  return weaponCategory.querySelector(&amp;quot;input[type='radio']:checked&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleWeaponDisplay(&lt;br /&gt;
  weaponCategory,&lt;br /&gt;
  weaponDisplay,&lt;br /&gt;
  weaponVnum,&lt;br /&gt;
  newWeapon&lt;br /&gt;
) {&lt;br /&gt;
  var newWeapon = newWeapon || getSelectedWeapon(weaponCategory);&lt;br /&gt;
&lt;br /&gt;
  var newImage = newWeapon.nextElementSibling;&lt;br /&gt;
  var newText = document.createElement(&amp;quot;span&amp;quot;);&lt;br /&gt;
  var oldImage = weaponDisplay.firstChild;&lt;br /&gt;
  var oldText = oldImage.nextElementSibling;&lt;br /&gt;
  var weaponTooltip = newImage.nextElementSibling;&lt;br /&gt;
  var originalWeaponName = weaponTooltip.dataset.o;&lt;br /&gt;
  var weaponName = weaponTooltip.textContent;&lt;br /&gt;
&lt;br /&gt;
  if (weaponVnum == 0) {&lt;br /&gt;
    newText.textContent = weaponName;&lt;br /&gt;
  } else {&lt;br /&gt;
    var weaponLink = createWikiLink(originalWeaponName, weaponName);&lt;br /&gt;
    newText.appendChild(weaponLink);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  weaponDisplay.replaceChild(newImage.cloneNode(), oldImage);&lt;br /&gt;
  weaponDisplay.replaceChild(newText, oldText);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterUpgrade(&lt;br /&gt;
  weaponUpgrade,&lt;br /&gt;
  weaponVnum,&lt;br /&gt;
  randomAttackValue,&lt;br /&gt;
  randomMagicAttackValue&lt;br /&gt;
) {&lt;br /&gt;
  var weapon = createWeapon(weaponVnum);&lt;br /&gt;
  var currentUpgrade = Number(weaponUpgrade.value);&lt;br /&gt;
  var weaponUpgradeChildren = weaponUpgrade.children;&lt;br /&gt;
&lt;br /&gt;
  if (weapon.isSerpent) {&lt;br /&gt;
    showElement(randomAttackValue);&lt;br /&gt;
&lt;br /&gt;
    if (weapon.isMagic) {&lt;br /&gt;
      showElement(randomMagicAttackValue);&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    hideElement(randomAttackValue);&lt;br /&gt;
    hideElement(randomMagicAttackValue);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (weapon.maxUpgrade &amp;lt; 1) {&lt;br /&gt;
    hideElement(weaponUpgrade.parentElement);&lt;br /&gt;
  } else {&lt;br /&gt;
    showElement(weaponUpgrade.parentElement);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (var upgrade = 0; upgrade &amp;lt;= weapon.maxUpgrade; upgrade++) {&lt;br /&gt;
    showElement(weaponUpgradeChildren[upgrade]);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (&lt;br /&gt;
    var upgrade = weapon.maxUpgrade + 1;&lt;br /&gt;
    upgrade &amp;lt; weaponUpgradeChildren.length;&lt;br /&gt;
    upgrade++&lt;br /&gt;
  ) {&lt;br /&gt;
    hideElement(weaponUpgradeChildren[upgrade]);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (currentUpgrade &amp;gt; weapon.maxUpgrade) {&lt;br /&gt;
    weaponUpgrade.value = weapon.maxUpgrade;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterCheckbox(checkbox, element) {&lt;br /&gt;
  if (checkbox.checked) {&lt;br /&gt;
    showElement(element);&lt;br /&gt;
  } else {&lt;br /&gt;
    hideElement(element);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterSkills(selectedClass, skillElementsToFilter) {&lt;br /&gt;
  for (var element of skillElementsToFilter) {&lt;br /&gt;
    if (isValueInArray(selectedClass, element.dataset.class)) {&lt;br /&gt;
      showElement(element);&lt;br /&gt;
    } else {&lt;br /&gt;
      hideElement(element);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterForm(characters, battle) {&lt;br /&gt;
  var { saveButton, characterCreation, toggleSiblings } = characters;&lt;br /&gt;
  var allowedWeaponsPerRace = battle.constants.allowedWeaponsPerRace;&lt;br /&gt;
  var battleChoice = battle.battleChoice;&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;change&amp;quot;, function (event) {&lt;br /&gt;
    var target = event.target;&lt;br /&gt;
    var targetName = target.name;&lt;br /&gt;
&lt;br /&gt;
    saveButtonOrange(saveButton);&lt;br /&gt;
    characters.unsavedChanges = true;&lt;br /&gt;
&lt;br /&gt;
    switch (targetName) {&lt;br /&gt;
      case &amp;quot;race&amp;quot;:&lt;br /&gt;
        var selectedRace = target.value;&lt;br /&gt;
        var classChoice = characterCreation.class;&lt;br /&gt;
        var weaponElement = characterCreation.weapon;&lt;br /&gt;
&lt;br /&gt;
        filterClass(selectedRace, classChoice);&lt;br /&gt;
        filterWeapon(&lt;br /&gt;
          selectedRace,&lt;br /&gt;
          weaponElement,&lt;br /&gt;
          characters.weaponCategory,&lt;br /&gt;
          allowedWeaponsPerRace&lt;br /&gt;
        );&lt;br /&gt;
        handleWeaponDisplay(&lt;br /&gt;
          characters.weaponCategory,&lt;br /&gt;
          characters.weaponDisplay,&lt;br /&gt;
          weaponElement.value&lt;br /&gt;
        );&lt;br /&gt;
        filterUpgrade(&lt;br /&gt;
          characterCreation.weaponUpgrade,&lt;br /&gt;
          weaponElement.value,&lt;br /&gt;
          characters.randomAttackValue,&lt;br /&gt;
          characters.randomMagicAttackValue&lt;br /&gt;
        );&lt;br /&gt;
        filterSkills(classChoice.value, characters.skillElementsToFilter);&lt;br /&gt;
        handleBonusVariationUpdate(&lt;br /&gt;
          characterCreation,&lt;br /&gt;
          characters.bonusVariation,&lt;br /&gt;
          true&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        battleChoice.resetAttackType = true;&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;class&amp;quot;:&lt;br /&gt;
        filterSkills(target.value, characters.skillElementsToFilter);&lt;br /&gt;
        handleBonusVariationUpdate(&lt;br /&gt;
          characterCreation,&lt;br /&gt;
          characters.bonusVariation,&lt;br /&gt;
          true&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        battleChoice.resetAttackType = true;&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;weapon&amp;quot;:&lt;br /&gt;
        var weaponElement = characterCreation.weapon;&lt;br /&gt;
&lt;br /&gt;
        handleWeaponDisplay(&lt;br /&gt;
          characters.weaponCategory,&lt;br /&gt;
          characters.weaponDisplay,&lt;br /&gt;
          weaponElement.value,&lt;br /&gt;
          target&lt;br /&gt;
        );&lt;br /&gt;
        filterUpgrade(&lt;br /&gt;
          characterCreation.weaponUpgrade,&lt;br /&gt;
          target.value,&lt;br /&gt;
          characters.randomAttackValue,&lt;br /&gt;
          characters.randomMagicAttackValue&lt;br /&gt;
        );&lt;br /&gt;
        handleBonusVariationUpdate(&lt;br /&gt;
          characterCreation,&lt;br /&gt;
          characters.bonusVariation&lt;br /&gt;
        );&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;isRiding&amp;quot;:&lt;br /&gt;
        battleChoice.resetAttackType = true;&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;isPolymorph&amp;quot;:&lt;br /&gt;
        battleChoice.resetAttackType = true;&lt;br /&gt;
        break;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (toggleSiblings.hasOwnProperty(targetName)) {&lt;br /&gt;
      filterCheckbox(target, toggleSiblings[targetName]);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      targetName.startsWith(&amp;quot;attackSkill&amp;quot;) ||&lt;br /&gt;
      targetName.startsWith(&amp;quot;horseSkill&amp;quot;)&lt;br /&gt;
    ) {&lt;br /&gt;
      battleChoice.resetAttackType = true;&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addUniquePseudo(characterDataObject, savedCharactersPseudo) {&lt;br /&gt;
  var characterPseudo = String(characterDataObject.name);&lt;br /&gt;
  var originalPseudo = characterPseudo;&lt;br /&gt;
  var count = 0;&lt;br /&gt;
&lt;br /&gt;
  var regex = /(.*)(\d)$/;&lt;br /&gt;
  var match = characterPseudo.match(regex);&lt;br /&gt;
&lt;br /&gt;
  if (match) {&lt;br /&gt;
    originalPseudo = match[1];&lt;br /&gt;
    count = match[2];&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  while (isValueInArray(characterPseudo, savedCharactersPseudo)) {&lt;br /&gt;
    characterPseudo = originalPseudo + count;&lt;br /&gt;
    count++;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  characterDataObject.name = characterPseudo;&lt;br /&gt;
  return [characterDataObject, characterPseudo];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function convertToNumber(value) {&lt;br /&gt;
  var valueNumber = Number(value);&lt;br /&gt;
  return isNaN(valueNumber) ? value : valueNumber;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getLocalStorageValue(key, defaultValue) {&lt;br /&gt;
  var storedValue = localStorage.getItem(key);&lt;br /&gt;
&lt;br /&gt;
  if (storedValue) {&lt;br /&gt;
    return JSON.parse(storedValue);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return defaultValue;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSavedCharacters() {&lt;br /&gt;
  return getLocalStorageValue(&amp;quot;mt2-calc.characters.saved&amp;quot;, {});&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSavedMonsters() {&lt;br /&gt;
  return getLocalStorageValue(&amp;quot;mt2-calc.monsters.saved&amp;quot;, {});&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSavedFights() {&lt;br /&gt;
  return getLocalStorageValue(&amp;quot;mt2-calc.fights.saved&amp;quot;, []);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getLastLang() {&lt;br /&gt;
  return getLocalStorageValue(&amp;quot;mt2-calc.language.last-used&amp;quot;, &amp;quot;&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveToLocalStorage(key, value) {&lt;br /&gt;
  localStorage.setItem(key, JSON.stringify(value));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateSavedCharacters(savedCharacters) {&lt;br /&gt;
  saveToLocalStorage(&amp;quot;mt2-calc.characters.saved&amp;quot;, savedCharacters);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateSavedMonsters(savedMonsters) {&lt;br /&gt;
  saveToLocalStorage(&amp;quot;mt2-calc.monsters.saved&amp;quot;, savedMonsters);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateSavedFights(savedFights) {&lt;br /&gt;
  saveToLocalStorage(&amp;quot;mt2-calc.fights.saved&amp;quot;, savedFights);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateLastLang(lang) {&lt;br /&gt;
  saveToLocalStorage(&amp;quot;mt2-calc.language.last-used&amp;quot;, lang);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveCharacter(&lt;br /&gt;
  savedCharacters,&lt;br /&gt;
  characterCreation,&lt;br /&gt;
  battle,&lt;br /&gt;
  newCharacter,&lt;br /&gt;
  characterDataObject&lt;br /&gt;
) {&lt;br /&gt;
  if (!characterDataObject) {&lt;br /&gt;
    var characterData = new FormData(characterCreation);&lt;br /&gt;
    var characterDataObject = {};&lt;br /&gt;
&lt;br /&gt;
    characterData.forEach(function (value, key) {&lt;br /&gt;
      characterDataObject[key] = convertToNumber(value);&lt;br /&gt;
    });&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var characterPseudo = characterDataObject.name;&lt;br /&gt;
  var { battleChoice } = battle;&lt;br /&gt;
&lt;br /&gt;
  savedCharacters[characterPseudo] = characterDataObject;&lt;br /&gt;
  updateSavedCharacters(savedCharacters);&lt;br /&gt;
&lt;br /&gt;
  if (newCharacter) {&lt;br /&gt;
    addBattleChoice(battleChoice, characterPseudo, characterDataObject);&lt;br /&gt;
  } else {&lt;br /&gt;
    updateBattleChoiceImage(&lt;br /&gt;
      battleChoice,&lt;br /&gt;
      characterPseudo,&lt;br /&gt;
      characterDataObject.race&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (battleChoice.resetAttackType) {&lt;br /&gt;
    if (isCharacterSelected(characterPseudo, battleChoice.attacker.selected)) {&lt;br /&gt;
      filterAttackTypeSelectionCharacter(&lt;br /&gt;
        characterDataObject,&lt;br /&gt;
        battleChoice.attackType&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
    battleChoice.resetAttackType = false;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveButtonGreen(saveButton) {&lt;br /&gt;
  saveButton.classList.remove(&amp;quot;unsaved-character&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveButtonOrange(saveButton) {&lt;br /&gt;
  saveButton.classList.add(&amp;quot;unsaved-character&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function characterCreationListener(characters, battle) {&lt;br /&gt;
  var { characterCreation, saveButton, weaponCategory } = characters;&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;submit&amp;quot;, handleSubmitForm);&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;invalid&amp;quot;, handleInvalidInput, true);&lt;br /&gt;
  document.addEventListener(&amp;quot;keydown&amp;quot;, handleSaveShortcut);&lt;br /&gt;
  weaponCategory.addEventListener(&amp;quot;mouseover&amp;quot;, handleTooltipOverflow);&lt;br /&gt;
&lt;br /&gt;
  function handleSubmitForm(event) {&lt;br /&gt;
    event.preventDefault();&lt;br /&gt;
&lt;br /&gt;
    if (characters.unsavedChanges) {&lt;br /&gt;
      saveCharacter(characters.savedCharacters, characterCreation, battle);&lt;br /&gt;
      saveButtonGreen(saveButton);&lt;br /&gt;
      characters.unsavedChanges = false;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function handleInvalidInput(event) {&lt;br /&gt;
    var target = event.target;&lt;br /&gt;
&lt;br /&gt;
    if (target.checkVisibility()) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var autoCorrectInput = target.closest(&amp;quot;.auto-correct-input&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      autoCorrectInput &amp;amp;&amp;amp;&lt;br /&gt;
      autoCorrectInput.classList.contains(&amp;quot;tabber-noactive&amp;quot;)&lt;br /&gt;
    ) {&lt;br /&gt;
      target.value = target.defaultValue;&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    openTargetTab(target);&lt;br /&gt;
    openTargetCollapsible(target);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function handleSaveShortcut(event) {&lt;br /&gt;
    if (event.ctrlKey &amp;amp;&amp;amp; event.key === &amp;quot;s&amp;quot;) {&lt;br /&gt;
      event.preventDefault();&lt;br /&gt;
      saveButton.click();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function handleTooltipOverflow(event) {&lt;br /&gt;
    var label = event.target.closest(&amp;quot;label&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (label) {&lt;br /&gt;
      var tooltip = label.lastChild;&lt;br /&gt;
&lt;br /&gt;
      if (tooltip.classList.contains(&amp;quot;popContenu&amp;quot;)) {&lt;br /&gt;
        var tooltipRect = tooltip.getBoundingClientRect();&lt;br /&gt;
        var modalRect = weaponCategory.getBoundingClientRect();&lt;br /&gt;
&lt;br /&gt;
        if (tooltipRect.right &amp;gt; modalRect.right) {&lt;br /&gt;
          tooltip.style.left = &amp;quot;-100%&amp;quot;;&lt;br /&gt;
        } else if (tooltipRect.left &amp;lt; modalRect.left) {&lt;br /&gt;
          tooltip.style.left = &amp;quot;200%&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function downloadData(content, type, filename) {&lt;br /&gt;
  var link = document.createElement(&amp;quot;a&amp;quot;);&lt;br /&gt;
  var blob = new Blob([content], { type: type });&lt;br /&gt;
  var blobURL = URL.createObjectURL(blob);&lt;br /&gt;
&lt;br /&gt;
  link.href = blobURL;&lt;br /&gt;
  link.download = filename;&lt;br /&gt;
  document.body.appendChild(link);&lt;br /&gt;
&lt;br /&gt;
  link.click();&lt;br /&gt;
  document.body.removeChild(link);&lt;br /&gt;
  URL.revokeObjectURL(blobURL);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function uploadCharacter(&lt;br /&gt;
  selectedFiles,&lt;br /&gt;
  characters,&lt;br /&gt;
  characterTemplate,&lt;br /&gt;
  charactersContainer,&lt;br /&gt;
  battle&lt;br /&gt;
) {&lt;br /&gt;
  var selectFilesLength = selectedFiles.length;&lt;br /&gt;
  var defaultPseudo = characters.defaultText.pseudo;&lt;br /&gt;
&lt;br /&gt;
  for (var fileIndex = 0; fileIndex &amp;lt; selectFilesLength; fileIndex++) {&lt;br /&gt;
    var selectedFile = selectedFiles[fileIndex];&lt;br /&gt;
&lt;br /&gt;
    if (selectedFile.type === &amp;quot;text/plain&amp;quot;) {&lt;br /&gt;
      var reader = new FileReader();&lt;br /&gt;
      reader.onload = function (e) {&lt;br /&gt;
        var fileContent = e.target.result;&lt;br /&gt;
        try {&lt;br /&gt;
          var characterDataObject = JSON.parse(fileContent);&lt;br /&gt;
&lt;br /&gt;
          if (characterDataObject.hasOwnProperty(&amp;quot;name&amp;quot;)) {&lt;br /&gt;
            var characterPseudo = String(characterDataObject.name);&lt;br /&gt;
&lt;br /&gt;
            hideElement(characters.characterCreation);&lt;br /&gt;
            characterPseudo = validPseudo(characterPseudo, defaultPseudo);&lt;br /&gt;
&lt;br /&gt;
            [characterDataObject, characterPseudo] = addUniquePseudo(&lt;br /&gt;
              characterDataObject,&lt;br /&gt;
              Object.keys(characters.savedCharacters)&lt;br /&gt;
            );&lt;br /&gt;
            var selectedCharacter = handleNewCharacter(&lt;br /&gt;
              characters,&lt;br /&gt;
              characterTemplate,&lt;br /&gt;
              charactersContainer,&lt;br /&gt;
              battle,&lt;br /&gt;
              characterPseudo&lt;br /&gt;
            )[0];&lt;br /&gt;
&lt;br /&gt;
            if (selectFilesLength === 1) {&lt;br /&gt;
              updateForm(&lt;br /&gt;
                characterDataObject,&lt;br /&gt;
                characters.characterCreation,&lt;br /&gt;
                characters,&lt;br /&gt;
                selectedCharacter,&lt;br /&gt;
                battle&lt;br /&gt;
              );&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            saveCharacter(&lt;br /&gt;
              characters.savedCharacters,&lt;br /&gt;
              characters.characterCreation,&lt;br /&gt;
              battle,&lt;br /&gt;
              true,&lt;br /&gt;
              characterDataObject&lt;br /&gt;
            );&lt;br /&gt;
          }&lt;br /&gt;
        } catch (error) {&lt;br /&gt;
          console.warn(error);&lt;br /&gt;
          if (error.name === &amp;quot;TypeError&amp;quot;) {&lt;br /&gt;
            // delete the character&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
      };&lt;br /&gt;
      reader.readAsText(selectedFile);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleUploadCharacter(&lt;br /&gt;
  characters,&lt;br /&gt;
  characterTemplate,&lt;br /&gt;
  charactersContainer,&lt;br /&gt;
  battle&lt;br /&gt;
) {&lt;br /&gt;
  var characterInput = characters.characterInput;&lt;br /&gt;
  var dropZone = characters.dropZone;&lt;br /&gt;
&lt;br /&gt;
  characterInput.accept = &amp;quot;.txt&amp;quot;;&lt;br /&gt;
  characterInput.multiple = true;&lt;br /&gt;
  dropZone.setAttribute(&amp;quot;tabindex&amp;quot;, &amp;quot;0&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  dropZone.addEventListener(&amp;quot;click&amp;quot;, function () {&lt;br /&gt;
    characterInput.click();&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  dropZone.addEventListener(&amp;quot;dragover&amp;quot;, function (event) {&lt;br /&gt;
    event.preventDefault();&lt;br /&gt;
    dropZone.classList.add(&amp;quot;drop-zone--dragover&amp;quot;);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  [&amp;quot;dragleave&amp;quot;, &amp;quot;dragend&amp;quot;].forEach(function (type) {&lt;br /&gt;
    dropZone.addEventListener(type, function () {&lt;br /&gt;
      dropZone.classList.remove(&amp;quot;drop-zone--dragover&amp;quot;);&lt;br /&gt;
    });&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  dropZone.addEventListener(&amp;quot;drop&amp;quot;, function (event) {&lt;br /&gt;
    event.preventDefault();&lt;br /&gt;
    uploadCharacter(&lt;br /&gt;
      event.dataTransfer.files,&lt;br /&gt;
      characters,&lt;br /&gt;
      characterTemplate,&lt;br /&gt;
      charactersContainer,&lt;br /&gt;
      battle&lt;br /&gt;
    );&lt;br /&gt;
    dropZone.classList.remove(&amp;quot;drop-zone--dragover&amp;quot;);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  characterInput.addEventListener(&amp;quot;change&amp;quot;, function (event) {&lt;br /&gt;
    uploadCharacter(&lt;br /&gt;
      event.target.files,&lt;br /&gt;
      characters,&lt;br /&gt;
      characterTemplate,&lt;br /&gt;
      charactersContainer,&lt;br /&gt;
      battle&lt;br /&gt;
    );&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function deleteCharacter(characters, pseudo, element, battle) {&lt;br /&gt;
  delete characters.savedCharacters[pseudo];&lt;br /&gt;
  element.remove();&lt;br /&gt;
&lt;br /&gt;
  updateSavedCharacters(characters.savedCharacters);&lt;br /&gt;
  removeBattleChoice(battle.battleChoice, pseudo, &amp;quot;character&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (&lt;br /&gt;
    !Object.keys(characters.savedCharacters).length ||&lt;br /&gt;
    characters.characterCreation.name.value === pseudo&lt;br /&gt;
  ) {&lt;br /&gt;
    saveButtonGreen(characters.saveButton);&lt;br /&gt;
    characters.unsavedChanges = false;&lt;br /&gt;
    hideElement(characters.characterCreation);&lt;br /&gt;
    showElement(characters.characterCreation.previousElementSibling);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function deleteMonster(characters, battle, monsterVnum) {&lt;br /&gt;
  var monsterElements = characters.monsterElements;&lt;br /&gt;
  var monsterType = characters.savedMonsters[monsterVnum].category;&lt;br /&gt;
&lt;br /&gt;
  if (monsterElements.hasOwnProperty(monsterVnum)) {&lt;br /&gt;
    monsterElements[monsterVnum].remove();&lt;br /&gt;
    delete monsterElements[monsterVnum];&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  delete characters.savedMonsters[monsterVnum];&lt;br /&gt;
&lt;br /&gt;
  updateSavedMonsters(characters.savedMonsters);&lt;br /&gt;
  removeBattleChoice(battle.battleChoice, monsterVnum, monsterType);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleStyle(characters, selectedElement) {&lt;br /&gt;
  var currentCharacter = characters.currentCharacter;&lt;br /&gt;
&lt;br /&gt;
  if (currentCharacter) {&lt;br /&gt;
    currentCharacter.classList.remove(&amp;quot;selected-character&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  selectedElement.classList.add(&amp;quot;selected-character&amp;quot;);&lt;br /&gt;
  characters.currentCharacter = selectedElement;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateForm(&lt;br /&gt;
  formData,&lt;br /&gt;
  characterCreation,&lt;br /&gt;
  characters,&lt;br /&gt;
  selectedElement,&lt;br /&gt;
  battle&lt;br /&gt;
) {&lt;br /&gt;
  saveButtonGreen(characters.saveButton);&lt;br /&gt;
  hideElement(characterCreation.previousElementSibling);&lt;br /&gt;
  showElement(characterCreation);&lt;br /&gt;
  handleStyle(characters, selectedElement);&lt;br /&gt;
&lt;br /&gt;
  characterCreation.reset();&lt;br /&gt;
&lt;br /&gt;
  for (var [name, value] of Object.entries(formData)) {&lt;br /&gt;
    var formElement = characterCreation[name];&lt;br /&gt;
&lt;br /&gt;
    if (!formElement) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (formElement.type === &amp;quot;checkbox&amp;quot;) {&lt;br /&gt;
      if (isChecked(value)) {&lt;br /&gt;
        formElement.checked = true;&lt;br /&gt;
      }&lt;br /&gt;
    } else {&lt;br /&gt;
      formElement.value = value;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  var selectedRace = characterCreation.race.value;&lt;br /&gt;
  var classChoice = characterCreation.class;&lt;br /&gt;
  var weaponElement = characterCreation.weapon;&lt;br /&gt;
&lt;br /&gt;
  filterClass(selectedRace, classChoice, true);&lt;br /&gt;
  filterWeapon(&lt;br /&gt;
    selectedRace,&lt;br /&gt;
    weaponElement,&lt;br /&gt;
    characters.weaponCategory,&lt;br /&gt;
    battle.constants.allowedWeaponsPerRace,&lt;br /&gt;
    true&lt;br /&gt;
  );&lt;br /&gt;
  handlePolymorphDisplay(&lt;br /&gt;
    characters,&lt;br /&gt;
    characterCreation.polymorphMonster.value,&lt;br /&gt;
    characterCreation.polymorphMonsterImage.value&lt;br /&gt;
  );&lt;br /&gt;
  handleWeaponDisplay(&lt;br /&gt;
    characters.weaponCategory,&lt;br /&gt;
    characters.weaponDisplay,&lt;br /&gt;
    weaponElement.value&lt;br /&gt;
  );&lt;br /&gt;
  filterUpgrade(&lt;br /&gt;
    characterCreation.weaponUpgrade,&lt;br /&gt;
    weaponElement.value,&lt;br /&gt;
    characters.randomAttackValue,&lt;br /&gt;
    characters.randomMagicAttackValue&lt;br /&gt;
  );&lt;br /&gt;
  for (var [targetName, sibling] of Object.entries(characters.toggleSiblings)) {&lt;br /&gt;
    filterCheckbox(characterCreation[targetName], sibling);&lt;br /&gt;
  }&lt;br /&gt;
  filterSkills(classChoice.value, characters.skillElementsToFilter);&lt;br /&gt;
  handleBonusVariationUpdate(characterCreation, characters.bonusVariation);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleClickOnCharacter(&lt;br /&gt;
  spanInput,&lt;br /&gt;
  target,&lt;br /&gt;
  characters,&lt;br /&gt;
  characterElement,&lt;br /&gt;
  battle,&lt;br /&gt;
  edition&lt;br /&gt;
) {&lt;br /&gt;
  var displayedPseudo = characters.characterCreation.name.value;&lt;br /&gt;
  var pseudo = spanInput.dataset.name;&lt;br /&gt;
  var { unsavedWarning, deleteWarning } = characters.defaultText;&lt;br /&gt;
&lt;br /&gt;
  if (edition) {&lt;br /&gt;
    if (!characters.unsavedChanges) {&lt;br /&gt;
      updateForm(&lt;br /&gt;
        characters.savedCharacters[pseudo],&lt;br /&gt;
        characters.characterCreation,&lt;br /&gt;
        characters,&lt;br /&gt;
        characterElement,&lt;br /&gt;
        battle&lt;br /&gt;
      );&lt;br /&gt;
    } else if (displayedPseudo === pseudo) {&lt;br /&gt;
      // pass&lt;br /&gt;
    } else {&lt;br /&gt;
      var result = confirm(unsavedWarning);&lt;br /&gt;
&lt;br /&gt;
      if (result) {&lt;br /&gt;
        updateForm(&lt;br /&gt;
          characters.savedCharacters[pseudo],&lt;br /&gt;
          characters.characterCreation,&lt;br /&gt;
          characters,&lt;br /&gt;
          characterElement,&lt;br /&gt;
          battle&lt;br /&gt;
        );&lt;br /&gt;
        characters.unsavedChanges = false;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    if (target.tagName === &amp;quot;path&amp;quot;) {&lt;br /&gt;
      target = target.parentElement;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    switch (target.dataset.icon) {&lt;br /&gt;
      case &amp;quot;duplicate&amp;quot;:&lt;br /&gt;
        if (!characters.unsavedChanges) {&lt;br /&gt;
          addNewCharacter(&lt;br /&gt;
            characters,&lt;br /&gt;
            characters.newCharacterTemplate,&lt;br /&gt;
            characters.charactersContainer,&lt;br /&gt;
            battle,&lt;br /&gt;
            pseudo&lt;br /&gt;
          );&lt;br /&gt;
        } else {&lt;br /&gt;
          var result = confirm(unsavedWarning);&lt;br /&gt;
&lt;br /&gt;
          if (result) {&lt;br /&gt;
            addNewCharacter(&lt;br /&gt;
              characters,&lt;br /&gt;
              characters.newCharacterTemplate,&lt;br /&gt;
              characters.charactersContainer,&lt;br /&gt;
              battle,&lt;br /&gt;
              pseudo&lt;br /&gt;
            );&lt;br /&gt;
            saveButtonGreen(characters.saveButton);&lt;br /&gt;
            characters.unsavedChanges = false;&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
        break;&lt;br /&gt;
&lt;br /&gt;
      case &amp;quot;download&amp;quot;:&lt;br /&gt;
        var character = characters.savedCharacters[pseudo];&lt;br /&gt;
        downloadData(&lt;br /&gt;
          JSON.stringify(character),&lt;br /&gt;
          &amp;quot;text/plain&amp;quot;,&lt;br /&gt;
          character.name + &amp;quot;.txt&amp;quot;&lt;br /&gt;
        );&lt;br /&gt;
        break;&lt;br /&gt;
&lt;br /&gt;
      case &amp;quot;delete&amp;quot;:&lt;br /&gt;
        var result = confirm(deleteWarning.replace(&amp;quot;[[]]&amp;quot;, pseudo));&lt;br /&gt;
        if (result) {&lt;br /&gt;
          deleteCharacter(characters, pseudo, characterElement, battle);&lt;br /&gt;
        }&lt;br /&gt;
        break;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleNewCharacter(&lt;br /&gt;
  characters,&lt;br /&gt;
  characterTemplate,&lt;br /&gt;
  charactersContainer,&lt;br /&gt;
  battle,&lt;br /&gt;
  pseudo&lt;br /&gt;
) {&lt;br /&gt;
  var newCharacterTemplate = characterTemplate.cloneNode(true);&lt;br /&gt;
  var spanInput = newCharacterTemplate.querySelector(&amp;quot;span.input&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  newCharacterTemplate.setAttribute(&amp;quot;tabindex&amp;quot;, &amp;quot;0&amp;quot;);&lt;br /&gt;
  charactersContainer.appendChild(newCharacterTemplate);&lt;br /&gt;
&lt;br /&gt;
  if (pseudo) {&lt;br /&gt;
    spanInput.textContent = pseudo;&lt;br /&gt;
    spanInput.setAttribute(&amp;quot;data-name&amp;quot;, pseudo);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  newCharacterTemplate.addEventListener(&amp;quot;click&amp;quot;, function (event) {&lt;br /&gt;
    var target = event.target;&lt;br /&gt;
&lt;br /&gt;
    if (target.tagName === &amp;quot;path&amp;quot; || target.tagName === &amp;quot;svg&amp;quot;) {&lt;br /&gt;
      handleClickOnCharacter(&lt;br /&gt;
        spanInput,&lt;br /&gt;
        target,&lt;br /&gt;
        characters,&lt;br /&gt;
        newCharacterTemplate,&lt;br /&gt;
        battle&lt;br /&gt;
      );&lt;br /&gt;
    } else {&lt;br /&gt;
      handleClickOnCharacter(&lt;br /&gt;
        spanInput,&lt;br /&gt;
        null,&lt;br /&gt;
        characters,&lt;br /&gt;
        newCharacterTemplate,&lt;br /&gt;
        battle,&lt;br /&gt;
        true&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  newCharacterTemplate.addEventListener(&amp;quot;keydown&amp;quot;, function (event) {&lt;br /&gt;
    if (event.keyCode === 13) {&lt;br /&gt;
      event.target.click();&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  return [newCharacterTemplate, spanInput];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function validPseudo(pseudo, defaultPseudo) {&lt;br /&gt;
  var newPseudo = pseudoFormat(pseudo);&lt;br /&gt;
&lt;br /&gt;
  if (!newPseudo) {&lt;br /&gt;
    return pseudoFormat(defaultPseudo);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return newPseudo;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addNewCharacter(&lt;br /&gt;
  characters,&lt;br /&gt;
  characterTemplate,&lt;br /&gt;
  charactersContainer,&lt;br /&gt;
  battle,&lt;br /&gt;
  pseudoToDuplicate&lt;br /&gt;
) {&lt;br /&gt;
  function editAndSetCharacterPseudoInput(selectedCharacter, spanInput) {&lt;br /&gt;
    var maxPseudoLength = 20;&lt;br /&gt;
    var defaultPseudo = characters.defaultText.pseudo;&lt;br /&gt;
&lt;br /&gt;
    var selection = window.getSelection();&lt;br /&gt;
    var range = document.createRange();&lt;br /&gt;
&lt;br /&gt;
    if (pseudoToDuplicate) {&lt;br /&gt;
      spanInput.textContent = pseudoToDuplicate;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    spanInput.contentEditable = true;&lt;br /&gt;
    spanInput.focus();&lt;br /&gt;
    range.selectNodeContents(spanInput);&lt;br /&gt;
    selection.removeAllRanges();&lt;br /&gt;
    selection.addRange(range);&lt;br /&gt;
&lt;br /&gt;
    function pseudoValidation() {&lt;br /&gt;
      var characterPseudo = validPseudo(spanInput.textContent, defaultPseudo);&lt;br /&gt;
      var characterDataObject = { name: characterPseudo };&lt;br /&gt;
&lt;br /&gt;
      if (pseudoToDuplicate) {&lt;br /&gt;
        characterDataObject = copyObject(&lt;br /&gt;
          characters.savedCharacters[pseudoToDuplicate]&lt;br /&gt;
        );&lt;br /&gt;
        characterDataObject.name = characterPseudo;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      [characterDataObject, characterPseudo] = addUniquePseudo(&lt;br /&gt;
        characterDataObject,&lt;br /&gt;
        Object.keys(characters.savedCharacters)&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      selection.removeAllRanges();&lt;br /&gt;
      spanInput.contentEditable = false;&lt;br /&gt;
      spanInput.textContent = characterPseudo;&lt;br /&gt;
      spanInput.setAttribute(&amp;quot;data-name&amp;quot;, characterPseudo);&lt;br /&gt;
&lt;br /&gt;
      updateForm(&lt;br /&gt;
        characterDataObject,&lt;br /&gt;
        characters.characterCreation,&lt;br /&gt;
        characters,&lt;br /&gt;
        selectedCharacter,&lt;br /&gt;
        battle&lt;br /&gt;
      );&lt;br /&gt;
      saveCharacter(&lt;br /&gt;
        characters.savedCharacters,&lt;br /&gt;
        characters.characterCreation,&lt;br /&gt;
        battle,&lt;br /&gt;
        true&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handleMaxLength(event) {&lt;br /&gt;
      if (spanInput.textContent.length &amp;gt; maxPseudoLength) {&lt;br /&gt;
        spanInput.textContent = spanInput.textContent.slice(0, maxPseudoLength);&lt;br /&gt;
        range.setStart(spanInput.childNodes[0], maxPseudoLength);&lt;br /&gt;
        selection.removeAllRanges();&lt;br /&gt;
        selection.addRange(range);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handleBlur() {&lt;br /&gt;
      spanInput.removeEventListener(&amp;quot;blur&amp;quot;, handleBlur);&lt;br /&gt;
      spanInput.removeEventListener(&amp;quot;input&amp;quot;, handleMaxLength);&lt;br /&gt;
      pseudoValidation();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handleKeyDown(event) {&lt;br /&gt;
      if (event.key === &amp;quot;Enter&amp;quot;) {&lt;br /&gt;
        event.preventDefault();&lt;br /&gt;
&lt;br /&gt;
        spanInput.removeEventListener(&amp;quot;keydown&amp;quot;, handleKeyDown);&lt;br /&gt;
        spanInput.removeEventListener(&amp;quot;blur&amp;quot;, handleBlur);&lt;br /&gt;
        spanInput.removeEventListener(&amp;quot;input&amp;quot;, handleMaxLength);&lt;br /&gt;
&lt;br /&gt;
        pseudoValidation();&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    spanInput.addEventListener(&amp;quot;input&amp;quot;, handleMaxLength);&lt;br /&gt;
    spanInput.addEventListener(&amp;quot;keydown&amp;quot;, handleKeyDown);&lt;br /&gt;
    spanInput.addEventListener(&amp;quot;blur&amp;quot;, handleBlur);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  hideElement(characters.characterCreation);&lt;br /&gt;
  var [selectedCharacter, spanInput] = handleNewCharacter(&lt;br /&gt;
    characters,&lt;br /&gt;
    characterTemplate,&lt;br /&gt;
    charactersContainer,&lt;br /&gt;
    battle&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  editAndSetCharacterPseudoInput(selectedCharacter, spanInput);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleFocus() {&lt;br /&gt;
  var tooltipLinks = document.querySelectorAll(&amp;quot;div.tooltip a&amp;quot;);&lt;br /&gt;
  tooltipLinks.forEach(function (link) {&lt;br /&gt;
    link.setAttribute(&amp;quot;tabindex&amp;quot;, -1);&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function resetBonusVariation(bonusVariation) {&lt;br /&gt;
  function resetInput(input) {&lt;br /&gt;
    input.removeAttribute(&amp;quot;min&amp;quot;);&lt;br /&gt;
    input.removeAttribute(&amp;quot;max&amp;quot;);&lt;br /&gt;
    input.defaultValue = 0;&lt;br /&gt;
    input.value = input.defaultValue;&lt;br /&gt;
  }&lt;br /&gt;
  var { minValue, maxValue, checkbox, container, disabledText, selectedText } =&lt;br /&gt;
    bonusVariation;&lt;br /&gt;
&lt;br /&gt;
  resetInput(minValue);&lt;br /&gt;
  resetInput(maxValue);&lt;br /&gt;
  showElement(disabledText);&lt;br /&gt;
  hideElement(selectedText);&lt;br /&gt;
  hideElement(container);&lt;br /&gt;
  checkbox.checked = false;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleBonusVariationUpdate(&lt;br /&gt;
  characterCreation,&lt;br /&gt;
  bonusVariation,&lt;br /&gt;
  resetSkill&lt;br /&gt;
) {&lt;br /&gt;
  var selectedBonus = characterCreation.bonusVariation.value;&lt;br /&gt;
  var displayName = characterCreation.bonusVariationName.value;&lt;br /&gt;
&lt;br /&gt;
  if (&lt;br /&gt;
    resetSkill &amp;amp;&amp;amp;&lt;br /&gt;
    (selectedBonus.startsWith(&amp;quot;attackSkill&amp;quot;) ||&lt;br /&gt;
      selectedBonus.startsWith(&amp;quot;horseSkill&amp;quot;) ||&lt;br /&gt;
      selectedBonus.startsWith(&amp;quot;skillBonus&amp;quot;))&lt;br /&gt;
  ) {&lt;br /&gt;
    resetBonusVariation(bonusVariation);&lt;br /&gt;
    return;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (&lt;br /&gt;
    characterCreation.hasOwnProperty(selectedBonus) &amp;amp;&amp;amp;&lt;br /&gt;
    selectedBonus != 0 &amp;amp;&amp;amp;&lt;br /&gt;
    displayName != 0&lt;br /&gt;
  ) {&lt;br /&gt;
    handleBonusVariation(&lt;br /&gt;
      characterCreation[selectedBonus],&lt;br /&gt;
      bonusVariation,&lt;br /&gt;
      displayName&lt;br /&gt;
    );&lt;br /&gt;
  } else {&lt;br /&gt;
    resetBonusVariation(bonusVariation);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getTargetContent(targetParent, targetName, isSkill) {&lt;br /&gt;
  var targetContent = &amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  if (targetParent.children.length &amp;lt;= 1) {&lt;br /&gt;
    targetContent = targetParent.textContent;&lt;br /&gt;
  } else if (targetName === &amp;quot;weaponUpgrade&amp;quot;) {&lt;br /&gt;
    targetContent = targetParent.children[1].textContent;&lt;br /&gt;
  } else if (targetName === &amp;quot;level&amp;quot;) {&lt;br /&gt;
    targetContent = targetParent.textContent.replace(&amp;quot;Lv&amp;quot;, &amp;quot;&amp;quot;).trim();&lt;br /&gt;
  } else if (isSkill) {&lt;br /&gt;
    var container = targetParent.children[1];&lt;br /&gt;
&lt;br /&gt;
    for (var index = 0; index &amp;lt; container.children.length; index++) {&lt;br /&gt;
      var element = container.children[index];&lt;br /&gt;
&lt;br /&gt;
      if (element.checkVisibility()) {&lt;br /&gt;
        targetContent += element.textContent;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    for (var index = 1; index &amp;lt; targetParent.children.length; index++) {&lt;br /&gt;
      var element = targetParent.children[index];&lt;br /&gt;
&lt;br /&gt;
      if (element.checkVisibility()) {&lt;br /&gt;
        targetContent += element.textContent;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return targetContent.trim();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleBonusVariation(target, bonusVariation, displayName) {&lt;br /&gt;
  var {&lt;br /&gt;
    minValue,&lt;br /&gt;
    maxValue,&lt;br /&gt;
    checkbox,&lt;br /&gt;
    container,&lt;br /&gt;
    disabledText,&lt;br /&gt;
    selectedText,&lt;br /&gt;
    displaySpan,&lt;br /&gt;
  } = bonusVariation;&lt;br /&gt;
&lt;br /&gt;
  var {&lt;br /&gt;
    min: targetMin,&lt;br /&gt;
    max: targetMax,&lt;br /&gt;
    name: targetName,&lt;br /&gt;
    value: targetValue,&lt;br /&gt;
    parentElement: targetParent,&lt;br /&gt;
    tagName,&lt;br /&gt;
  } = target;&lt;br /&gt;
&lt;br /&gt;
  targetMin = Number(targetMin);&lt;br /&gt;
  targetMax = Number(targetMax);&lt;br /&gt;
  targetValue = Number(targetValue);&lt;br /&gt;
&lt;br /&gt;
  var isSkill = tagName === &amp;quot;SELECT&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  if (isSkill) {&lt;br /&gt;
    var options = target.options;&lt;br /&gt;
&lt;br /&gt;
    targetMin = options[0].value;&lt;br /&gt;
    targetMax = options[options.length - 1].value;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  minValue.min = targetMin;&lt;br /&gt;
  minValue.max = targetMax;&lt;br /&gt;
  minValue.defaultValue = targetMin;&lt;br /&gt;
&lt;br /&gt;
  maxValue.min = targetMin;&lt;br /&gt;
  maxValue.max = targetMax;&lt;br /&gt;
  maxValue.defaultValue = targetMin;&lt;br /&gt;
&lt;br /&gt;
  hideElement(disabledText);&lt;br /&gt;
  showElement(selectedText);&lt;br /&gt;
&lt;br /&gt;
  if (displayName) {&lt;br /&gt;
    minValue.value = Math.min(Math.max(minValue.value, targetMin), targetMax);&lt;br /&gt;
    maxValue.value = Math.max(Math.min(maxValue.value, targetMax), targetMin);&lt;br /&gt;
&lt;br /&gt;
    displaySpan.textContent = displayName;&lt;br /&gt;
  } else {&lt;br /&gt;
    var { input, inputName, tabButton } = bonusVariation;&lt;br /&gt;
    var targetContent = getTargetContent(targetParent, targetName, isSkill);&lt;br /&gt;
&lt;br /&gt;
    input.value = targetName;&lt;br /&gt;
    inputName.value = targetContent;&lt;br /&gt;
    displaySpan.textContent = targetContent;&lt;br /&gt;
&lt;br /&gt;
    minValue.value = Math.max(targetValue - 10, targetMin);&lt;br /&gt;
    maxValue.value = Math.min(targetValue + 10, targetMax);&lt;br /&gt;
&lt;br /&gt;
    showElement(container);&lt;br /&gt;
    checkbox.checked = true;&lt;br /&gt;
&lt;br /&gt;
    tabButton.click();&lt;br /&gt;
    tabButton.scrollIntoView(true);&lt;br /&gt;
&lt;br /&gt;
    input.dispatchEvent(newChangeEvent());&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function characterManagement(characters, battle) {&lt;br /&gt;
  var {&lt;br /&gt;
    newCharacterTemplate: characterTemplate,&lt;br /&gt;
    charactersContainer,&lt;br /&gt;
    addNewCharacterButton,&lt;br /&gt;
    saveButton,&lt;br /&gt;
    characterCreation,&lt;br /&gt;
    bonusVariation,&lt;br /&gt;
    defaultText: { unsavedWarning },&lt;br /&gt;
  } = characters;&lt;br /&gt;
&lt;br /&gt;
  Object.keys(characters.savedCharacters).forEach(function (pseudo) {&lt;br /&gt;
    handleNewCharacter(&lt;br /&gt;
      characters,&lt;br /&gt;
      characterTemplate,&lt;br /&gt;
      charactersContainer,&lt;br /&gt;
      battle,&lt;br /&gt;
      pseudo&lt;br /&gt;
    );&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  addNewCharacterButton.addEventListener(&amp;quot;click&amp;quot;, function (event) {&lt;br /&gt;
    if (!characters.unsavedChanges) {&lt;br /&gt;
      addNewCharacter(&lt;br /&gt;
        characters,&lt;br /&gt;
        characterTemplate,&lt;br /&gt;
        charactersContainer,&lt;br /&gt;
        battle&lt;br /&gt;
      );&lt;br /&gt;
    } else {&lt;br /&gt;
      var result = confirm(unsavedWarning);&lt;br /&gt;
&lt;br /&gt;
      if (result) {&lt;br /&gt;
        addNewCharacter(&lt;br /&gt;
          characters,&lt;br /&gt;
          characterTemplate,&lt;br /&gt;
          charactersContainer,&lt;br /&gt;
          battle&lt;br /&gt;
        );&lt;br /&gt;
        saveButtonGreen(saveButton);&lt;br /&gt;
        characters.unsavedChanges = false;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  handleUploadCharacter(&lt;br /&gt;
    characters,&lt;br /&gt;
    characterTemplate,&lt;br /&gt;
    charactersContainer,&lt;br /&gt;
    battle&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  function handleLongPress(target) {&lt;br /&gt;
    if (target.tagName !== &amp;quot;INPUT&amp;quot; &amp;amp;&amp;amp; target.tagName !== &amp;quot;SELECT&amp;quot;) {&lt;br /&gt;
      target = target.querySelector(&amp;quot;input&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      !target ||&lt;br /&gt;
      (target.type !== &amp;quot;number&amp;quot; &amp;amp;&amp;amp;&lt;br /&gt;
        !target.classList.contains(&amp;quot;skill-select&amp;quot;) &amp;amp;&amp;amp;&lt;br /&gt;
        target.name !== &amp;quot;weaponUpgrade&amp;quot;) ||&lt;br /&gt;
      target.classList.contains(&amp;quot;disabled-variation&amp;quot;)&lt;br /&gt;
    ) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    handleBonusVariation(target, bonusVariation, null);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;click&amp;quot;, function (event) {&lt;br /&gt;
    if (event.shiftKey || event.ctrlKey) {&lt;br /&gt;
      handleLongPress(event.target);&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  var longPressTimer;&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;touchstart&amp;quot;, function (event) {&lt;br /&gt;
    longPressTimer = setTimeout(function () {&lt;br /&gt;
      handleLongPress(event.target);&lt;br /&gt;
    }, 800);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;touchend&amp;quot;, function () {&lt;br /&gt;
    clearTimeout(longPressTimer);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;touchmove&amp;quot;, function () {&lt;br /&gt;
    clearTimeout(longPressTimer);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  filterForm(characters, battle);&lt;br /&gt;
  characterCreationListener(characters, battle);&lt;br /&gt;
  handleFocus();&lt;br /&gt;
&lt;br /&gt;
  window.addEventListener(&amp;quot;beforeunload&amp;quot;, function (event) {&lt;br /&gt;
    if (characters.unsavedChanges) {&lt;br /&gt;
      event.preventDefault();&lt;br /&gt;
      return &amp;quot;&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addMonsterElement(characters, battle, monsterVnum, iframeInfo) {&lt;br /&gt;
  var { monsterTemplate, monstersContainer } = characters;&lt;br /&gt;
  var monsterElement = monsterTemplate.cloneNode(true);&lt;br /&gt;
  var spanInput = monsterElement.querySelector(&amp;quot;span.input&amp;quot;);&lt;br /&gt;
  var deleteSvg = monsterElement.querySelector(&amp;quot;svg&amp;quot;);&lt;br /&gt;
  var monsterName = getMonsterName(monsterVnum);&lt;br /&gt;
  var displayName = characters.translateMonsters&lt;br /&gt;
    ? getTranslatedMonsterName(monsterVnum)&lt;br /&gt;
    : monsterName;&lt;br /&gt;
  var link = createWikiLink(monsterName, displayName);&lt;br /&gt;
&lt;br /&gt;
  monsterElement.setAttribute(&amp;quot;tabindex&amp;quot;, &amp;quot;0&amp;quot;);&lt;br /&gt;
  spanInput.appendChild(link);&lt;br /&gt;
  monstersContainer.appendChild(monsterElement);&lt;br /&gt;
  characters.monsterElements[monsterVnum] = monsterElement;&lt;br /&gt;
&lt;br /&gt;
  deleteSvg.addEventListener(&amp;quot;click&amp;quot;, function () {&lt;br /&gt;
    var monster = characters.savedMonsters[monsterVnum];&lt;br /&gt;
    iframeInfo[monster.category].shouldBeUpdated = true;&lt;br /&gt;
&lt;br /&gt;
    deleteMonster(characters, battle, monsterVnum);&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addNewMonster(&lt;br /&gt;
  characters,&lt;br /&gt;
  battle,&lt;br /&gt;
  monsterVnum,&lt;br /&gt;
  monsterImage,&lt;br /&gt;
  iframeInfo,&lt;br /&gt;
  category&lt;br /&gt;
) {&lt;br /&gt;
  if (isValueInArray(monsterVnum, Object.keys(characters.savedMonsters)))&lt;br /&gt;
    return;&lt;br /&gt;
&lt;br /&gt;
  var newMonster = {&lt;br /&gt;
    image: monsterImage,&lt;br /&gt;
    category: category,&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  characters.savedMonsters[monsterVnum] = newMonster;&lt;br /&gt;
&lt;br /&gt;
  addMonsterElement(characters, battle, monsterVnum, iframeInfo);&lt;br /&gt;
  updateSavedMonsters(characters.savedMonsters);&lt;br /&gt;
  addBattleChoice(battle.battleChoice, monsterVnum, newMonster, true);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function translateiFrameElements(iframeDoc, category) {&lt;br /&gt;
  const filterName = iframeDoc.getElementById(&amp;quot;filter-name&amp;quot;);&lt;br /&gt;
  const { general, special } = translation;&lt;br /&gt;
  const translatedPlaceholder = special.placeholder;&lt;br /&gt;
&lt;br /&gt;
  if (filterName &amp;amp;&amp;amp; translatedPlaceholder) {&lt;br /&gt;
    filterName.placeholder = translatedPlaceholder;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (const element of iframeDoc.querySelectorAll(&amp;quot;[data-t]&amp;quot;)) {&lt;br /&gt;
    const translateText = general[element.dataset.t];&lt;br /&gt;
&lt;br /&gt;
    if (translateText) {&lt;br /&gt;
      element.textContent = translateText;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function translateiFrame(iframeDoc, category) {&lt;br /&gt;
  const filterForm = iframeDoc.getElementById(&amp;quot;filter-form&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (filterForm) {&lt;br /&gt;
    translateiFrameElements(iframeDoc, category);&lt;br /&gt;
  } else {&lt;br /&gt;
    const observer = new MutationObserver((mutations, obs) =&amp;gt; {&lt;br /&gt;
      const filterForm = iframeDoc.getElementById(&amp;quot;filter-form&amp;quot;);&lt;br /&gt;
      if (filterForm) {&lt;br /&gt;
        translateiFrameElements(iframeDoc, category);&lt;br /&gt;
        obs.disconnect();&lt;br /&gt;
      }&lt;br /&gt;
    });&lt;br /&gt;
    observer.observe(iframeDoc.body, { childList: true, subtree: true });&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function translateMonsterCard(card, cardNameElement, monsterVnum) {&lt;br /&gt;
  const mapping = translation.mapping;&lt;br /&gt;
  const levelElement = card.querySelector(&amp;quot;[data-level]&amp;quot;);&lt;br /&gt;
  const typeElement = card.querySelector(&amp;quot;[data-type] a&amp;quot;);&lt;br /&gt;
  const damageElements = card.querySelectorAll(&amp;quot;[data-damage] a&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  cardNameElement.textContent = getTranslatedMonsterName(monsterVnum);&lt;br /&gt;
&lt;br /&gt;
  levelElement.textContent = levelElement.textContent.replace(&lt;br /&gt;
    &amp;quot;Boss&amp;quot;,&lt;br /&gt;
    translation.special.boss&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  if (typeElement) {&lt;br /&gt;
    typeElement.textContent = mapping[typeElement.textContent];&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  damageElements.forEach((damageElement) =&amp;gt; {&lt;br /&gt;
    damageElement.textContent = mapping[damageElement.textContent];&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addButtonsToCardsAndTranslate(&lt;br /&gt;
  characters,&lt;br /&gt;
  iframeDoc,&lt;br /&gt;
  iframeInfo,&lt;br /&gt;
  category&lt;br /&gt;
) {&lt;br /&gt;
  const buttonTemplates = characters.monsterButtonTemplates.children[0];&lt;br /&gt;
  const cardToEdit = iframeDoc.getElementById(&amp;quot;cards-container&amp;quot;).children;&lt;br /&gt;
  const { nameToVnum } = iframeInfo;&lt;br /&gt;
  const vnumToButtons = iframeInfo[category].vnumToButtons;&lt;br /&gt;
  const translateMonsters = characters.translateMonsters;&lt;br /&gt;
&lt;br /&gt;
  for (let cardIndex = 0; cardIndex &amp;lt; cardToEdit.length; cardIndex++) {&lt;br /&gt;
    const card = cardToEdit[cardIndex];&lt;br /&gt;
    const cardNameElement = card.querySelector(&amp;quot;[data-name]&amp;quot;).firstChild;&lt;br /&gt;
    const buttonTemplatesClone = buttonTemplates.cloneNode(true);&lt;br /&gt;
    const cardName = cardNameElement.title.replace(/\s/g, &amp;quot; &amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (!nameToVnum.hasOwnProperty(cardName)) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    const monsterVnum = nameToVnum[cardName];&lt;br /&gt;
&lt;br /&gt;
    buttonTemplatesClone.dataset.monsterId = monsterVnum;&lt;br /&gt;
    card.lastElementChild.appendChild(buttonTemplatesClone);&lt;br /&gt;
    vnumToButtons[monsterVnum] = buttonTemplatesClone.children;&lt;br /&gt;
&lt;br /&gt;
    if (translateMonsters) {&lt;br /&gt;
      translateMonsterCard(card, cardNameElement, monsterVnum);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (translateMonsters) {&lt;br /&gt;
    translateiFrame(iframeDoc, category);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateiFrameButtons(characters, iframeInfo, category) {&lt;br /&gt;
  var addedMonsters = Object.keys(characters.savedMonsters);&lt;br /&gt;
  var { currentiFrameIsMonster } = iframeInfo;&lt;br /&gt;
  var vnumToButtons = iframeInfo[category].vnumToButtons;&lt;br /&gt;
  var isPolymorphModal = category === &amp;quot;monster&amp;quot; &amp;amp;&amp;amp; !currentiFrameIsMonster;&lt;br /&gt;
&lt;br /&gt;
  for (var monsterVnum in vnumToButtons) {&lt;br /&gt;
    var [addButton, deleteButton, selectButton] = vnumToButtons[monsterVnum];&lt;br /&gt;
&lt;br /&gt;
    if (isPolymorphModal) {&lt;br /&gt;
      hideElement(addButton);&lt;br /&gt;
      hideElement(deleteButton);&lt;br /&gt;
      showElement(selectButton);&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isValueInArray(monsterVnum, addedMonsters)) {&lt;br /&gt;
      hideElement(addButton);&lt;br /&gt;
      showElement(deleteButton);&lt;br /&gt;
      hideElement(selectButton);&lt;br /&gt;
    } else {&lt;br /&gt;
      showElement(addButton);&lt;br /&gt;
      hideElement(deleteButton);&lt;br /&gt;
      hideElement(selectButton);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  iframeInfo.lastiFrameIsMonster = currentiFrameIsMonster;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getMonsterImage(buttonsContainer) {&lt;br /&gt;
  var elder = buttonsContainer.parentElement.firstElementChild;&lt;br /&gt;
  var image = elder.querySelector(&amp;quot;img&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (image) {&lt;br /&gt;
    return image.getAttribute(&amp;quot;src&amp;quot;) || &amp;quot;&amp;quot;;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return &amp;quot;&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleiFrame(iframeInfo, category) {&lt;br /&gt;
  var { characters, battle } = iframeInfo;&lt;br /&gt;
  var iframeInfoCategory = iframeInfo[category];&lt;br /&gt;
  var { iframe, pageName, vnumToButtons } = iframeInfoCategory;&lt;br /&gt;
  var loadingAnimation = iframeInfoCategory.iframe.previousElementSibling;&lt;br /&gt;
&lt;br /&gt;
  iframe.src = mw.util.getUrl(pageName);&lt;br /&gt;
&lt;br /&gt;
  iframe.addEventListener(&amp;quot;load&amp;quot;, function () {&lt;br /&gt;
    var iframeDoc = this.contentDocument || this.contentWindow.document;&lt;br /&gt;
    var iframeBody = iframeDoc.body;&lt;br /&gt;
    var content = iframeDoc.getElementById(&amp;quot;show-after-loading&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    iframeBody.firstElementChild.replaceWith(content);&lt;br /&gt;
&lt;br /&gt;
    iframeBody.style.background = &amp;quot;transparent&amp;quot;;&lt;br /&gt;
    iframeBody.style.paddingRight = &amp;quot;10px&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    addButtonsToCardsAndTranslate(characters, iframeDoc, iframeInfo, category);&lt;br /&gt;
    updateiFrameButtons(characters, iframeInfo, category);&lt;br /&gt;
&lt;br /&gt;
    iframeInfoCategory.loadIsFinished = true;&lt;br /&gt;
&lt;br /&gt;
    hideElement(loadingAnimation);&lt;br /&gt;
    showElement(iframe);&lt;br /&gt;
&lt;br /&gt;
    iframeDoc.addEventListener(&amp;quot;click&amp;quot;, handleButtonClick);&lt;br /&gt;
&lt;br /&gt;
    function handleButtonClick(event) {&lt;br /&gt;
      var target = event.target;&lt;br /&gt;
      var link = target.closest(&amp;quot;a&amp;quot;);&lt;br /&gt;
      var buttonsContainer = target.closest(&amp;quot;.handle-monster&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
      if (link) {&lt;br /&gt;
        event.preventDefault();&lt;br /&gt;
        window.open(link.href, &amp;quot;_blank&amp;quot;);&lt;br /&gt;
      } else if (buttonsContainer) {&lt;br /&gt;
        var { monsterId: monsterVnum } = buttonsContainer.dataset;&lt;br /&gt;
&lt;br /&gt;
        // polymorph iframe&lt;br /&gt;
        if (category === &amp;quot;monster&amp;quot; &amp;amp;&amp;amp; !iframeInfo.currentiFrameIsMonster) {&lt;br /&gt;
          var monsterImage = getMonsterImage(buttonsContainer);&lt;br /&gt;
          changePolymorphValues(&lt;br /&gt;
            characters.characterCreation,&lt;br /&gt;
            monsterVnum,&lt;br /&gt;
            monsterImage&lt;br /&gt;
          );&lt;br /&gt;
          handlePolymorphDisplay(characters, monsterVnum, monsterImage);&lt;br /&gt;
          iframe.dispatchEvent(newChangeEvent());&lt;br /&gt;
        } else {&lt;br /&gt;
          var addedMonsters = Object.keys(characters.savedMonsters);&lt;br /&gt;
          var [addButton, deleteButton] = vnumToButtons[monsterVnum];&lt;br /&gt;
&lt;br /&gt;
          if (isValueInArray(monsterVnum, addedMonsters)) {&lt;br /&gt;
            deleteMonster(characters, battle, monsterVnum);&lt;br /&gt;
            showElement(addButton);&lt;br /&gt;
            hideElement(deleteButton);&lt;br /&gt;
          } else {&lt;br /&gt;
            var monsterImage = getMonsterImage(buttonsContainer);&lt;br /&gt;
            addNewMonster(&lt;br /&gt;
              characters,&lt;br /&gt;
              battle,&lt;br /&gt;
              monsterVnum,&lt;br /&gt;
              monsterImage,&lt;br /&gt;
              iframeInfo,&lt;br /&gt;
              category&lt;br /&gt;
            );&lt;br /&gt;
            hideElement(addButton);&lt;br /&gt;
            showElement(deleteButton);&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getNameToVnumMapping() {&lt;br /&gt;
  var nameToVnum = {};&lt;br /&gt;
&lt;br /&gt;
  for (var monsterVnum in monsterData) {&lt;br /&gt;
    nameToVnum[monsterData[monsterVnum][monsterData[monsterVnum].length - 1]] =&lt;br /&gt;
      monsterVnum;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return nameToVnum;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function monsterManagement(characters, battle) {&lt;br /&gt;
  var { monsteriFrame, stoneiFrame } = characters;&lt;br /&gt;
  var monsterVnums = Object.keys(monsterData);&lt;br /&gt;
&lt;br /&gt;
  var iframeInfo = {&lt;br /&gt;
    lastiFrameIsMonster: false,&lt;br /&gt;
    currentiFrameIsMonster: false,&lt;br /&gt;
    characters: characters,&lt;br /&gt;
    battle: battle,&lt;br /&gt;
    nameToVnum: getNameToVnumMapping(),&lt;br /&gt;
    monster: {&lt;br /&gt;
      isLoaded: false,&lt;br /&gt;
      loadIsFinished: false,&lt;br /&gt;
      shouldBeUpdated: false,&lt;br /&gt;
      vnumToButtons: {},&lt;br /&gt;
      pageName: &amp;quot;Monstres&amp;quot;,&lt;br /&gt;
      iframe: monsteriFrame,&lt;br /&gt;
    },&lt;br /&gt;
    stone: {&lt;br /&gt;
      isLoaded: false,&lt;br /&gt;
      loadIsFinished: false,&lt;br /&gt;
      shouldBeUpdated: false,&lt;br /&gt;
      vnumToButtons: {},&lt;br /&gt;
      pageName: &amp;quot;Pierres Metin&amp;quot;,&lt;br /&gt;
      iframe: stoneiFrame,&lt;br /&gt;
    },&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  document.addEventListener(&amp;quot;modalOpen&amp;quot;, function (event) {&lt;br /&gt;
    var modalName = event.detail.name;&lt;br /&gt;
&lt;br /&gt;
    if (modalName === &amp;quot;monster&amp;quot; || modalName === &amp;quot;stone&amp;quot;) {&lt;br /&gt;
      handleModal(event.target, modalName);&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  function handleModal(target, modalName) {&lt;br /&gt;
    var iframeInfoCategory = iframeInfo[modalName];&lt;br /&gt;
&lt;br /&gt;
    if (modalName === &amp;quot;monster&amp;quot;) {&lt;br /&gt;
      var isMonsteriFrame = target.id === &amp;quot;add-new-monster&amp;quot;;&lt;br /&gt;
      iframeInfo.currentiFrameIsMonster = isMonsteriFrame;&lt;br /&gt;
&lt;br /&gt;
      if (&lt;br /&gt;
        iframeInfoCategory.loadIsFinished &amp;amp;&amp;amp;&lt;br /&gt;
        ((isMonsteriFrame &amp;amp;&amp;amp; !iframeInfo.lastiFrameIsMonster) ||&lt;br /&gt;
          (!isMonsteriFrame &amp;amp;&amp;amp; iframeInfo.lastiFrameIsMonster))&lt;br /&gt;
      ) {&lt;br /&gt;
        iframeInfoCategory.shouldBeUpdated = true;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!iframeInfoCategory.isLoaded) {&lt;br /&gt;
      handleiFrame(iframeInfo, modalName);&lt;br /&gt;
      iframeInfoCategory.isLoaded = true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      iframeInfoCategory.loadIsFinished &amp;amp;&amp;amp;&lt;br /&gt;
      iframeInfoCategory.shouldBeUpdated&lt;br /&gt;
    ) {&lt;br /&gt;
      updateiFrameButtons(characters, iframeInfo, modalName);&lt;br /&gt;
      iframeInfoCategory.shouldBeUpdated = false;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  Object.keys(characters.savedMonsters)&lt;br /&gt;
    .slice()&lt;br /&gt;
    .forEach(function (monsterVnum) {&lt;br /&gt;
      if (isValueInArray(monsterVnum, monsterVnums)) {&lt;br /&gt;
        addMonsterElement(characters, battle, monsterVnum, iframeInfo);&lt;br /&gt;
      } else {&lt;br /&gt;
        deleteMonster(characters, battle, monsterVnum);&lt;br /&gt;
      }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function hideAttackType(container, input, attackType) {&lt;br /&gt;
  hideElement(container);&lt;br /&gt;
&lt;br /&gt;
  if (input.checked) {&lt;br /&gt;
    var defaultInput = attackType.defaultInput;&lt;br /&gt;
&lt;br /&gt;
    input.checked = false;&lt;br /&gt;
    defaultInput.checked = true;&lt;br /&gt;
    defaultInput.dispatchEvent(newChangeEvent());&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterAttackTypeSelectionCharacter(attacker, attackType) {&lt;br /&gt;
  var attackerClass = attacker.class;&lt;br /&gt;
  var attackerIsNotPolymorph = !isPolymorph(attacker);&lt;br /&gt;
  var { elements: attackTypeElements } = attackType;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; attackTypeElements.length; index++) {&lt;br /&gt;
    var { container, input, inputClass, inputValue } =&lt;br /&gt;
      attackTypeElements[index];&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      attackerIsNotPolymorph &amp;amp;&amp;amp;&lt;br /&gt;
      attacker[inputValue] &amp;amp;&amp;amp;&lt;br /&gt;
      (attackerClass === inputClass ||&lt;br /&gt;
        (inputValue.startsWith(&amp;quot;horseSkill&amp;quot;) &amp;amp;&amp;amp;&lt;br /&gt;
          isRiding(attacker) &amp;amp;&amp;amp;&lt;br /&gt;
          (!inputClass || isValueInArray(attackerClass, inputClass))))&lt;br /&gt;
    ) {&lt;br /&gt;
      showElement(container);&lt;br /&gt;
    } else {&lt;br /&gt;
      hideAttackType(container, input, attackType);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterAttackTypeSelectionMonster(attackType) {&lt;br /&gt;
  var attackTypeElements = attackType.elements;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; attackTypeElements.length; index++) {&lt;br /&gt;
    var { container, input } = attackTypeElements[index];&lt;br /&gt;
    hideAttackType(container, input, attackType);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function removeBattleElement(battleChoice, nameOrVnum, category, type) {&lt;br /&gt;
  var elements = battleChoice[category][type].elements;&lt;br /&gt;
&lt;br /&gt;
  if (elements.hasOwnProperty(nameOrVnum)) {&lt;br /&gt;
    elements[nameOrVnum].container.remove();&lt;br /&gt;
    delete elements[nameOrVnum];&lt;br /&gt;
    battleChoice[category][type].count--;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function removeBattleChoice(battleChoice, nameOrVnum, type) {&lt;br /&gt;
  battleChoice.categories.forEach(function (category) {&lt;br /&gt;
    if (category === &amp;quot;attacker&amp;quot; &amp;amp;&amp;amp; type === &amp;quot;stone&amp;quot;) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
    var selected = battleChoice[category].selected;&lt;br /&gt;
&lt;br /&gt;
    if (selected) {&lt;br /&gt;
      var { type: selectedType, nameOrVnum: selectedNameOrVnum } =&lt;br /&gt;
        parseTypeAndName(selected);&lt;br /&gt;
&lt;br /&gt;
      if (nameOrVnum === selectedNameOrVnum &amp;amp;&amp;amp; type === selectedType) {&lt;br /&gt;
        resetBattleChoiceButton(battleChoice, category);&lt;br /&gt;
        battleChoice[category].selected = null;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    removeBattleElement(battleChoice, nameOrVnum, category, type);&lt;br /&gt;
    updateBattleChoiceText(battleChoice, category, type);&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addBattleElement(&lt;br /&gt;
  battleChoice,&lt;br /&gt;
  pseudoOrVnum,&lt;br /&gt;
  characterOrMonster,&lt;br /&gt;
  category,&lt;br /&gt;
  isMonster&lt;br /&gt;
) {&lt;br /&gt;
  var { template, raceToImage, translateMonsters } = battleChoice;&lt;br /&gt;
  var battleChoiceCategory = battleChoice[category];&lt;br /&gt;
  var templateClone = template.cloneNode(true);&lt;br /&gt;
  var label = templateClone.firstElementChild;&lt;br /&gt;
  var [input, image, span] = label.children;&lt;br /&gt;
  var imageSrc;&lt;br /&gt;
  var name;&lt;br /&gt;
  var type;&lt;br /&gt;
&lt;br /&gt;
  if (isMonster) {&lt;br /&gt;
    type = characterOrMonster.category;&lt;br /&gt;
&lt;br /&gt;
    if (type === &amp;quot;stone&amp;quot; &amp;amp;&amp;amp; category === &amp;quot;attacker&amp;quot;) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
    imageSrc = characterOrMonster.image;&lt;br /&gt;
    name = translateMonsters&lt;br /&gt;
      ? getTranslatedMonsterName(pseudoOrVnum)&lt;br /&gt;
      : getMonsterName(pseudoOrVnum);&lt;br /&gt;
  } else {&lt;br /&gt;
    type = &amp;quot;character&amp;quot;;&lt;br /&gt;
    imageSrc = raceToImage[characterOrMonster.race];&lt;br /&gt;
    name = pseudoOrVnum;&lt;br /&gt;
    label.classList.add(&amp;quot;notranslate&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var value = type + &amp;quot;-&amp;quot; + pseudoOrVnum;&lt;br /&gt;
  var id = category + &amp;quot;-&amp;quot; + value;&lt;br /&gt;
  var currentBattleChoice = battleChoiceCategory[type];&lt;br /&gt;
&lt;br /&gt;
  label.setAttribute(&amp;quot;for&amp;quot;, id);&lt;br /&gt;
  input.value = value;&lt;br /&gt;
  input.id = id;&lt;br /&gt;
  input.name = category;&lt;br /&gt;
  span.textContent = name;&lt;br /&gt;
&lt;br /&gt;
  handleImageFromWiki(image, imageSrc);&lt;br /&gt;
&lt;br /&gt;
  currentBattleChoice.container.appendChild(templateClone);&lt;br /&gt;
  currentBattleChoice.count++;&lt;br /&gt;
  currentBattleChoice.elements[pseudoOrVnum] = {&lt;br /&gt;
    container: templateClone,&lt;br /&gt;
    image: image,&lt;br /&gt;
    name: name,&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  updateBattleChoiceText(battleChoice, category, type);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addBattleChoice(&lt;br /&gt;
  battleChoice,&lt;br /&gt;
  pseudoOrVnum,&lt;br /&gt;
  characterOrMonster,&lt;br /&gt;
  isMonster = false&lt;br /&gt;
) {&lt;br /&gt;
  addBattleElement(&lt;br /&gt;
    battleChoice,&lt;br /&gt;
    pseudoOrVnum,&lt;br /&gt;
    characterOrMonster,&lt;br /&gt;
    &amp;quot;attacker&amp;quot;,&lt;br /&gt;
    isMonster&lt;br /&gt;
  );&lt;br /&gt;
  addBattleElement(&lt;br /&gt;
    battleChoice,&lt;br /&gt;
    pseudoOrVnum,&lt;br /&gt;
    characterOrMonster,&lt;br /&gt;
    &amp;quot;victim&amp;quot;,&lt;br /&gt;
    isMonster&lt;br /&gt;
  );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateBattleChoiceImage(battleChoice, characterName, newRace) {&lt;br /&gt;
  var imageSrc = battleChoice.raceToImage[newRace];&lt;br /&gt;
&lt;br /&gt;
  battleChoice.categories.forEach(function (category) {&lt;br /&gt;
    handleImageFromWiki(&lt;br /&gt;
      battleChoice[category].character.elements[characterName].image,&lt;br /&gt;
      imageSrc&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    var selected = battleChoice[category].selected;&lt;br /&gt;
&lt;br /&gt;
    if (isCharacterSelected(characterName, selected)) {&lt;br /&gt;
      updateBattleChoiceButton(battleChoice, category, selected);&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateBattleChoiceText(battleChoice, category, type) {&lt;br /&gt;
  var { count, container } = battleChoice[category][type];&lt;br /&gt;
  var parentContainer = container.parentElement;&lt;br /&gt;
&lt;br /&gt;
  if (count === 0) {&lt;br /&gt;
    hideElement(parentContainer);&lt;br /&gt;
    showElement(parentContainer.nextElementSibling);&lt;br /&gt;
  } else if (count === 1) {&lt;br /&gt;
    showElement(parentContainer);&lt;br /&gt;
    hideElement(parentContainer.nextElementSibling);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateBattleChoice(characters, battleChoice) {&lt;br /&gt;
  var templateImage = battleChoice.template.querySelector(&amp;quot;img&amp;quot;);&lt;br /&gt;
  var attackerImage = battleChoice.attacker.buttonContent.querySelector(&amp;quot;img&amp;quot;);&lt;br /&gt;
  var victimImage = battleChoice.victim.buttonContent.querySelector(&amp;quot;img&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  resetImageFromWiki(templateImage);&lt;br /&gt;
  resetImageFromWiki(attackerImage);&lt;br /&gt;
  resetImageFromWiki(victimImage);&lt;br /&gt;
&lt;br /&gt;
  for (var [pseudo, character] of Object.entries(characters.savedCharacters)) {&lt;br /&gt;
    addBattleChoice(battleChoice, pseudo, character);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (var [vnum, monster] of Object.entries(characters.savedMonsters)) {&lt;br /&gt;
    addBattleChoice(battleChoice, vnum, monster, true);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateBattleChoiceButton(battleChoice, category, data) {&lt;br /&gt;
  var battleChoiceCategory = battleChoice[category];&lt;br /&gt;
  var { defaultButtonContent, buttonContent } = battleChoiceCategory;&lt;br /&gt;
  var [buttonImage, buttonSpan] = buttonContent.firstElementChild.children;&lt;br /&gt;
  var { type, nameOrVnum } = parseTypeAndName(data);&lt;br /&gt;
  var { name, image } = battleChoiceCategory[type].elements[nameOrVnum];&lt;br /&gt;
&lt;br /&gt;
  hideElement(defaultButtonContent);&lt;br /&gt;
  showElement(buttonContent);&lt;br /&gt;
&lt;br /&gt;
  buttonSpan.textContent = name;&lt;br /&gt;
  buttonImage.src = image.src;&lt;br /&gt;
  battleChoiceCategory.selected = data;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function resetBattleChoiceButton(battleChoice, category) {&lt;br /&gt;
  var { defaultButtonContent, buttonContent } = battleChoice[category];&lt;br /&gt;
&lt;br /&gt;
  showElement(defaultButtonContent);&lt;br /&gt;
  hideElement(buttonContent);&lt;br /&gt;
&lt;br /&gt;
  if (category === &amp;quot;attacker&amp;quot;) {&lt;br /&gt;
    filterAttackTypeSelectionMonster(battleChoice.attackType);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isPC(character) {&lt;br /&gt;
  if (character.race === 0 || character.race === 1) {&lt;br /&gt;
    return false;&lt;br /&gt;
  }&lt;br /&gt;
  return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isBoss(character) {&lt;br /&gt;
  return character.race === 0 &amp;amp;&amp;amp; character.rank &amp;gt;= 5;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isStone(character) {&lt;br /&gt;
  return character.race === 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isMeleeAttacker(monster) {&lt;br /&gt;
  return monster.attack == 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isRangeAttacker(monster) {&lt;br /&gt;
  return monster.attack == 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isMagicAttacker(monster) {&lt;br /&gt;
  return monster.attack == 2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isMagicClass(character) {&lt;br /&gt;
  return character.race === &amp;quot;shaman&amp;quot; || character.class === &amp;quot;black_magic&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isDispell(character, skillId) {&lt;br /&gt;
  return character.class === &amp;quot;weaponary&amp;quot; &amp;amp;&amp;amp; skillId === 6;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isPolymorph(character) {&lt;br /&gt;
  return isChecked(character.isPolymorph);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isRiding(character) {&lt;br /&gt;
  return isChecked(character.isRiding);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isBow(weaponType) {&lt;br /&gt;
  return weaponType === 2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcAttackFactor(attacker, victim) {&lt;br /&gt;
  function calcCoeffK(dex, level) {&lt;br /&gt;
    return Math.min(90, Math.floor((2 * dex + level) / 3));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var K1 = calcCoeffK(attacker.polymorphDex, attacker.level);&lt;br /&gt;
  var K2 = calcCoeffK(victim.polymorphDex, attacker.level);&lt;br /&gt;
&lt;br /&gt;
  var AR = (K1 + 210) / 300;&lt;br /&gt;
  var ER = (((2 * K2 + 5) / (K2 + 95)) * 3) / 10;&lt;br /&gt;
&lt;br /&gt;
  return truncateNumber(AR - ER, 8);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcMainAttackValue(attacker) {&lt;br /&gt;
  var leadership = 0;&lt;br /&gt;
  var weaponGrowth = 0;&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker)) {&lt;br /&gt;
    weaponGrowth = attacker.weapon.growth;&lt;br /&gt;
    leadership = attacker.leadership;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return 2 * (attacker.level + weaponGrowth) + leadership;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcStatAttackValue(character) {&lt;br /&gt;
  switch (character.race) {&lt;br /&gt;
    case &amp;quot;warrior&amp;quot;:&lt;br /&gt;
    case &amp;quot;sura&amp;quot;:&lt;br /&gt;
      return 2 * character.str;&lt;br /&gt;
    case &amp;quot;ninja&amp;quot;:&lt;br /&gt;
      return Math.floor((1 / 4) * (character.str + 7 * character.dex));&lt;br /&gt;
    case &amp;quot;shaman&amp;quot;:&lt;br /&gt;
      return Math.floor((1 / 3) * (5 * character.int + character.dex));&lt;br /&gt;
    case &amp;quot;lycan&amp;quot;:&lt;br /&gt;
      return character.vit + 2 * character.dex;&lt;br /&gt;
    default:&lt;br /&gt;
      return 2 * character.str;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcPvpCriticalAttackRange(minAttackValue, maxAttackValue, growth) {&lt;br /&gt;
  return Array.from(&lt;br /&gt;
    { length: maxAttackValue - minAttackValue + 1 },&lt;br /&gt;
    (_, index) =&amp;gt; (minAttackValue + growth + index) * 2&lt;br /&gt;
  );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcSecondaryAttackValue(attacker, isPlayerVsPlayer) {&lt;br /&gt;
  let attackValueOther = 0;&lt;br /&gt;
&lt;br /&gt;
  let minAttackValue = 0;&lt;br /&gt;
  let maxAttackValue = 0;&lt;br /&gt;
&lt;br /&gt;
  let minAttackValueSlash = 0;&lt;br /&gt;
  let maxAttackValueSlash = 0;&lt;br /&gt;
&lt;br /&gt;
  let type, isSerpent, growth;&lt;br /&gt;
&lt;br /&gt;
  let criticalAttackRange;&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker)) {&lt;br /&gt;
    ({ type, isSerpent, minAttackValue, maxAttackValue, growth } =&lt;br /&gt;
      attacker.weapon);&lt;br /&gt;
&lt;br /&gt;
    if (isSerpent) {&lt;br /&gt;
      minAttackValue = Math.max(0, attacker.minAttackValueRandom - growth);&lt;br /&gt;
      maxAttackValue = Math.max(&lt;br /&gt;
        minAttackValue,&lt;br /&gt;
        attacker.maxAttackValueRandom - growth&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    minAttackValueSlash = Math.min(&lt;br /&gt;
      attacker.minAttackValueSlash,&lt;br /&gt;
      attacker.maxAttackValueSlash&lt;br /&gt;
    );&lt;br /&gt;
    maxAttackValueSlash = Math.max(&lt;br /&gt;
      attacker.minAttackValueSlash,&lt;br /&gt;
      attacker.maxAttackValueSlash&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    attackValueOther += attacker.attackValue;&lt;br /&gt;
&lt;br /&gt;
    if (isBow(type) &amp;amp;&amp;amp; !isPolymorph(attacker)) {&lt;br /&gt;
      attackValueOther += 25;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isPlayerVsPlayer) {&lt;br /&gt;
      criticalAttackRange = calcPvpCriticalAttackRange(&lt;br /&gt;
        minAttackValue,&lt;br /&gt;
        maxAttackValue,&lt;br /&gt;
        growth&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    minAttackValue = attacker.minAttackValue;&lt;br /&gt;
    maxAttackValue = attacker.maxAttackValue;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  minAttackValue += attacker.minAttackValuePolymorph;&lt;br /&gt;
  maxAttackValue += attacker.maxAttackValuePolymorph;&lt;br /&gt;
&lt;br /&gt;
  attackValueOther += attacker.statAttackValue;&lt;br /&gt;
  attackValueOther += attacker.horseAttackValue;&lt;br /&gt;
&lt;br /&gt;
  const weaponInterval = maxAttackValue - minAttackValue + 1;&lt;br /&gt;
  const slashInterval = maxAttackValueSlash - minAttackValueSlash + 1;&lt;br /&gt;
&lt;br /&gt;
  const totalCardinal = weaponInterval * slashInterval * 1_000_000;&lt;br /&gt;
  const minInterval = Math.min(weaponInterval, slashInterval);&lt;br /&gt;
&lt;br /&gt;
  minAttackValue += minAttackValueSlash;&lt;br /&gt;
  maxAttackValue += maxAttackValueSlash;&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    minAttackValue: minAttackValue,&lt;br /&gt;
    maxAttackValue: maxAttackValue,&lt;br /&gt;
    attackValueOther: attackValueOther,&lt;br /&gt;
    totalCardinal: totalCardinal,&lt;br /&gt;
    weights: calcWeights(minAttackValue, maxAttackValue, minInterval),&lt;br /&gt;
    possibleDamageCount: maxAttackValue - minAttackValue + 1,&lt;br /&gt;
    criticalAttackRange: criticalAttackRange,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcMagicAttackValue(attacker, isPlayerVsPlayer) {&lt;br /&gt;
  let minMagicAttackValueSlash = 0;&lt;br /&gt;
  let maxMagicAttackValueSlash = 0;&lt;br /&gt;
&lt;br /&gt;
  let criticalAttackRange;&lt;br /&gt;
&lt;br /&gt;
  let {&lt;br /&gt;
    isSerpent,&lt;br /&gt;
    minMagicAttackValue,&lt;br /&gt;
    maxMagicAttackValue,&lt;br /&gt;
    minAttackValue,&lt;br /&gt;
    maxAttackValue,&lt;br /&gt;
    growth,&lt;br /&gt;
  } = attacker.weapon;&lt;br /&gt;
&lt;br /&gt;
  if (isSerpent) {&lt;br /&gt;
    minMagicAttackValue = Math.max(0, attacker.minMagicAttackValueRandom);&lt;br /&gt;
    maxMagicAttackValue = Math.max(&lt;br /&gt;
      minMagicAttackValue,&lt;br /&gt;
      attacker.maxMagicAttackValueRandom&lt;br /&gt;
    );&lt;br /&gt;
    minAttackValue = Math.max(0, attacker.minAttackValueRandom - growth);&lt;br /&gt;
    maxAttackValue = Math.max(&lt;br /&gt;
      minAttackValue,&lt;br /&gt;
      attacker.maxAttackValueRandom - growth&lt;br /&gt;
    );&lt;br /&gt;
  } else {&lt;br /&gt;
    minMagicAttackValue += growth;&lt;br /&gt;
    maxMagicAttackValue += growth;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (isPlayerVsPlayer) {&lt;br /&gt;
    criticalAttackRange = calcPvpCriticalAttackRange(&lt;br /&gt;
      minAttackValue,&lt;br /&gt;
      maxAttackValue,&lt;br /&gt;
      growth&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  minMagicAttackValueSlash = Math.min(&lt;br /&gt;
    attacker.minMagicAttackValueSlash,&lt;br /&gt;
    attacker.maxMagicAttackValueSlash&lt;br /&gt;
  );&lt;br /&gt;
  maxMagicAttackValueSlash = Math.max(&lt;br /&gt;
    attacker.minMagicAttackValueSlash,&lt;br /&gt;
    attacker.maxMagicAttackValueSlash&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  const weaponInterval = maxMagicAttackValue - minMagicAttackValue + 1;&lt;br /&gt;
  const slashInterval = maxMagicAttackValueSlash - minMagicAttackValueSlash + 1;&lt;br /&gt;
&lt;br /&gt;
  const totalCardinal = weaponInterval * slashInterval * 1_000_000;&lt;br /&gt;
  const minInterval = Math.min(weaponInterval, slashInterval);&lt;br /&gt;
&lt;br /&gt;
  minMagicAttackValue += minMagicAttackValueSlash;&lt;br /&gt;
  maxMagicAttackValue += maxMagicAttackValueSlash;&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    minMagicAttackValue: minMagicAttackValue,&lt;br /&gt;
    maxMagicAttackValue: maxMagicAttackValue,&lt;br /&gt;
    magicAttackValueAugmentation: getMagicAttackValueAugmentation(&lt;br /&gt;
      minMagicAttackValue,&lt;br /&gt;
      maxMagicAttackValue,&lt;br /&gt;
      attacker.magicAttackValue&lt;br /&gt;
    ),&lt;br /&gt;
    totalCardinal: totalCardinal,&lt;br /&gt;
    weights: calcWeights(minMagicAttackValue, maxMagicAttackValue, minInterval),&lt;br /&gt;
    possibleDamageCount: maxMagicAttackValue - minMagicAttackValue + 1,&lt;br /&gt;
    criticalAttackRange: criticalAttackRange,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getPolymorphPower(polymorphPoint, polymorphPowerTable) {&lt;br /&gt;
  return polymorphPowerTable[polymorphPoint];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSkillPower(skillPoint, skillPowerTable) {&lt;br /&gt;
  return skillPowerTable[skillPoint];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getMarriageBonusValue(character, marriageTable, itemName) {&lt;br /&gt;
  let index;&lt;br /&gt;
  const lovePoint = character.lovePoint;&lt;br /&gt;
&lt;br /&gt;
  if (lovePoint &amp;lt; 65) {&lt;br /&gt;
    index = 0;&lt;br /&gt;
  } else if (lovePoint &amp;lt; 80) {&lt;br /&gt;
    index = 1;&lt;br /&gt;
  } else if (lovePoint &amp;lt; 100) {&lt;br /&gt;
    index = 2;&lt;br /&gt;
  } else {&lt;br /&gt;
    index = 3;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return marriageTable[itemName][index];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcDamageWithPrimaryBonuses(damage, bonusValues) {&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.attackValueCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  damage += bonusValues.attackValueMarriage;&lt;br /&gt;
&lt;br /&gt;
  damage = Math.floor(&lt;br /&gt;
    (damage * bonusValues.monsterResistanceMarriageCoeff) / 100&lt;br /&gt;
  );&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.monsterResistanceCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  damage += Math.floor((damage * bonusValues.typeBonusCoeff) / 100);&lt;br /&gt;
  damage +=&lt;br /&gt;
    Math.floor((damage * bonusValues.raceBonusCoeff) / 100) -&lt;br /&gt;
    Math.floor((damage * bonusValues.raceResistanceCoeff) / 100);&lt;br /&gt;
  damage += Math.floor((damage * bonusValues.stoneBonusCoeff) / 100);&lt;br /&gt;
  damage += Math.floor((damage * bonusValues.monsterBonusCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  const elementBonusCoeff = bonusValues.elementBonusCoeff;&lt;br /&gt;
&lt;br /&gt;
  damage +=&lt;br /&gt;
    Math.trunc((damage * elementBonusCoeff[0]) / 10000) +&lt;br /&gt;
    Math.trunc((damage * elementBonusCoeff[1]) / 10000) +&lt;br /&gt;
    Math.trunc((damage * elementBonusCoeff[2]) / 10000) +&lt;br /&gt;
    Math.trunc((damage * elementBonusCoeff[3]) / 10000) +&lt;br /&gt;
    Math.trunc((damage * elementBonusCoeff[4]) / 10000) +&lt;br /&gt;
    Math.trunc((damage * elementBonusCoeff[5]) / 10000);&lt;br /&gt;
&lt;br /&gt;
  damage = Math.floor(damage * bonusValues.damageMultiplier);&lt;br /&gt;
&lt;br /&gt;
  return damage;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcFinalDamage(&lt;br /&gt;
  finalDamage,&lt;br /&gt;
  minPiercingDamage,&lt;br /&gt;
  tempDamage,&lt;br /&gt;
  bonusValues,&lt;br /&gt;
  criticalAttackRange,&lt;br /&gt;
  damageByType&lt;br /&gt;
) {&lt;br /&gt;
  for (let criticalIndex = 0; criticalIndex &amp;lt; 2; criticalIndex++) {&lt;br /&gt;
    if (bonusValues.skipCriticalStep[criticalIndex]) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
    let beforeCriticalDamage = finalDamage;&lt;br /&gt;
    let damageValues = criticalIndex&lt;br /&gt;
      ? criticalAttackRange || [finalDamage]&lt;br /&gt;
      : [0];&lt;br /&gt;
&lt;br /&gt;
    for (let index = 0, len = damageValues.length; index &amp;lt; len; index++) {&lt;br /&gt;
      let afterCriticalDamage = beforeCriticalDamage + damageValues[index];&lt;br /&gt;
&lt;br /&gt;
      for (let piercingIndex = 0; piercingIndex &amp;lt; 2; piercingIndex++) {&lt;br /&gt;
        if (bonusValues.skipPiercingStep[piercingIndex]) {&lt;br /&gt;
          continue;&lt;br /&gt;
        }&lt;br /&gt;
        let damage = afterCriticalDamage;&lt;br /&gt;
&lt;br /&gt;
        if (piercingIndex) {&lt;br /&gt;
          damage += bonusValues.defenseBoost + Math.min(0, minPiercingDamage);&lt;br /&gt;
          damage += Math.floor(&lt;br /&gt;
            (tempDamage * bonusValues.extraPiercingHitCoeff) / 1000&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        damage = Math.floor((damage * bonusValues.averageDamageCoeff) / 100);&lt;br /&gt;
        damage = Math.floor(&lt;br /&gt;
          (damage * bonusValues.averageDamageResistanceCoeff) / 100&lt;br /&gt;
        );&lt;br /&gt;
        damage = Math.floor((damage * bonusValues.skillDamageCoeff) / 100);&lt;br /&gt;
        damage = Math.floor(&lt;br /&gt;
          (damage * bonusValues.skillDamageResistanceCoeff) / 100&lt;br /&gt;
        );&lt;br /&gt;
        damage = Math.floor((damage * bonusValues.rankBonusCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
        if (bonusValues.useDarkProtection) {&lt;br /&gt;
          const { darkProtectionPoint, darkProtectionSp } = bonusValues;&lt;br /&gt;
&lt;br /&gt;
          const damageReduction = Math.floor(damage / 3);&lt;br /&gt;
          const spAbsorption = Math.floor(&lt;br /&gt;
            (damageReduction * darkProtectionPoint) / 100&lt;br /&gt;
          );&lt;br /&gt;
&lt;br /&gt;
          if (spAbsorption &amp;lt;= darkProtectionSp) {&lt;br /&gt;
            damage -= damageReduction;&lt;br /&gt;
          } else {&lt;br /&gt;
            damage -= Math.floor(&lt;br /&gt;
              (darkProtectionSp * 100) / darkProtectionPoint&lt;br /&gt;
            );&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        damage = Math.max(0, damage + bonusValues.defensePercent);&lt;br /&gt;
        damage += Math.min(&lt;br /&gt;
          300,&lt;br /&gt;
          Math.floor((damage * bonusValues.damageBonusCoeff) / 100)&lt;br /&gt;
        );&lt;br /&gt;
        damage = Math.floor((damage * bonusValues.empireMalusCoeff) / 10);&lt;br /&gt;
        damage = Math.floor((damage * bonusValues.sungMaStrBonusCoeff) / 10000);&lt;br /&gt;
        damage -= Math.floor(damage * bonusValues.sungmaStrMalusCoeff);&lt;br /&gt;
&lt;br /&gt;
        damage = Math.floor(&lt;br /&gt;
          (damage * bonusValues.whiteDragonElixirCoeff) / 100&lt;br /&gt;
        );&lt;br /&gt;
        damage = Math.floor(&lt;br /&gt;
          (damage * bonusValues.steelDragonElixirCoeff) / 100&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        damageByType[criticalIndex + 2 * piercingIndex].push(damage);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveFinalDamage(&lt;br /&gt;
  damage,&lt;br /&gt;
  minPiercingDamage,&lt;br /&gt;
  damageWithPrimaryBonuses,&lt;br /&gt;
  bonusValues,&lt;br /&gt;
  criticalAttackRange,&lt;br /&gt;
  damageByType&lt;br /&gt;
) {&lt;br /&gt;
  damage = Math.floor(damage * bonusValues.magicResistanceCoeff);&lt;br /&gt;
  damage = Math.trunc((damage * bonusValues.weaponDefenseCoeff) / 100);&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.tigerStrengthCoeff) / 100);&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.berserkBonusCoeff) / 100);&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.fearBonusCoeff) / 100);&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.blessingBonusCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  calcFinalDamage(&lt;br /&gt;
    damage,&lt;br /&gt;
    minPiercingDamage,&lt;br /&gt;
    damageWithPrimaryBonuses,&lt;br /&gt;
    bonusValues,&lt;br /&gt;
    criticalAttackRange,&lt;br /&gt;
    damageByType&lt;br /&gt;
  );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveFinalSkillDamage(&lt;br /&gt;
  damage,&lt;br /&gt;
  minPiercingDamage,&lt;br /&gt;
  bonusValues,&lt;br /&gt;
  criticalAttackRange,&lt;br /&gt;
  damageByType&lt;br /&gt;
) {&lt;br /&gt;
  damage = Math.floor(damage * bonusValues.magicResistanceCoeff);&lt;br /&gt;
  damage = Math.trunc((damage * bonusValues.weaponDefenseCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  damage -= bonusValues.defense;&lt;br /&gt;
&lt;br /&gt;
  damage = floorMultiplication(damage, bonusValues.skillWardCoeff);&lt;br /&gt;
  damage = floorMultiplication(damage, bonusValues.skillBonusCoeff);&lt;br /&gt;
&lt;br /&gt;
  const tempDamage = Math.floor(&lt;br /&gt;
    (damage * bonusValues.skillBonusByBonusCoeff) / 100&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  damage = Math.floor(&lt;br /&gt;
    (tempDamage * bonusValues.magicAttackValueCoeff) / 100 + 0.5&lt;br /&gt;
  );&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.tigerStrengthCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  calcFinalDamage(&lt;br /&gt;
    damage,&lt;br /&gt;
    minPiercingDamage,&lt;br /&gt;
    tempDamage,&lt;br /&gt;
    bonusValues,&lt;br /&gt;
    criticalAttackRange,&lt;br /&gt;
    damageByType&lt;br /&gt;
  );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function computePolymorphPoint(attacker, victim, polymorphPowerTable) {&lt;br /&gt;
  attacker.polymorphDex = attacker.dex;&lt;br /&gt;
  victim.polymorphDex = victim.dex;&lt;br /&gt;
&lt;br /&gt;
  attacker.minAttackValuePolymorph = 0;&lt;br /&gt;
  attacker.maxAttackValuePolymorph = 0;&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker) &amp;amp;&amp;amp; isPolymorph(attacker)) {&lt;br /&gt;
    var polymorphPowerPct =&lt;br /&gt;
      getPolymorphPower(attacker.polymorphPoint, polymorphPowerTable) / 100;&lt;br /&gt;
    var polymorphMonster = createMonster(&lt;br /&gt;
      attacker.polymorphMonster,&lt;br /&gt;
      null,&lt;br /&gt;
      null,&lt;br /&gt;
      true&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    var polymorphStr = floorMultiplication(&lt;br /&gt;
      polymorphPowerPct,&lt;br /&gt;
      polymorphMonster.str&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    attacker.polymorphDex += floorMultiplication(&lt;br /&gt;
      polymorphPowerPct,&lt;br /&gt;
      polymorphMonster.dex&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    attacker.minAttackValuePolymorph = floorMultiplication(&lt;br /&gt;
      polymorphPowerPct,&lt;br /&gt;
      polymorphMonster.minAttackValue&lt;br /&gt;
    );&lt;br /&gt;
    attacker.maxAttackValuePolymorph = floorMultiplication(&lt;br /&gt;
      polymorphPowerPct,&lt;br /&gt;
      polymorphMonster.maxAttackValue&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    if (!attacker.weapon) {&lt;br /&gt;
      attacker.maxAttackValuePolymorph += 1;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    attacker.attackValue = 0;&lt;br /&gt;
&lt;br /&gt;
    if (isMagicClass(attacker)) {&lt;br /&gt;
      attacker.statAttackValue = 2 * (polymorphStr + attacker.int);&lt;br /&gt;
    } else {&lt;br /&gt;
      attacker.statAttackValue = 2 * (polymorphStr + attacker.str);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function computeHorse(attacker) {&lt;br /&gt;
  attacker.horseAttackValue = 0;&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker) &amp;amp;&amp;amp; isRiding(attacker) &amp;amp;&amp;amp; !isPolymorph(attacker)) {&lt;br /&gt;
    var horseConstant = 30;&lt;br /&gt;
&lt;br /&gt;
    if (attacker.class === &amp;quot;weaponary&amp;quot;) {&lt;br /&gt;
      horseConstant = 60;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    attacker.horseAttackValue = floorMultiplication(&lt;br /&gt;
      2 * attacker.level + attacker.statAttackValue,&lt;br /&gt;
      attacker.horsePoint / horseConstant&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getRankBonus(attacker) {&lt;br /&gt;
  if (!isChecked(attacker.lowRank)) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  switch (attacker.rank) {&lt;br /&gt;
    case &amp;quot;aggressive&amp;quot;:&lt;br /&gt;
      return 1;&lt;br /&gt;
    case &amp;quot;fraudulent&amp;quot;:&lt;br /&gt;
      return 2;&lt;br /&gt;
    case &amp;quot;malicious&amp;quot;:&lt;br /&gt;
      return 3;&lt;br /&gt;
    case &amp;quot;cruel&amp;quot;:&lt;br /&gt;
      return 5;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcElementCoeffPvP(elementBonus, mapping, attacker, victim) {&lt;br /&gt;
  var minElementMalus = 0;&lt;br /&gt;
  var maxDifference = 0;&lt;br /&gt;
  var savedElementDifferences = [];&lt;br /&gt;
  var elementBonusIndex = 0;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; elementBonus.length; index++) {&lt;br /&gt;
    if (!attacker[mapping.elementBonus[index]]) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var elementDifference =&lt;br /&gt;
      attacker[mapping.elementBonus[index]] -&lt;br /&gt;
      victim[mapping.elementResistance[index]];&lt;br /&gt;
&lt;br /&gt;
    if (elementDifference &amp;gt;= 0) {&lt;br /&gt;
      elementBonus[elementBonusIndex] = 10 * elementDifference;&lt;br /&gt;
      minElementMalus -= elementDifference;&lt;br /&gt;
      maxDifference = Math.max(maxDifference, elementDifference);&lt;br /&gt;
      elementBonusIndex++;&lt;br /&gt;
    } else {&lt;br /&gt;
      savedElementDifferences.push(elementDifference);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (!savedElementDifferences.length) {&lt;br /&gt;
    return;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  minElementMalus += maxDifference;&lt;br /&gt;
  savedElementDifferences.sort(compareNumbers);&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; savedElementDifferences.length; index++) {&lt;br /&gt;
    var elementDifference = savedElementDifferences[index];&lt;br /&gt;
&lt;br /&gt;
    elementBonus[elementBonusIndex + index] =&lt;br /&gt;
      10 * Math.max(minElementMalus, elementDifference);&lt;br /&gt;
&lt;br /&gt;
    minElementMalus = Math.min(&lt;br /&gt;
      0,&lt;br /&gt;
      Math.max(minElementMalus, minElementMalus - elementDifference)&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcCriticalHitChance(criticalHitPercentage) {&lt;br /&gt;
  if (criticalHitPercentage &amp;lt;= 9) {&lt;br /&gt;
    return Math.floor((criticalHitPercentage + 5) / 5);&lt;br /&gt;
  }&lt;br /&gt;
  return Math.floor((criticalHitPercentage + 5) / 6);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcCriticalSkillChance(criticalHitPercentage) {&lt;br /&gt;
  if (criticalHitPercentage === 0) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  } else if (criticalHitPercentage &amp;lt;= 9) {&lt;br /&gt;
    return Math.floor((criticalHitPercentage + 7) / 3);&lt;br /&gt;
  }&lt;br /&gt;
  return Math.floor((criticalHitPercentage + 5) / 3);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcPiercingSkillChance(piercingHitPercentage) {&lt;br /&gt;
  if (piercingHitPercentage &amp;lt;= 9) {&lt;br /&gt;
    return Math.floor(piercingHitPercentage / 2);&lt;br /&gt;
  }&lt;br /&gt;
  return 5 + Math.floor((piercingHitPercentage - 10) / 4);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function magicResistanceToCoeff(magicResistance) {&lt;br /&gt;
  if (magicResistance) {&lt;br /&gt;
    return 2000 / (6 * magicResistance + 1000) - 1;&lt;br /&gt;
  }&lt;br /&gt;
  return 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createBattleValues(attacker, victim, battle, skillType) {&lt;br /&gt;
  var {&lt;br /&gt;
    mapping,&lt;br /&gt;
    constants: { polymorphPowerTable, skillPowerTable, marriageTable },&lt;br /&gt;
  } = battle;&lt;br /&gt;
  var calcAttackValues;&lt;br /&gt;
&lt;br /&gt;
  var missPercentage = 0;&lt;br /&gt;
  var attackValueMeleeMagic = 0;&lt;br /&gt;
  var attackValueMarriage = 0;&lt;br /&gt;
  var monsterResistanceMarriage = 0;&lt;br /&gt;
  var monsterResistance = 0;&lt;br /&gt;
  var typeBonus = 0;&lt;br /&gt;
  var raceBonus = 0;&lt;br /&gt;
  var raceResistance = 0;&lt;br /&gt;
  var stoneBonus = 0;&lt;br /&gt;
  var monsterBonus = 0;&lt;br /&gt;
  var elementBonus = [0, 0, 0, 0, 0, 0]; // fire, ice, lightning, earth, darkness, wind, order doesn't matter&lt;br /&gt;
  var defenseMarriage = 0;&lt;br /&gt;
  var damageMultiplier = 1;&lt;br /&gt;
  var useDamage = 1;&lt;br /&gt;
  var defense = victim.defense;&lt;br /&gt;
  var defenseBoost = defense;&lt;br /&gt;
  var magicResistance = 0;&lt;br /&gt;
  var weaponDefense = 0;&lt;br /&gt;
  var tigerStrength = 0;&lt;br /&gt;
  var berserkBonus = 0;&lt;br /&gt;
  var blessingBonus = 0;&lt;br /&gt;
  var fearBonus = 0;&lt;br /&gt;
  var magicAttackValueMeleeMagic = 0;&lt;br /&gt;
  var criticalHitPercentage = attacker.criticalHit;&lt;br /&gt;
  var isPlayerVsPlayer = false;&lt;br /&gt;
  var piercingHitPercentage = attacker.piercingHit;&lt;br /&gt;
  var extraPiercingHitPercentage = Math.max(0, piercingHitPercentage - 100);&lt;br /&gt;
  var averageDamage = 0;&lt;br /&gt;
  var averageDamageResistance = 0;&lt;br /&gt;
  var skillDamage = 0;&lt;br /&gt;
  var skillDamageResistance = 0;&lt;br /&gt;
  var rankBonus = 0;&lt;br /&gt;
  var useDarkProtection = false;&lt;br /&gt;
  var darkProtectionPoint = 0;&lt;br /&gt;
  var defensePercent = 0;&lt;br /&gt;
  var damageBonus = 0;&lt;br /&gt;
  var empireMalus = 0;&lt;br /&gt;
  var sungMaStrBonus = 0;&lt;br /&gt;
  var sungmaStrMalus = 0;&lt;br /&gt;
  var whiteDragonElixir = 0;&lt;br /&gt;
  var steelDragonElixir = 0;&lt;br /&gt;
&lt;br /&gt;
  attacker.statAttackValue = calcStatAttackValue(attacker);&lt;br /&gt;
&lt;br /&gt;
  computePolymorphPoint(attacker, victim, polymorphPowerTable);&lt;br /&gt;
  computeHorse(attacker);&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker)) {&lt;br /&gt;
    if (weaponData.hasOwnProperty(attacker.weapon)) {&lt;br /&gt;
      attacker.weapon = createWeapon(attacker.weapon);&lt;br /&gt;
    } else {&lt;br /&gt;
      attacker.weapon = createWeapon(0);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    attacker.weapon.getValues(attacker.weaponUpgrade);&lt;br /&gt;
&lt;br /&gt;
    attackValueMeleeMagic =&lt;br /&gt;
      attacker.attackValuePercent + Math.min(100, attacker.attackMeleeMagic);&lt;br /&gt;
&lt;br /&gt;
    var weaponType = attacker.weapon.type;&lt;br /&gt;
&lt;br /&gt;
    if (skillType &amp;amp;&amp;amp; attacker.class === &amp;quot;archery&amp;quot;) {&lt;br /&gt;
      if (weaponType !== 2) {&lt;br /&gt;
        useDamage = 0;&lt;br /&gt;
        weaponType = 2;&lt;br /&gt;
      }&lt;br /&gt;
      defense = 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var weaponDefenseName = mapping.defenseWeapon[weaponType];&lt;br /&gt;
    var weaponDefenseBreakName = mapping.breakWeapon[weaponType];&lt;br /&gt;
&lt;br /&gt;
    if (victim.hasOwnProperty(weaponDefenseName)) {&lt;br /&gt;
      weaponDefense = victim[weaponDefenseName];&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isChecked(attacker.whiteDragonElixir)) {&lt;br /&gt;
      whiteDragonElixir = 10;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isPC(victim)) {&lt;br /&gt;
      isPlayerVsPlayer = true;&lt;br /&gt;
&lt;br /&gt;
      if (!skillType) {&lt;br /&gt;
        if (weaponType === 2 &amp;amp;&amp;amp; !isPolymorph(attacker)) {&lt;br /&gt;
          missPercentage = victim.arrowBlock;&lt;br /&gt;
        } else {&lt;br /&gt;
          missPercentage = victim.meleeBlock;&lt;br /&gt;
        }&lt;br /&gt;
        missPercentage +=&lt;br /&gt;
          victim.meleeArrowBlock -&lt;br /&gt;
          (missPercentage * victim.meleeArrowBlock) / 100;&lt;br /&gt;
&lt;br /&gt;
        criticalHitPercentage = calcCriticalHitChance(criticalHitPercentage);&lt;br /&gt;
        berserkBonus = calcBerserkBonus(skillPowerTable, victim);&lt;br /&gt;
        blessingBonus = calcBlessingBonus(skillPowerTable, victim);&lt;br /&gt;
        fearBonus = calcFearBonus(skillPowerTable, victim);&lt;br /&gt;
        averageDamageResistance = victim.averageDamageResistance;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      typeBonus = Math.max(1, attacker.humanBonus - victim.humanResistance);&lt;br /&gt;
      raceBonus = attacker[mapping.raceBonus[victim.race]];&lt;br /&gt;
      raceResistance = victim[mapping.raceResistance[attacker.race]];&lt;br /&gt;
&lt;br /&gt;
      calcElementCoeffPvP(elementBonus, mapping, attacker, victim);&lt;br /&gt;
&lt;br /&gt;
      if (weaponType !== 2 &amp;amp;&amp;amp; attacker.hasOwnProperty(weaponDefenseBreakName)) {&lt;br /&gt;
        weaponDefense -= attacker[weaponDefenseBreakName];&lt;br /&gt;
      }&lt;br /&gt;
    } else {&lt;br /&gt;
      if (isChecked(attacker.isMarried)) {&lt;br /&gt;
        if (isChecked(attacker.loveNecklace)) {&lt;br /&gt;
          attackValueMarriage = getMarriageBonusValue(&lt;br /&gt;
            attacker,&lt;br /&gt;
            marriageTable,&lt;br /&gt;
            &amp;quot;loveNecklace&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isChecked(attacker.loveEarrings)) {&lt;br /&gt;
          criticalHitPercentage += getMarriageBonusValue(&lt;br /&gt;
            attacker,&lt;br /&gt;
            marriageTable,&lt;br /&gt;
            &amp;quot;loveEarrings&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isChecked(attacker.harmonyEarrings)) {&lt;br /&gt;
          piercingHitPercentage += getMarriageBonusValue(&lt;br /&gt;
            attacker,&lt;br /&gt;
            marriageTable,&lt;br /&gt;
            &amp;quot;harmonyEarrings&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (isChecked(attacker.tigerStrength)) {&lt;br /&gt;
        tigerStrength = 40;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      for (var index = 0; index &amp;lt; elementBonus.length; index++) {&lt;br /&gt;
        var elementBonusName = mapping.elementBonus[index];&lt;br /&gt;
        var elementResistanceName = mapping.elementResistance[index];&lt;br /&gt;
&lt;br /&gt;
        if (attacker[elementBonusName] &amp;amp;&amp;amp; victim[elementBonusName]) {&lt;br /&gt;
          elementBonus[index] =&lt;br /&gt;
            50 * (attacker[elementBonusName] - victim[elementResistanceName]);&lt;br /&gt;
        } else {&lt;br /&gt;
          elementBonus[index] = 5 * attacker[elementBonusName];&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      var victimType = victim.type;&lt;br /&gt;
&lt;br /&gt;
      if (victimType !== -1) {&lt;br /&gt;
        typeBonus = attacker[mapping.typeFlag[victimType]];&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      monsterBonus = attacker.monsterBonus;&lt;br /&gt;
&lt;br /&gt;
      if (isStone(victim)) {&lt;br /&gt;
        stoneBonus = attacker.stoneBonus;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (isBoss(victim)) {&lt;br /&gt;
        if (skillType) {&lt;br /&gt;
          skillDamage += attacker.skillBossDamage;&lt;br /&gt;
        } else {&lt;br /&gt;
          averageDamage += attacker.bossDamage;&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (isChecked(attacker.onYohara)) {&lt;br /&gt;
        var sungmaStrDifference = attacker.sungmaStr - attacker.sungmaStrMalus;&lt;br /&gt;
&lt;br /&gt;
        if (sungmaStrDifference &amp;gt;= 0) {&lt;br /&gt;
          sungMaStrBonus = sungmaStrDifference;&lt;br /&gt;
        } else {&lt;br /&gt;
          sungmaStrMalus = 0.5;&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (skillType) {&lt;br /&gt;
      skillDamage += attacker.skillDamage;&lt;br /&gt;
    } else {&lt;br /&gt;
      averageDamage += attacker.averageDamage;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    rankBonus = getRankBonus(attacker);&lt;br /&gt;
    damageBonus = attacker.damageBonus;&lt;br /&gt;
&lt;br /&gt;
    if (isChecked(attacker.empireMalus)) {&lt;br /&gt;
      empireMalus = 1;&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    if (isPC(victim)) {&lt;br /&gt;
      if (isChecked(victim.isMarried)) {&lt;br /&gt;
        if (isChecked(victim.harmonyBracelet)) {&lt;br /&gt;
          monsterResistanceMarriage = getMarriageBonusValue(&lt;br /&gt;
            victim,&lt;br /&gt;
            marriageTable,&lt;br /&gt;
            &amp;quot;harmonyBracelet&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isChecked(victim.harmonyNecklace) &amp;amp;&amp;amp; !skillType) {&lt;br /&gt;
          defenseMarriage = getMarriageBonusValue(&lt;br /&gt;
            victim,&lt;br /&gt;
            marriageTable,&lt;br /&gt;
            &amp;quot;harmonyNecklace&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      monsterResistance = victim.monsterResistance;&lt;br /&gt;
&lt;br /&gt;
      for (var index = 0; index &amp;lt; elementBonus.length; index++) {&lt;br /&gt;
        var elementBonusName = mapping.elementBonus[index];&lt;br /&gt;
        var elementResistanceName = mapping.elementResistance[index];&lt;br /&gt;
&lt;br /&gt;
        if (attacker[elementBonusName]) {&lt;br /&gt;
          elementBonus[index] =&lt;br /&gt;
            80 * (attacker[elementBonusName] - victim[elementResistanceName]);&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (!skillType) {&lt;br /&gt;
        if (isMeleeAttacker(attacker)) {&lt;br /&gt;
          missPercentage = victim.meleeBlock;&lt;br /&gt;
          averageDamageResistance = victim.averageDamageResistance;&lt;br /&gt;
          berserkBonus = calcBerserkBonus(skillPowerTable, victim);&lt;br /&gt;
          blessingBonus = calcBlessingBonus(skillPowerTable, victim);&lt;br /&gt;
          fearBonus = calcFearBonus(skillPowerTable, victim);&lt;br /&gt;
        } else if (isRangeAttacker(attacker)) {&lt;br /&gt;
          missPercentage = victim.arrowBlock;&lt;br /&gt;
          weaponDefense = victim.arrowDefense;&lt;br /&gt;
          averageDamageResistance = victim.averageDamageResistance;&lt;br /&gt;
          berserkBonus = calcBerserkBonus(skillPowerTable, victim);&lt;br /&gt;
          blessingBonus = calcBlessingBonus(skillPowerTable, victim);&lt;br /&gt;
          fearBonus = calcFearBonus(skillPowerTable, victim);&lt;br /&gt;
        } else if (isMagicAttacker(attacker)) {&lt;br /&gt;
          missPercentage = victim.arrowBlock;&lt;br /&gt;
          skillDamageResistance = victim.skillDamageResistance;&lt;br /&gt;
          magicResistance = victim.magicResistance;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        missPercentage +=&lt;br /&gt;
          victim.meleeArrowBlock -&lt;br /&gt;
          (missPercentage * victim.meleeArrowBlock) / 100;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    typeBonus = 1;&lt;br /&gt;
    damageMultiplier = attacker.damageMultiplier;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillType) {&lt;br /&gt;
    criticalHitPercentage = calcCriticalSkillChance(criticalHitPercentage);&lt;br /&gt;
    piercingHitPercentage = calcPiercingSkillChance(piercingHitPercentage);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (isPC(victim)) {&lt;br /&gt;
    if (!skillType &amp;amp;&amp;amp; isChecked(victim.biologist70)) {&lt;br /&gt;
      defenseBoost = Math.floor((defenseBoost * 110) / 100);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    criticalHitPercentage = Math.max(&lt;br /&gt;
      0,&lt;br /&gt;
      criticalHitPercentage - victim.criticalHitResistance&lt;br /&gt;
    );&lt;br /&gt;
    piercingHitPercentage = Math.max(&lt;br /&gt;
      0,&lt;br /&gt;
      piercingHitPercentage - victim.piercingHitResistance&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    if (skillType) {&lt;br /&gt;
      skillDamageResistance = victim.skillDamageResistance;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      victim.useDarkProtection &amp;amp;&amp;amp;&lt;br /&gt;
      victim.class === &amp;quot;black_magic&amp;quot; &amp;amp;&amp;amp;&lt;br /&gt;
      victim.skillDarkProtection&lt;br /&gt;
    ) {&lt;br /&gt;
      useDarkProtection = true;&lt;br /&gt;
      darkProtectionPoint = calcDarkProtectionPoint(skillPowerTable, victim);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isMagicClass(victim)) {&lt;br /&gt;
      defensePercent = (-2 * victim.magicDefense * victim.defensePercent) / 100;&lt;br /&gt;
    } else {&lt;br /&gt;
      defensePercent = (-2 * defenseBoost * victim.defensePercent) / 100;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isChecked(victim.steelDragonElixir)) {&lt;br /&gt;
      steelDragonElixir = 10;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillType === &amp;quot;magic&amp;quot;) {&lt;br /&gt;
    attackValueMeleeMagic = 0;&lt;br /&gt;
    magicAttackValueMeleeMagic =&lt;br /&gt;
      attacker.attackMagic + Math.min(100, attacker.attackMeleeMagic);&lt;br /&gt;
    attackValueMarriage = 0;&lt;br /&gt;
    defense = 0;&lt;br /&gt;
    if (isDispell(attacker, 6)) {&lt;br /&gt;
      typeBonus = 0;&lt;br /&gt;
      raceBonus = 0;&lt;br /&gt;
      raceResistance = 0;&lt;br /&gt;
      stoneBonus = 0;&lt;br /&gt;
      monsterBonus = 0;&lt;br /&gt;
      for (var index = 0; index &amp;lt; elementBonus.length; index++) {&lt;br /&gt;
        elementBonus[index] = 0;&lt;br /&gt;
      }&lt;br /&gt;
    } else {&lt;br /&gt;
      magicResistance = victim.magicResistance;&lt;br /&gt;
    }&lt;br /&gt;
    weaponDefense = 0;&lt;br /&gt;
    calcAttackValues = calcMagicAttackValue;&lt;br /&gt;
  } else {&lt;br /&gt;
    calcAttackValues = calcSecondaryAttackValue;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  missPercentage = Math.min(100, missPercentage);&lt;br /&gt;
  criticalHitPercentage = Math.min(criticalHitPercentage, 100);&lt;br /&gt;
  piercingHitPercentage = Math.min(piercingHitPercentage, 100);&lt;br /&gt;
&lt;br /&gt;
  const bonusValues = {&lt;br /&gt;
    missPercentage: missPercentage,&lt;br /&gt;
    skipCriticalStep: [&lt;br /&gt;
      !Boolean(100 - criticalHitPercentage),&lt;br /&gt;
      !Boolean(criticalHitPercentage),&lt;br /&gt;
    ],&lt;br /&gt;
    skipPiercingStep: [&lt;br /&gt;
      !Boolean(100 - piercingHitPercentage),&lt;br /&gt;
      !Boolean(piercingHitPercentage),&lt;br /&gt;
    ],&lt;br /&gt;
    weaponBonusCoeff: 1,&lt;br /&gt;
    attackValueCoeff: 100 + attackValueMeleeMagic,&lt;br /&gt;
    attackValueMarriage: attackValueMarriage,&lt;br /&gt;
    monsterResistanceMarriageCoeff: 100 - monsterResistanceMarriage,&lt;br /&gt;
    monsterResistanceCoeff: 100 - monsterResistance,&lt;br /&gt;
    typeBonusCoeff: typeBonus,&lt;br /&gt;
    raceBonusCoeff: raceBonus,&lt;br /&gt;
    raceResistanceCoeff: raceResistance,&lt;br /&gt;
    stoneBonusCoeff: stoneBonus,&lt;br /&gt;
    monsterBonusCoeff: monsterBonus,&lt;br /&gt;
    elementBonusCoeff: elementBonus,&lt;br /&gt;
    damageMultiplier: damageMultiplier,&lt;br /&gt;
    useDamage: useDamage,&lt;br /&gt;
    defense: defense,&lt;br /&gt;
    defenseBoost: defenseBoost,&lt;br /&gt;
    defenseMarriage: defenseMarriage,&lt;br /&gt;
    tigerStrengthCoeff: 100 + tigerStrength,&lt;br /&gt;
    magicResistanceCoeff: magicResistanceToCoeff(magicResistance),&lt;br /&gt;
    weaponDefenseCoeff: 100 - weaponDefense,&lt;br /&gt;
    berserkBonusCoeff: 100 + berserkBonus,&lt;br /&gt;
    blessingBonusCoeff: 100 - blessingBonus,&lt;br /&gt;
    fearBonusCoeff: 100 - fearBonus,&lt;br /&gt;
    magicAttackValueCoeff: 100 + magicAttackValueMeleeMagic,&lt;br /&gt;
    extraPiercingHitCoeff: 5 * extraPiercingHitPercentage,&lt;br /&gt;
    averageDamageCoeff: 100 + averageDamage,&lt;br /&gt;
    averageDamageResistanceCoeff: 100 - Math.min(99, averageDamageResistance),&lt;br /&gt;
    skillDamageCoeff: 100 + skillDamage,&lt;br /&gt;
    skillDamageResistanceCoeff: 100 - Math.min(99, skillDamageResistance),&lt;br /&gt;
    useDarkProtection: useDarkProtection,&lt;br /&gt;
    darkProtectionPoint: darkProtectionPoint,&lt;br /&gt;
    darkProtectionSp: victim.darkProtectionSp,&lt;br /&gt;
    rankBonusCoeff: 100 + rankBonus,&lt;br /&gt;
    defensePercent: Math.floor(defensePercent),&lt;br /&gt;
    damageBonusCoeff: Math.min(20, damageBonus),&lt;br /&gt;
    empireMalusCoeff: 10 - empireMalus,&lt;br /&gt;
    sungMaStrBonusCoeff: 10000 + sungMaStrBonus,&lt;br /&gt;
    sungmaStrMalusCoeff: sungmaStrMalus,&lt;br /&gt;
    whiteDragonElixirCoeff: 100 + whiteDragonElixir,&lt;br /&gt;
    steelDragonElixirCoeff: 100 - steelDragonElixir,&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  const damageTypeWeights = [&lt;br /&gt;
    (100 - criticalHitPercentage) *&lt;br /&gt;
      (100 - piercingHitPercentage) *&lt;br /&gt;
      (100 - missPercentage),&lt;br /&gt;
    criticalHitPercentage *&lt;br /&gt;
      (100 - piercingHitPercentage) *&lt;br /&gt;
      (100 - missPercentage),&lt;br /&gt;
    (100 - criticalHitPercentage) *&lt;br /&gt;
      piercingHitPercentage *&lt;br /&gt;
      (100 - missPercentage),&lt;br /&gt;
    criticalHitPercentage * piercingHitPercentage * (100 - missPercentage),&lt;br /&gt;
  ];&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    attacker: attacker,&lt;br /&gt;
    victim: victim,&lt;br /&gt;
    attackFactor: calcAttackFactor(attacker, victim),&lt;br /&gt;
    mainAttackValue: calcMainAttackValue(attacker),&lt;br /&gt;
    attackValues: calcAttackValues(attacker, isPlayerVsPlayer),&lt;br /&gt;
    bonusValues: bonusValues,&lt;br /&gt;
    damageTypeWeights: damageTypeWeights,&lt;br /&gt;
    attackTypeMapping: mapping.attackType,&lt;br /&gt;
    damageWeightedByType: {&lt;br /&gt;
      normalHit: {},&lt;br /&gt;
      criticalHit: {},&lt;br /&gt;
      piercingHit: {},&lt;br /&gt;
      criticalPiercingHit: {},&lt;br /&gt;
    },&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateBattleValues(battleValues, skillFormula, skillInfo) {&lt;br /&gt;
  var weaponBonus = 0;&lt;br /&gt;
  var skillWard = 0;&lt;br /&gt;
  var skillBonus = 0;&lt;br /&gt;
  var skillBonusByBonus = 0;&lt;br /&gt;
  var { attacker: attacker, bonusValues: bonusValues } = battleValues;&lt;br /&gt;
  var {&lt;br /&gt;
    range: [minVariation, maxVariation],&lt;br /&gt;
  } = skillInfo;&lt;br /&gt;
  var variationLength = maxVariation - minVariation + 1;&lt;br /&gt;
&lt;br /&gt;
  if (skillInfo.hasOwnProperty(&amp;quot;weaponBonus&amp;quot;)) {&lt;br /&gt;
    var [weaponType, weaponBonusValue] = skillInfo.weaponBonus;&lt;br /&gt;
&lt;br /&gt;
    if (weaponType === attacker.weapon.type) {&lt;br /&gt;
      weaponBonus = weaponBonusValue;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillInfo.skillBonus) {&lt;br /&gt;
    skillBonus = skillInfo.skillBonus;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillInfo.skillWard) {&lt;br /&gt;
    skillWard = skillInfo.skillWard;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillInfo.skillBonusByBonus) {&lt;br /&gt;
    skillBonusByBonus = skillInfo.skillBonusByBonus;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillInfo.removeWeaponReduction) {&lt;br /&gt;
    bonusValues.weaponDefenseCoeff = 100;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  bonusValues.weaponBonusCoeff = 100 + weaponBonus;&lt;br /&gt;
  bonusValues.skillWardCoeff = 1 - skillWard / 100;&lt;br /&gt;
  bonusValues.skillBonusCoeff = 1 + skillBonus / 100;&lt;br /&gt;
  bonusValues.skillBonusByBonusCoeff = 100 + skillBonusByBonus;&lt;br /&gt;
&lt;br /&gt;
  battleValues.skillFormula = skillFormula;&lt;br /&gt;
  battleValues.skillRange = skillInfo.range;&lt;br /&gt;
  battleValues.attackValues.totalCardinal *= variationLength;&lt;br /&gt;
  battleValues.attackValues.possibleDamageCount *= variationLength;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcWeights(minValue, maxValue, minInterval) {&lt;br /&gt;
  var firstWeightLimit = minValue + minInterval - 1;&lt;br /&gt;
  var lastWeightsLimit = maxValue - minInterval + 1;&lt;br /&gt;
  var weights = [];&lt;br /&gt;
&lt;br /&gt;
  for (var value = minValue; value &amp;lt; firstWeightLimit; value++) {&lt;br /&gt;
    weights.push(value - minValue + 1);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (var value = firstWeightLimit; value &amp;lt;= lastWeightsLimit; value++) {&lt;br /&gt;
    weights.push(minInterval);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (var value = lastWeightsLimit + 1; value &amp;lt;= maxValue; value++) {&lt;br /&gt;
    weights.push(maxValue - value + 1);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return weights;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcBerserkBonus(skillPowerTable, victim) {&lt;br /&gt;
  if (!isChecked(victim.useBerserk) || victim.class !== &amp;quot;body&amp;quot;) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var skillPower = getSkillPower(victim.skillBerserk, skillPowerTable);&lt;br /&gt;
&lt;br /&gt;
  if (!skillPower) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var berserkBonus = Math.floor(skillPower * 25);&lt;br /&gt;
&lt;br /&gt;
  return berserkBonus;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcBlessingBonus(skillPowerTable, victim) {&lt;br /&gt;
  if (!isChecked(victim.isBlessed)) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var int = victim.intBlessing;&lt;br /&gt;
  var dex = victim.dexBlessing;&lt;br /&gt;
  var skillPower = getSkillPower(victim.skillBlessing, skillPowerTable);&lt;br /&gt;
&lt;br /&gt;
  if (!skillPower) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var blessingBonus = floorMultiplication(&lt;br /&gt;
    ((int * 0.3 + 5) * (2 * skillPower + 0.5) + 0.3 * dex) / (skillPower + 2.3),&lt;br /&gt;
    1&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  if (victim.class === &amp;quot;dragon&amp;quot; &amp;amp;&amp;amp; isChecked(victim.blessingOnself)) {&lt;br /&gt;
    blessingBonus = floorMultiplication(blessingBonus, 1.1);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return blessingBonus;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcFearBonus(skillPowerTable, victim) {&lt;br /&gt;
  if (!isChecked(victim.useFear) || victim.class !== &amp;quot;weaponary&amp;quot;) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var skillPower = getSkillPower(victim.skillFear, skillPowerTable);&lt;br /&gt;
&lt;br /&gt;
  if (!skillPower) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var fearBonus = 5 + Math.floor(skillPower * 20);&lt;br /&gt;
&lt;br /&gt;
  return fearBonus;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcDarkProtectionPoint(skillPowerTable, victim) {&lt;br /&gt;
  var skillPower = getSkillPower(victim.skillDarkProtection, skillPowerTable);&lt;br /&gt;
&lt;br /&gt;
  return floorMultiplication(100 - victim.int * 0.84 * skillPower, 1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSkillFormula(battle, skillId, battleValues, removeSkillVariation) {&lt;br /&gt;
  var { attacker, victim, attackFactor } = battleValues;&lt;br /&gt;
  var skillPowerTable = battle.constants.skillPowerTable;&lt;br /&gt;
&lt;br /&gt;
  var skillFormula;&lt;br /&gt;
  var skillInfo = { range: [0, 0] };&lt;br /&gt;
&lt;br /&gt;
  var { class: attackerClass, level: lv, vit, str, int, dex } = attacker;&lt;br /&gt;
&lt;br /&gt;
  if (skillId &amp;lt;= 9) {&lt;br /&gt;
    var skillPower = getSkillPower(&lt;br /&gt;
      attacker[&amp;quot;attackSkill&amp;quot; + skillId],&lt;br /&gt;
      skillPowerTable&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    var improvedBySkillBonus = false;&lt;br /&gt;
    var improvedByBonus = false;&lt;br /&gt;
&lt;br /&gt;
    if (attackerClass === &amp;quot;body&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Triple lacération&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.1 * atk + (0.5 * atk + 1.5 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Moulinet à l'épée&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              3 * atk + (0.8 * atk + 5 * str + 3 * dex + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Accélération&lt;br /&gt;
        case 5:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * atk + (atk + dex * 3 + str * 7 + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Volonté de vivre&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              (3 * atk + (atk + 1.5 * str) * skillPower) * 1.07,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          break;&lt;br /&gt;
        // Tremblement de terre&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              3 * atk +&lt;br /&gt;
                (0.9 * atk + variation + 5 * str + 3 * dex + lv) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;mental&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Attaque de l'esprit&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2.3 * atk + (4 * atk + 4 * str + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Attaque de la paume&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2.3 * atk + (3 * atk + 4 * str + 3 * vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Charge&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * atk + (2 * atk + 2 * dex + 2 * vit + 4 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          break;&lt;br /&gt;
        // Coup d'épée&lt;br /&gt;
        case 5:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * atk + (atk + 3 * dex + 5 * str + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Orbe de l'épée&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              (2 * atk + (2 * atk + 2 * dex + 2 * vit + 4 * str) * skillPower) *&lt;br /&gt;
                1.1,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          break;&lt;br /&gt;
        // Tremblement de terre&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              3 * atk +&lt;br /&gt;
                (0.9 * atk + variation + 5 * str + 3 * dex + lv) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;blade_fight&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Embuscade&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk + (1.2 * atk + variation + 4 * dex + 4 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [1, 50];&lt;br /&gt;
          skillInfo.range = [500, 700];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Attaque rapide&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk + (1.6 * atk + variation + 7 * dex + 7 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [1, 35];&lt;br /&gt;
          skillInfo.range = [200, 300];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Dague filante&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * atk + (0.5 * atk + 9 * dex + 7 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Brume empoisonnée&lt;br /&gt;
        case 5:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * lv + (atk + 3 * str + 18 * dex) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Poison insidieux&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              (2 * lv + (atk + 3 * str + 18 * dex) * skillPower) * 1.1,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          break;&lt;br /&gt;
        // Étoiles brillantes&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk + (1.7 * atk + variation + 6 * dex + 5 * lv) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;archery&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Tir à répétition&lt;br /&gt;
        // case 1:&lt;br /&gt;
        //   skillFormula = function (atk) {&lt;br /&gt;
        //     return floorMultiplication(&lt;br /&gt;
        //       atk + 0.2 * atk * Math.floor(2 + 6 * skillPower) + (0.8 * atk + 8 * dex * attackFactor + 2 * int) * skillPower,&lt;br /&gt;
        //       1&lt;br /&gt;
        //     );&lt;br /&gt;
        //   };&lt;br /&gt;
        //   improvedByBonus = true;&lt;br /&gt;
        //   break;&lt;br /&gt;
        // Pluie de flèches&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk + (1.7 * atk + 5 * dex + str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Flèche de feu&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.5 * atk + (2.6 * atk + 0.9 * int + variation) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [100, 300];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Foulée de plume&lt;br /&gt;
        case 4:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              (3 * dex + 200 + 2 * str + 2 * int) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.removeWeaponReduction = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Flèche empoisonnée&lt;br /&gt;
        case 5:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk +&lt;br /&gt;
                (1.4 * atk + variation + 7 * dex + 4 * str + 4 * int) *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [100, 200];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Coup étincelant&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              (atk +&lt;br /&gt;
                (1.2 * atk + variation + 6 * dex + 3 * str + 3 * int) *&lt;br /&gt;
                  skillPower) *&lt;br /&gt;
                1.2,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [100, 200];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Tir tempête&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.9 * atk + (2.6 * atk + variation) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;weaponary&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Toucher brûlant&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk +&lt;br /&gt;
                2 * lv +&lt;br /&gt;
                2 * int +&lt;br /&gt;
                (2 * atk + 4 * str + 14 * int) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Tourbillon du dragon&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.1 * atk +&lt;br /&gt;
                2 * lv +&lt;br /&gt;
                2 * int +&lt;br /&gt;
                (1.5 * atk + str + 12 * int) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Contre-sort&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              40 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                2 * int +&lt;br /&gt;
                (10 * int + 7 * mav + variation) * attackFactor * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [50, 100];&lt;br /&gt;
          break;&lt;br /&gt;
        // Coup démoniaque&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.9 * atk + (2.6 * atk + variation) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;black_magic&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Attaque des ténèbres&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              40 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                2 * int +&lt;br /&gt;
                (13 * int + 6 * mav + variation) * attackFactor * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [50, 100];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Attaque de flammes&lt;br /&gt;
        // case 2:&lt;br /&gt;
        //   skillFormula = function (mav, variation) {&lt;br /&gt;
        //     return floorMultiplication(&lt;br /&gt;
        //       5 * lv + 2 * int + (7 * int + 8 * mav + 4 * str + 2 * vit + variation) * skillPower,&lt;br /&gt;
        //       1&lt;br /&gt;
        //     );&lt;br /&gt;
        //   };&lt;br /&gt;
        //   skillInfo.range = [180, 100];&lt;br /&gt;
        //   improvedByBonus = true;&lt;br /&gt;
        //   break;&lt;br /&gt;
        // Esprit de flammes&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              30 +&lt;br /&gt;
                2 * lv +&lt;br /&gt;
                2 * int +&lt;br /&gt;
                (7 * int + 6 * mav + variation) * attackFactor * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [200, 500];&lt;br /&gt;
          break;&lt;br /&gt;
        // Frappe de l'esprit&lt;br /&gt;
        // case 5:&lt;br /&gt;
        //   skillFormula = function (mav, variation) {&lt;br /&gt;
        //     return floorMultiplication(&lt;br /&gt;
        //       40 + 2 * lv + 2 * int + (2 * vit + 2 * dex + 13 * int + 6 * mav + variation) * attackFactor * skillPower,&lt;br /&gt;
        //       1&lt;br /&gt;
        //     );&lt;br /&gt;
        //   };&lt;br /&gt;
        //   skillInfo.range = [180, 200];&lt;br /&gt;
        //   break;&lt;br /&gt;
        // Orbe des ténèbres&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (mav) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              120 +&lt;br /&gt;
                6 * lv +&lt;br /&gt;
                (5 * vit + 5 * dex + 29 * int + 9 * mav) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Vague mortelle&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              120 +&lt;br /&gt;
                6 * lv +&lt;br /&gt;
                (5 * vit + 5 * dex + 30 * int + variation + 9 * mav) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;dragon&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Talisman volant&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (mav) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              70 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                (18 * int + 7 * str + 5 * mav + 50) * attackFactor * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [4, 10];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Dragon chassant&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (mav) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              60 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                (16 * int + 6 * dex + 6 * mav + 120) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [4, 10];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Rugissement du dragon&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (mav) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              70 +&lt;br /&gt;
                3 * lv +&lt;br /&gt;
                (20 * int + 3 * str + 10 * mav + 100) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [4, 10];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Météore&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              120 +&lt;br /&gt;
                6 * lv +&lt;br /&gt;
                (5 * vit + 5 * dex + 30 * int + variation + 9 * mav) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;heal&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Jet de foudre&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              60 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                (8 * int + 2 * dex + 8 * mav + variation) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [6, 10];&lt;br /&gt;
          skillInfo.range = [5 * int, 15 * int];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Invocation de foudre&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              40 +&lt;br /&gt;
                4 * lv +&lt;br /&gt;
                (13 * int + 2 * str + 10 * mav + variation) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [6, 10];&lt;br /&gt;
          skillInfo.range = [5 * int, 16 * int];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Griffe de foudre&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              50 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                (8 * int + 2 * str + 8 * mav + variation) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 800];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;lycan&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Déchiqueter&lt;br /&gt;
        // case 1:&lt;br /&gt;
        //   skillFormula = function (atk) {&lt;br /&gt;
        //     return floorMultiplication(&lt;br /&gt;
        //       1.1 * atk + (0.3 * atk + 1.5 * str) * skillPower,&lt;br /&gt;
        //       1&lt;br /&gt;
        //     );&lt;br /&gt;
        //   };&lt;br /&gt;
        //   skillInfo.weaponBonus = [5, 54];&lt;br /&gt;
        //   improvedByBonus = true;&lt;br /&gt;
        //   break;&lt;br /&gt;
        // Souffle de loup&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * atk + (atk + 3 * dex + 5 * str + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [5, 35];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Bond de loup&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk + (1.6 * atk + 200 + 7 * dex + 7 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [5, 35];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Griffe de loup&lt;br /&gt;
        case 4:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              3 * atk + (0.8 * atk + 6 * str + 2 * dex + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Tempête cinglante&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.8 * atk +&lt;br /&gt;
                (atk + 6 * dex + variation + 3 * str + lv) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
    if (improvedBySkillBonus) {&lt;br /&gt;
      skillInfo.skillBonus =&lt;br /&gt;
        16 * getSkillPower(attacker.skillBonus, skillPowerTable);&lt;br /&gt;
&lt;br /&gt;
      var skillWardChoice = victim.skillWardChoice;&lt;br /&gt;
&lt;br /&gt;
      if (skillWardChoice &amp;amp;&amp;amp; skillWardChoice === attackerClass) {&lt;br /&gt;
        skillInfo.skillWard =&lt;br /&gt;
          24 * getSkillPower(victim.skillWard, skillPowerTable);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (improvedByBonus) {&lt;br /&gt;
      skillInfo.skillBonusByBonus = attacker[&amp;quot;skillBonus&amp;quot; + skillId];&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (removeSkillVariation) {&lt;br /&gt;
      var averageVariation = (skillInfo.range[0] + skillInfo.range[0]) / 2;&lt;br /&gt;
      skillInfo.range = [averageVariation, averageVariation];&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    var skillPower = getSkillPower(&lt;br /&gt;
      attacker[&amp;quot;horseSkill&amp;quot; + skillId],&lt;br /&gt;
      skillPowerTable&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    switch (skillId) {&lt;br /&gt;
      // Combat équestre&lt;br /&gt;
      case 137:&lt;br /&gt;
        skillFormula = function (atk) {&lt;br /&gt;
          return floorMultiplication(atk + 2 * atk * skillPower, 1);&lt;br /&gt;
        };&lt;br /&gt;
        break;&lt;br /&gt;
      // Charge à cheval&lt;br /&gt;
      case 138:&lt;br /&gt;
        skillFormula = function (atk) {&lt;br /&gt;
          return floorMultiplication(&lt;br /&gt;
            2.4 * (200 + 1.5 * lv) + 600 * skillPower,&lt;br /&gt;
            1&lt;br /&gt;
          );&lt;br /&gt;
        };&lt;br /&gt;
        break;&lt;br /&gt;
      // Vague de Pouvoir&lt;br /&gt;
      case 139:&lt;br /&gt;
        skillFormula = function (atk) {&lt;br /&gt;
          return floorMultiplication(&lt;br /&gt;
            2 * (200 + 1.5 * lv) + 600 * skillPower,&lt;br /&gt;
            1&lt;br /&gt;
          );&lt;br /&gt;
        };&lt;br /&gt;
        break;&lt;br /&gt;
      // Grêle de flèches&lt;br /&gt;
      case 140:&lt;br /&gt;
        skillFormula = function (atk) {&lt;br /&gt;
          return floorMultiplication(atk + 2 * atk * skillPower, 1);&lt;br /&gt;
        };&lt;br /&gt;
        break;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  updateBattleValues(battleValues, skillFormula, skillInfo);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcMagicAttackValueAugmentation(&lt;br /&gt;
  magicAttackValueWeapon,&lt;br /&gt;
  magicAttackValueBonus&lt;br /&gt;
) {&lt;br /&gt;
  if (magicAttackValueBonus) {&lt;br /&gt;
    return Math.max(&lt;br /&gt;
      1,&lt;br /&gt;
      0.0025056 *&lt;br /&gt;
        magicAttackValueBonus ** 0.602338 *&lt;br /&gt;
        magicAttackValueWeapon ** 1.20476&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
  return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getMagicAttackValueAugmentation(&lt;br /&gt;
  minMagicAttackValue,&lt;br /&gt;
  maxMagicAttackValue,&lt;br /&gt;
  magicAttackValueBonus&lt;br /&gt;
) {&lt;br /&gt;
  var magicAttackValueAugmentation = [];&lt;br /&gt;
&lt;br /&gt;
  for (&lt;br /&gt;
    var magicAttackValue = minMagicAttackValue;&lt;br /&gt;
    magicAttackValue &amp;lt;= maxMagicAttackValue;&lt;br /&gt;
    magicAttackValue++&lt;br /&gt;
  ) {&lt;br /&gt;
    magicAttackValueAugmentation.push(&lt;br /&gt;
      calcMagicAttackValueAugmentation(magicAttackValue, magicAttackValueBonus)&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return magicAttackValueAugmentation;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcPhysicalDamage(battleValues) {&lt;br /&gt;
  const {&lt;br /&gt;
    attackFactor,&lt;br /&gt;
    mainAttackValue,&lt;br /&gt;
    attackValues: {&lt;br /&gt;
      minAttackValue,&lt;br /&gt;
      maxAttackValue,&lt;br /&gt;
      attackValueOther,&lt;br /&gt;
      weights,&lt;br /&gt;
      criticalAttackRange,&lt;br /&gt;
    },&lt;br /&gt;
    bonusValues,&lt;br /&gt;
    damageWeightedByType,&lt;br /&gt;
  } = battleValues;&lt;br /&gt;
&lt;br /&gt;
  const savedDamage = {};&lt;br /&gt;
&lt;br /&gt;
  if (bonusValues.missPercentage) {&lt;br /&gt;
    damageWeightedByType.miss = bonusValues.missPercentage / 100;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (&lt;br /&gt;
    let attackValue = minAttackValue;&lt;br /&gt;
    attackValue &amp;lt;= maxAttackValue;&lt;br /&gt;
    attackValue++&lt;br /&gt;
  ) {&lt;br /&gt;
    const weight = weights[attackValue - minAttackValue];&lt;br /&gt;
    const damageByType = [[], [], [], []];&lt;br /&gt;
    const currentDamageInfo = [weight, damageByType];&lt;br /&gt;
&lt;br /&gt;
    const secondaryAttackValue = 2 * attackValue + attackValueOther;&lt;br /&gt;
    const rawDamage =&lt;br /&gt;
      mainAttackValue + floorMultiplication(attackFactor, secondaryAttackValue);&lt;br /&gt;
&lt;br /&gt;
    const damageWithPrimaryBonuses = calcDamageWithPrimaryBonuses(&lt;br /&gt;
      rawDamage,&lt;br /&gt;
      bonusValues&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    const minPiercingDamage =&lt;br /&gt;
      damageWithPrimaryBonuses -&lt;br /&gt;
      bonusValues.defenseBoost -&lt;br /&gt;
      bonusValues.defenseMarriage;&lt;br /&gt;
&lt;br /&gt;
    const damageValues =&lt;br /&gt;
      minPiercingDamage &amp;lt;= 2 ? [1, 2, 3, 4, 5] : [minPiercingDamage];&lt;br /&gt;
&lt;br /&gt;
    for (const damage of damageValues) {&lt;br /&gt;
      saveFinalDamage(&lt;br /&gt;
        damage,&lt;br /&gt;
        minPiercingDamage,&lt;br /&gt;
        damageWithPrimaryBonuses,&lt;br /&gt;
        bonusValues,&lt;br /&gt;
        criticalAttackRange,&lt;br /&gt;
        damageByType&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    savedDamage[attackValue] = currentDamageInfo;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  processSavedDamage(savedDamage, damageWeightedByType, battleValues);&lt;br /&gt;
&lt;br /&gt;
  return damageWeightedByType;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcPhysicalSkillDamage(battleValues) {&lt;br /&gt;
  const {&lt;br /&gt;
    attackFactor,&lt;br /&gt;
    mainAttackValue,&lt;br /&gt;
    attackValues: {&lt;br /&gt;
      minAttackValue,&lt;br /&gt;
      maxAttackValue,&lt;br /&gt;
      attackValueOther,&lt;br /&gt;
      weights,&lt;br /&gt;
      criticalAttackRange,&lt;br /&gt;
    },&lt;br /&gt;
    bonusValues,&lt;br /&gt;
    damageWeightedByType,&lt;br /&gt;
    skillFormula,&lt;br /&gt;
    skillRange: [minVariation, maxVariation],&lt;br /&gt;
  } = battleValues;&lt;br /&gt;
&lt;br /&gt;
  const savedDamage = {};&lt;br /&gt;
&lt;br /&gt;
  for (&lt;br /&gt;
    let attackValue = minAttackValue;&lt;br /&gt;
    attackValue &amp;lt;= maxAttackValue;&lt;br /&gt;
    attackValue++&lt;br /&gt;
  ) {&lt;br /&gt;
    const weight = weights[attackValue - minAttackValue];&lt;br /&gt;
&lt;br /&gt;
    const secondaryAttackValue = 2 * attackValue + attackValueOther;&lt;br /&gt;
    const rawDamage =&lt;br /&gt;
      mainAttackValue + floorMultiplication(attackFactor, secondaryAttackValue);&lt;br /&gt;
&lt;br /&gt;
    const damageWithPrimaryBonuses = calcDamageWithPrimaryBonuses(&lt;br /&gt;
      rawDamage,&lt;br /&gt;
      bonusValues&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    const damageValues =&lt;br /&gt;
      damageWithPrimaryBonuses &amp;lt;= 2&lt;br /&gt;
        ? [1, 2, 3, 4, 5]&lt;br /&gt;
        : [damageWithPrimaryBonuses];&lt;br /&gt;
&lt;br /&gt;
    for (let variation = minVariation; variation &amp;lt;= maxVariation; variation++) {&lt;br /&gt;
      for (const damage of damageValues) {&lt;br /&gt;
        const damageWithFormula = skillFormula(&lt;br /&gt;
          damage * bonusValues.useDamage,&lt;br /&gt;
          variation&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        let damageKey = damageWithFormula;&lt;br /&gt;
&lt;br /&gt;
        if (damageWithPrimaryBonuses &amp;lt; 0) {&lt;br /&gt;
          damageKey = `${damageWithFormula}_${Math.abs(&lt;br /&gt;
            damageWithPrimaryBonuses&lt;br /&gt;
          )}`;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        const entry = savedDamage[damageKey];&lt;br /&gt;
&lt;br /&gt;
        if (entry) {&lt;br /&gt;
          entry[0] += weight;&lt;br /&gt;
          continue;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        const damageByType = [[], [], [], []];&lt;br /&gt;
        const currentDamageInfo = [weight, damageByType];&lt;br /&gt;
&lt;br /&gt;
        const finalDamage = Math.floor(&lt;br /&gt;
          (damageWithFormula * bonusValues.weaponBonusCoeff) / 100&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        saveFinalSkillDamage(&lt;br /&gt;
          finalDamage,&lt;br /&gt;
          damageWithPrimaryBonuses,&lt;br /&gt;
          bonusValues,&lt;br /&gt;
          criticalAttackRange,&lt;br /&gt;
          damageByType&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        savedDamage[damageKey] = currentDamageInfo;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  processSavedDamage(savedDamage, damageWeightedByType, battleValues);&lt;br /&gt;
&lt;br /&gt;
  return damageWeightedByType;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcMagicSkillDamage(battleValues) {&lt;br /&gt;
  const {&lt;br /&gt;
    attackValues: {&lt;br /&gt;
      minMagicAttackValue,&lt;br /&gt;
      maxMagicAttackValue,&lt;br /&gt;
      magicAttackValueAugmentation,&lt;br /&gt;
      weights,&lt;br /&gt;
      criticalAttackRange,&lt;br /&gt;
    },&lt;br /&gt;
    bonusValues,&lt;br /&gt;
    damageWeightedByType,&lt;br /&gt;
    skillFormula,&lt;br /&gt;
    skillRange: [minVariation, maxVariation],&lt;br /&gt;
  } = battleValues;&lt;br /&gt;
&lt;br /&gt;
  const savedDamage = {};&lt;br /&gt;
&lt;br /&gt;
  for (&lt;br /&gt;
    let magicAttackValue = minMagicAttackValue;&lt;br /&gt;
    magicAttackValue &amp;lt;= maxMagicAttackValue;&lt;br /&gt;
    magicAttackValue++&lt;br /&gt;
  ) {&lt;br /&gt;
    const index = magicAttackValue - minMagicAttackValue;&lt;br /&gt;
    const weight = weights[index];&lt;br /&gt;
&lt;br /&gt;
    for (let variation = minVariation; variation &amp;lt;= maxVariation; variation++) {&lt;br /&gt;
      const rawDamage = skillFormula(&lt;br /&gt;
        magicAttackValue + magicAttackValueAugmentation[index],&lt;br /&gt;
        variation&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      const entry = savedDamage[rawDamage];&lt;br /&gt;
&lt;br /&gt;
      if (entry) {&lt;br /&gt;
        entry[0] += weight;&lt;br /&gt;
        continue;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      const damageByType = [[], [], [], []];&lt;br /&gt;
      const currentDamageInfo = [weight, damageByType];&lt;br /&gt;
&lt;br /&gt;
      let damageWithPrimaryBonuses = Math.floor(&lt;br /&gt;
        (rawDamage * bonusValues.weaponBonusCoeff) / 100&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      damageWithPrimaryBonuses = calcDamageWithPrimaryBonuses(&lt;br /&gt;
        damageWithPrimaryBonuses,&lt;br /&gt;
        bonusValues&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      const damageValues =&lt;br /&gt;
        damageWithPrimaryBonuses &amp;lt;= 2&lt;br /&gt;
          ? [1, 2, 3, 4, 5]&lt;br /&gt;
          : [damageWithPrimaryBonuses];&lt;br /&gt;
&lt;br /&gt;
      for (const damage of damageValues) {&lt;br /&gt;
        saveFinalSkillDamage(&lt;br /&gt;
          damage,&lt;br /&gt;
          damageWithPrimaryBonuses,&lt;br /&gt;
          bonusValues,&lt;br /&gt;
          criticalAttackRange,&lt;br /&gt;
          damageByType&lt;br /&gt;
        );&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      savedDamage[rawDamage] = currentDamageInfo;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  processSavedDamage(savedDamage, damageWeightedByType, battleValues);&lt;br /&gt;
&lt;br /&gt;
  return damageWeightedByType;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcDamage(&lt;br /&gt;
  attacker,&lt;br /&gt;
  victim,&lt;br /&gt;
  attackType,&lt;br /&gt;
  battle,&lt;br /&gt;
  removeSkillVariation&lt;br /&gt;
) {&lt;br /&gt;
  var damageCalculator, skillId, skillType;&lt;br /&gt;
&lt;br /&gt;
  if (attackType === &amp;quot;physical&amp;quot;) {&lt;br /&gt;
    damageCalculator = calcPhysicalDamage;&lt;br /&gt;
  } else if (attackType.startsWith(&amp;quot;attackSkill&amp;quot;)) {&lt;br /&gt;
    skillId = Number(attackType.split(&amp;quot;attackSkill&amp;quot;)[1]);&lt;br /&gt;
&lt;br /&gt;
    if (isMagicClass(attacker) || isDispell(attacker, skillId)) {&lt;br /&gt;
      skillType = &amp;quot;magic&amp;quot;;&lt;br /&gt;
      damageCalculator = calcMagicSkillDamage;&lt;br /&gt;
    } else {&lt;br /&gt;
      skillType = &amp;quot;physical&amp;quot;;&lt;br /&gt;
      damageCalculator = calcPhysicalSkillDamage;&lt;br /&gt;
    }&lt;br /&gt;
  } else if (attackType.startsWith(&amp;quot;horseSkill&amp;quot;)) {&lt;br /&gt;
    skillType = &amp;quot;physical&amp;quot;;&lt;br /&gt;
    skillId = Number(attackType.split(&amp;quot;horseSkill&amp;quot;)[1]);&lt;br /&gt;
    damageCalculator = calcPhysicalSkillDamage;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var battleValues = createBattleValues(attacker, victim, battle, skillType);&lt;br /&gt;
&lt;br /&gt;
  if (skillId) {&lt;br /&gt;
    getSkillFormula(battle, skillId, battleValues, removeSkillVariation);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    damageWeightedByType: damageCalculator(battleValues),&lt;br /&gt;
    attackValues: battleValues.attackValues,&lt;br /&gt;
    skillType: skillType,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function damageWithoutVariation(&lt;br /&gt;
  attacker,&lt;br /&gt;
  victim,&lt;br /&gt;
  attackType,&lt;br /&gt;
  battle,&lt;br /&gt;
  characters&lt;br /&gt;
) {&lt;br /&gt;
  var startDamageTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
  var { damageWeightedByType, attackValues, skillType } = calcDamage(&lt;br /&gt;
    attacker,&lt;br /&gt;
    victim,&lt;br /&gt;
    attackType,&lt;br /&gt;
    battle&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  var endDamageTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
  displayResults(&lt;br /&gt;
    attackValues,&lt;br /&gt;
    damageWeightedByType,&lt;br /&gt;
    battle,&lt;br /&gt;
    attacker.name,&lt;br /&gt;
    victim.name&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  var endDisplayTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
  displayFightInfo(&lt;br /&gt;
    attackValues.possibleDamageCount,&lt;br /&gt;
    endDamageTime - startDamageTime,&lt;br /&gt;
    endDisplayTime - endDamageTime,&lt;br /&gt;
    battle&lt;br /&gt;
  );&lt;br /&gt;
  addPotentialErrorInformation(&lt;br /&gt;
    battle.errorInformation,&lt;br /&gt;
    attacker,&lt;br /&gt;
    victim,&lt;br /&gt;
    skillType,&lt;br /&gt;
    characters&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  hideElement(battle.bonusVariationResultContainer);&lt;br /&gt;
  showElement(battle.fightResultTitle);&lt;br /&gt;
  showElement(battle.fightResultContainer);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function damageWithVariation(&lt;br /&gt;
  attacker,&lt;br /&gt;
  victim,&lt;br /&gt;
  attackType,&lt;br /&gt;
  battle,&lt;br /&gt;
  entity,&lt;br /&gt;
  entityVariation&lt;br /&gt;
) {&lt;br /&gt;
  var startTime = performance.now();&lt;br /&gt;
  var damageByBonus = [];&lt;br /&gt;
  var augmentationByBonus = [];&lt;br /&gt;
  var {&lt;br /&gt;
    bonusVariationMinValue: minVariation,&lt;br /&gt;
    bonusVariationMaxValue: maxVariation,&lt;br /&gt;
  } = entity;&lt;br /&gt;
  var step = Math.ceil((maxVariation - minVariation + 1) / 500);&lt;br /&gt;
  var simulationCount = 0;&lt;br /&gt;
  var simulationTime;&lt;br /&gt;
  var firstDamage = 1;&lt;br /&gt;
&lt;br /&gt;
  for (&lt;br /&gt;
    var bonusValue = minVariation;&lt;br /&gt;
    bonusValue &amp;lt;= maxVariation;&lt;br /&gt;
    bonusValue += step&lt;br /&gt;
  ) {&lt;br /&gt;
    entity[entityVariation] = bonusValue;&lt;br /&gt;
&lt;br /&gt;
    var {&lt;br /&gt;
      damageWeightedByType,&lt;br /&gt;
      attackValues: { totalCardinal },&lt;br /&gt;
    } = calcDamage(&lt;br /&gt;
      copyObject(attacker),&lt;br /&gt;
      copyObject(victim),&lt;br /&gt;
      attackType,&lt;br /&gt;
      battle,&lt;br /&gt;
      true&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    var meanDamage = calcMeanDamage(damageWeightedByType, totalCardinal);&lt;br /&gt;
&lt;br /&gt;
    if (bonusValue === minVariation) {&lt;br /&gt;
      firstDamage = Math.max(meanDamage, 1e-3);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    damageByBonus.push({ x: bonusValue, y: meanDamage });&lt;br /&gt;
    augmentationByBonus.push({&lt;br /&gt;
      x: bonusValue,&lt;br /&gt;
      y: meanDamage / firstDamage - 1,&lt;br /&gt;
    });&lt;br /&gt;
    simulationCount++;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var endTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
  battle.damageByBonus = damageByBonus.concat(entityVariation);&lt;br /&gt;
&lt;br /&gt;
  addToBonusVariationChart(&lt;br /&gt;
    damageByBonus,&lt;br /&gt;
    augmentationByBonus,&lt;br /&gt;
    entity.bonusVariationName,&lt;br /&gt;
    battle.bonusVariationChart&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  simulationCount = battle.numberFormats.default.format(simulationCount);&lt;br /&gt;
  simulationTime = battle.numberFormats.second.format(&lt;br /&gt;
    (endTime - startTime) / 1000&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  battle.simulationCounter.textContent = simulationCount;&lt;br /&gt;
  battle.simulationTime.textContent = simulationTime;&lt;br /&gt;
&lt;br /&gt;
  hideElement(battle.fightResultContainer);&lt;br /&gt;
  showElement(battle.fightResultTitle);&lt;br /&gt;
  showElement(battle.bonusVariationResultContainer);&lt;br /&gt;
&lt;br /&gt;
  if (&lt;br /&gt;
    isChecked(attacker.useBonusVariation) &amp;amp;&amp;amp;&lt;br /&gt;
    isChecked(victim.useBonusVariation)&lt;br /&gt;
  ) {&lt;br /&gt;
    showElement(battle.errorInformation[&amp;quot;attacker-victim-variation&amp;quot;]);&lt;br /&gt;
  } else {&lt;br /&gt;
    hideElement(battle.errorInformation[&amp;quot;attacker-victim-variation&amp;quot;]);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function changeMonsterValues(monster, instance, attacker) {&lt;br /&gt;
  switch (instance) {&lt;br /&gt;
    case &amp;quot;SungMahiTower&amp;quot;:&lt;br /&gt;
      var sungMahiFloor = 1;&lt;br /&gt;
      var sungMahiStep = 1;&lt;br /&gt;
      var rawDefense = 120;&lt;br /&gt;
&lt;br /&gt;
      if (isPC(attacker)) {&lt;br /&gt;
        sungMahiFloor = attacker.sungMahiFloor;&lt;br /&gt;
        sungMahiStep = attacker.sungMahiStep;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (monster.rank === 5) {&lt;br /&gt;
        monster.level = 121;&lt;br /&gt;
        monster.dex = 75;&lt;br /&gt;
        rawDefense += 1;&lt;br /&gt;
      } else if (monster.rank === 6) {&lt;br /&gt;
        monster.level = 123;&lt;br /&gt;
        monster.dex = 75;&lt;br /&gt;
        rawDefense += 1;&lt;br /&gt;
      } else {&lt;br /&gt;
        monster.level = 120;&lt;br /&gt;
        monster.dex = 68;&lt;br /&gt;
      }&lt;br /&gt;
      monster.vit = 100;&lt;br /&gt;
      monster.rawDefense = rawDefense + (sungMahiStep - 1) * 6;&lt;br /&gt;
      monster.fistDefense = 0;&lt;br /&gt;
      monster.swordDefense = 0;&lt;br /&gt;
      monster.twoHandedSwordDefense = 0;&lt;br /&gt;
      monster.daggerDefense = 0;&lt;br /&gt;
      monster.bellDefense = 0;&lt;br /&gt;
      monster.fanDefense = 0;&lt;br /&gt;
      monster.arrowDefense = 0;&lt;br /&gt;
      monster.clawDefense = 0;&lt;br /&gt;
      monster.magicResistance = 0;&lt;br /&gt;
      monster.fireResistance = -20;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  // Alastor&lt;br /&gt;
  if (monster.vnum === 6790) {&lt;br /&gt;
    monster.iceResistance = 0;&lt;br /&gt;
    monster.iceBonus = 0;&lt;br /&gt;
    monster.lightningResistance = -10;&lt;br /&gt;
    monster.lightningBonus = 65;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createWeapon(vnum) {&lt;br /&gt;
  var weapon = copyObject(weaponData[vnum]);&lt;br /&gt;
  var serpentVnums = [360, 380, 1210, 2230, 3250, 5200, 6150, 7330];&lt;br /&gt;
  var weaponValues = weapon[1];&lt;br /&gt;
  var isSerpent = isValueInArray(Number(vnum), serpentVnums);&lt;br /&gt;
  var isSpecial = Array.isArray(weaponValues[0]);&lt;br /&gt;
  var isMagic;&lt;br /&gt;
&lt;br /&gt;
  if (isSpecial) {&lt;br /&gt;
    isMagic = weaponValues[0][1] &amp;gt; 0;&lt;br /&gt;
  } else {&lt;br /&gt;
    isMagic = weaponValues[1] &amp;gt; 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    type: weapon[0],&lt;br /&gt;
    maxUpgrade: weapon[2].length - 1,&lt;br /&gt;
    isSerpent: isSerpent,&lt;br /&gt;
    isMagic: isMagic,&lt;br /&gt;
    getValues: function (upgrade) {&lt;br /&gt;
      var currentWeaponValues = weaponValues;&lt;br /&gt;
&lt;br /&gt;
      if (upgrade === undefined) {&lt;br /&gt;
        // rare bug when weaponUpgrade is deleted&lt;br /&gt;
        console.warn(&amp;quot;WeaponUpgrade is missing.&amp;quot;);&lt;br /&gt;
        upgrade = this.maxUpgrade;&lt;br /&gt;
      }&lt;br /&gt;
      upgrade = Math.min(upgrade, this.maxUpgrade);&lt;br /&gt;
&lt;br /&gt;
      if (isSpecial) {&lt;br /&gt;
        currentWeaponValues = weaponValues[upgrade];&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      this.minAttackValue = currentWeaponValues[2];&lt;br /&gt;
      this.maxAttackValue = currentWeaponValues[3];&lt;br /&gt;
      this.minMagicAttackValue = currentWeaponValues[0];&lt;br /&gt;
      this.maxMagicAttackValue = currentWeaponValues[1];&lt;br /&gt;
      this.growth = weapon[2][upgrade];&lt;br /&gt;
    },&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createMonster(&lt;br /&gt;
  monsterVnum,&lt;br /&gt;
  translateMonster,&lt;br /&gt;
  attacker,&lt;br /&gt;
  polymorphMonster&lt;br /&gt;
) {&lt;br /&gt;
  var monsterAttributes = monsterData[monsterVnum];&lt;br /&gt;
&lt;br /&gt;
  var monster = {&lt;br /&gt;
    vnum: Number(monsterVnum),&lt;br /&gt;
    name: translateMonster&lt;br /&gt;
      ? getTranslatedMonsterName(monsterVnum)&lt;br /&gt;
      : monsterAttributes[36],&lt;br /&gt;
    rank: monsterAttributes[0],&lt;br /&gt;
    race: monsterAttributes[1],&lt;br /&gt;
    attack: monsterAttributes[2],&lt;br /&gt;
    level: monsterAttributes[3],&lt;br /&gt;
    type: monsterAttributes[4],&lt;br /&gt;
    str: monsterAttributes[5],&lt;br /&gt;
    dex: monsterAttributes[6],&lt;br /&gt;
    vit: monsterAttributes[7],&lt;br /&gt;
    int: monsterAttributes[8],&lt;br /&gt;
    minAttackValue: monsterAttributes[9],&lt;br /&gt;
    maxAttackValue: monsterAttributes[10],&lt;br /&gt;
    rawDefense: monsterAttributes[11],&lt;br /&gt;
    criticalHit: monsterAttributes[12],&lt;br /&gt;
    piercingHit: monsterAttributes[13],&lt;br /&gt;
    fistDefense: monsterAttributes[14],&lt;br /&gt;
    swordDefense: monsterAttributes[15],&lt;br /&gt;
    twoHandedSwordDefense: monsterAttributes[16],&lt;br /&gt;
    daggerDefense: monsterAttributes[17],&lt;br /&gt;
    bellDefense: monsterAttributes[18],&lt;br /&gt;
    fanDefense: monsterAttributes[19],&lt;br /&gt;
    arrowDefense: monsterAttributes[20],&lt;br /&gt;
    clawDefense: monsterAttributes[21],&lt;br /&gt;
    fireResistance: monsterAttributes[22],&lt;br /&gt;
    lightningResistance: monsterAttributes[23],&lt;br /&gt;
    magicResistance: monsterAttributes[24],&lt;br /&gt;
    windResistance: monsterAttributes[25],&lt;br /&gt;
    lightningBonus: monsterAttributes[26],&lt;br /&gt;
    fireBonus: monsterAttributes[27],&lt;br /&gt;
    iceBonus: monsterAttributes[28],&lt;br /&gt;
    windBonus: monsterAttributes[29],&lt;br /&gt;
    earthBonus: monsterAttributes[30],&lt;br /&gt;
    darknessBonus: monsterAttributes[31],&lt;br /&gt;
    darknessResistance: monsterAttributes[32],&lt;br /&gt;
    iceResistance: monsterAttributes[33],&lt;br /&gt;
    earthResistance: monsterAttributes[34],&lt;br /&gt;
    damageMultiplier: monsterAttributes[35],&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  // monster.instance = 0;&lt;br /&gt;
&lt;br /&gt;
  // if (attacker &amp;amp;&amp;amp; monster.instance === 0) {&lt;br /&gt;
  //   changeMonsterValues(monster, &amp;quot;SungMahiTower&amp;quot;, attacker);&lt;br /&gt;
  // }&lt;br /&gt;
  if (!polymorphMonster) {&lt;br /&gt;
    changeMonsterValues(monster);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  monster.defense = monster.rawDefense + monster.level + monster.vit;&lt;br /&gt;
&lt;br /&gt;
  return monster;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addPotentialErrorInformation(&lt;br /&gt;
  errorInformation,&lt;br /&gt;
  attacker,&lt;br /&gt;
  victim,&lt;br /&gt;
  skillType,&lt;br /&gt;
  characters&lt;br /&gt;
) {&lt;br /&gt;
  for (var error of Object.values(errorInformation)) {&lt;br /&gt;
    hideElement(error);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker)) {&lt;br /&gt;
    if (isRiding(attacker)) {&lt;br /&gt;
      if (attacker.horsePoint === 0) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;horse-level&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
      showElement(errorInformation[&amp;quot;horse-stat&amp;quot;]);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isPolymorph(attacker)) {&lt;br /&gt;
      if (attacker.polymorphPoint === 0) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;polymorph-level&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (&lt;br /&gt;
        (attacker.polymorphPoint &amp;lt;= 39 &amp;amp;&amp;amp; attacker.attackValuePercent &amp;lt;= 199) ||&lt;br /&gt;
        (attacker.polymorphPoint === 40 &amp;amp;&amp;amp; attacker.attackValuePercent &amp;lt;= 299)&lt;br /&gt;
      ) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;polymorph-bonus&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
    if (skillType === &amp;quot;magic&amp;quot;) {&lt;br /&gt;
      if (attacker.magicAttackValue) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;magic-attack-value-bonus&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
      if (victim.magicResistance) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;magic-resistance&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    showElement(errorInformation[&amp;quot;monster-attacker&amp;quot;]);&lt;br /&gt;
    if (isMagicAttacker(attacker) &amp;amp;&amp;amp; victim.magicResistance) {&lt;br /&gt;
      showElement(errorInformation[&amp;quot;magic-resistance&amp;quot;]);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (isPC(victim)) {&lt;br /&gt;
    if (isRiding(victim)) {&lt;br /&gt;
      showElement(errorInformation[&amp;quot;horse-stat&amp;quot;]);&lt;br /&gt;
    }&lt;br /&gt;
    if (isPolymorph(victim)) {&lt;br /&gt;
      if (attacker.polymorphPoint === 0) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;polymorph-level&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
      showElement(errorInformation[&amp;quot;polymorph-defense&amp;quot;]);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (characters.unsavedChanges) {&lt;br /&gt;
    showElement(errorInformation[&amp;quot;save&amp;quot;]);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function reduceChartPointsListener(battle) {&lt;br /&gt;
  var {&lt;br /&gt;
    reduceChartPointsContainer,&lt;br /&gt;
    reduceChartPoints,&lt;br /&gt;
    numberFormats: { second: numberFormat },&lt;br /&gt;
    displayTime,&lt;br /&gt;
  } = battle;&lt;br /&gt;
&lt;br /&gt;
  reduceChartPoints.addEventListener(&amp;quot;change&amp;quot;, function () {&lt;br /&gt;
    reduceChartPoints.disabled = true;&lt;br /&gt;
&lt;br /&gt;
    var startDisplayTime = performance.now();&lt;br /&gt;
    var scatterDataByType = battle.scatterDataByType;&lt;br /&gt;
    var {&lt;br /&gt;
      chart,&lt;br /&gt;
      maxPoints,&lt;br /&gt;
      chart: {&lt;br /&gt;
        data: { datasets },&lt;br /&gt;
      },&lt;br /&gt;
    } = battle.damageChart;&lt;br /&gt;
    var addAnimations = false;&lt;br /&gt;
&lt;br /&gt;
    for (var index = 0; index &amp;lt; datasets.length; index++) {&lt;br /&gt;
      var dataset = datasets[index];&lt;br /&gt;
      var scatterData = scatterDataByType[dataset.name];&lt;br /&gt;
&lt;br /&gt;
      if (dataset.canBeReduced &amp;amp;&amp;amp; reduceChartPoints.checked) {&lt;br /&gt;
        dataset.data = aggregateDamage(scatterData, maxPoints);&lt;br /&gt;
        addAnimations = true;&lt;br /&gt;
      } else {&lt;br /&gt;
        dataset.data = scatterData;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    handleChartAnimations(chart, addAnimations);&lt;br /&gt;
    chart.update();&lt;br /&gt;
&lt;br /&gt;
    displayTime.textContent = numberFormat.format(&lt;br /&gt;
      (performance.now() - startDisplayTime) / 1000&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    setTimeout(function () {&lt;br /&gt;
      reduceChartPoints.disabled = false;&lt;br /&gt;
    }, 1000);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  reduceChartPointsContainer.addEventListener(&amp;quot;pointerup&amp;quot;, function (event) {&lt;br /&gt;
    if (event.pointerType === &amp;quot;mouse&amp;quot;) {&lt;br /&gt;
      if (event.target.closest(&amp;quot;label&amp;quot;)) {&lt;br /&gt;
        return;&lt;br /&gt;
      }&lt;br /&gt;
      reduceChartPoints.click();&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function downloadRawDataListener(battle) {&lt;br /&gt;
  var { downLoadRawData, downLoadRawDataVariation } = battle;&lt;br /&gt;
  var fileType = &amp;quot;text/csv;charset=utf-8;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  downLoadRawData.addEventListener(&amp;quot;click&amp;quot;, function () {&lt;br /&gt;
    var damageWeightedByType = battle.damageWeightedByType;&lt;br /&gt;
    var filename = &amp;quot;raw_damage.csv&amp;quot;;&lt;br /&gt;
    var csvContent = &amp;quot;damage,probabilities,damageType\n&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    for (var damageType in damageWeightedByType) {&lt;br /&gt;
      var damageWeighted = damageWeightedByType[damageType];&lt;br /&gt;
&lt;br /&gt;
      for (var damage in damageWeighted) {&lt;br /&gt;
        csvContent +=&lt;br /&gt;
          damage + &amp;quot;,&amp;quot; + damageWeighted[damage] + &amp;quot;,&amp;quot; + damageType + &amp;quot;\n&amp;quot;;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    downloadData(csvContent, fileType, filename);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  downLoadRawDataVariation.addEventListener(&amp;quot;click&amp;quot;, function () {&lt;br /&gt;
    var damageByBonus = battle.damageByBonus;&lt;br /&gt;
    var damageByBonusLength = damageByBonus.length;&lt;br /&gt;
    var filename = &amp;quot;damage_variation.csv&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    if (!damageByBonusLength) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var csvContent =&lt;br /&gt;
      damageByBonus[damageByBonusLength - 1] + &amp;quot;,averageDamage\n&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    for (var index = 0; index &amp;lt; damageByBonusLength - 1; index++) {&lt;br /&gt;
      var row = damageByBonus[index];&lt;br /&gt;
&lt;br /&gt;
      csvContent += row.x + &amp;quot;,&amp;quot; + row.y + &amp;quot;\n&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    downloadData(csvContent, fileType, filename);&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function displayResults(&lt;br /&gt;
  attackValues,&lt;br /&gt;
  damageWeightedByType,&lt;br /&gt;
  battle,&lt;br /&gt;
  attackerName,&lt;br /&gt;
  victimName&lt;br /&gt;
) {&lt;br /&gt;
  var [meanDamage, minDamage, maxDamage, scatterDataByType, uniqueDamageCount] =&lt;br /&gt;
    prepareDamageData(damageWeightedByType, attackValues);&lt;br /&gt;
&lt;br /&gt;
  addToDamageChart(&lt;br /&gt;
    scatterDataByType,&lt;br /&gt;
    battle.damageChart,&lt;br /&gt;
    battle.reduceChartPoints.checked&lt;br /&gt;
  );&lt;br /&gt;
  updateDamageChartDescription(&lt;br /&gt;
    battle.uniqueDamageCounters,&lt;br /&gt;
    uniqueDamageCount,&lt;br /&gt;
    battle.numberFormats.default&lt;br /&gt;
  );&lt;br /&gt;
  displayFightResults(&lt;br /&gt;
    battle,&lt;br /&gt;
    attackerName,&lt;br /&gt;
    victimName,&lt;br /&gt;
    meanDamage,&lt;br /&gt;
    minDamage,&lt;br /&gt;
    maxDamage&lt;br /&gt;
  );&lt;br /&gt;
  battle.damageWeightedByType = damageWeightedByType;&lt;br /&gt;
  battle.scatterDataByType = scatterDataByType;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function displayFightResults(&lt;br /&gt;
  battle,&lt;br /&gt;
  attackerName,&lt;br /&gt;
  victimName,&lt;br /&gt;
  meanDamage,&lt;br /&gt;
  minDamage,&lt;br /&gt;
  maxDamage&lt;br /&gt;
) {&lt;br /&gt;
  var {&lt;br /&gt;
    tableResultFight,&lt;br /&gt;
    tableResultHistory,&lt;br /&gt;
    savedFights,&lt;br /&gt;
    numberFormats: { default: numberFormat },&lt;br /&gt;
    deleteFightTemplate,&lt;br /&gt;
  } = battle;&lt;br /&gt;
&lt;br /&gt;
  hideElement(tableResultHistory.rows[1]);&lt;br /&gt;
&lt;br /&gt;
  var valuesToDisplay = [&lt;br /&gt;
    attackerName,&lt;br /&gt;
    victimName,&lt;br /&gt;
    battle.battleChoice.attackType.selectedText,&lt;br /&gt;
    meanDamage,&lt;br /&gt;
    minDamage,&lt;br /&gt;
    maxDamage,&lt;br /&gt;
  ];&lt;br /&gt;
&lt;br /&gt;
  savedFights.push(valuesToDisplay);&lt;br /&gt;
  updateSavedFights(savedFights);&lt;br /&gt;
&lt;br /&gt;
  editTableResultRow(tableResultFight.rows[1], valuesToDisplay, numberFormat);&lt;br /&gt;
  addRowToTableResultHistory(&lt;br /&gt;
    tableResultHistory,&lt;br /&gt;
    valuesToDisplay,&lt;br /&gt;
    deleteFightTemplate,&lt;br /&gt;
    numberFormat&lt;br /&gt;
  );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function displayFightInfo(&lt;br /&gt;
  possibleDamageCount,&lt;br /&gt;
  damageTimeDuration,&lt;br /&gt;
  displayTimeDuration,&lt;br /&gt;
  battle&lt;br /&gt;
) {&lt;br /&gt;
  var container = battle.possibleDamageCounter.parentElement;&lt;br /&gt;
&lt;br /&gt;
  if (possibleDamageCount &amp;lt;= 1) {&lt;br /&gt;
    hideElement(container);&lt;br /&gt;
    return;&lt;br /&gt;
  } else {&lt;br /&gt;
    showElement(container);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var { numberFormats, possibleDamageCounter, damageTime, displayTime } =&lt;br /&gt;
    battle;&lt;br /&gt;
&lt;br /&gt;
  possibleDamageCount = numberFormats.default.format(possibleDamageCount);&lt;br /&gt;
  damageTimeDuration = numberFormats.second.format(damageTimeDuration / 1000);&lt;br /&gt;
  displayTimeDuration = numberFormats.second.format(displayTimeDuration / 1000);&lt;br /&gt;
&lt;br /&gt;
  possibleDamageCounter.textContent = possibleDamageCount;&lt;br /&gt;
  damageTime.textContent = damageTimeDuration;&lt;br /&gt;
  displayTime.textContent = displayTimeDuration;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function parseTypeAndName(data) {&lt;br /&gt;
  var [type, nameOrVnum] = splitFirst(data, &amp;quot;-&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    type: type,&lt;br /&gt;
    nameOrVnum: nameOrVnum,&lt;br /&gt;
    isCharacter: type === &amp;quot;character&amp;quot;,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isCharacterSelected(characterName, selected) {&lt;br /&gt;
  if (!selected) {&lt;br /&gt;
    return false;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var { nameOrVnum, isCharacter } = parseTypeAndName(selected);&lt;br /&gt;
&lt;br /&gt;
  return nameOrVnum === characterName &amp;amp;&amp;amp; isCharacter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function useBonusVariationMode(character, variation) {&lt;br /&gt;
  return (&lt;br /&gt;
    isChecked(character.useBonusVariation) &amp;amp;&amp;amp;&lt;br /&gt;
    character.hasOwnProperty(variation) &amp;amp;&amp;amp;&lt;br /&gt;
    character.bonusVariationMinValue &amp;lt; character.bonusVariationMaxValue&lt;br /&gt;
  );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createBattle(characters, battle) {&lt;br /&gt;
  var battleChoice = battle.battleChoice;&lt;br /&gt;
  var battleForm = battleChoice.form;&lt;br /&gt;
  var lastInvalidTime = 0;&lt;br /&gt;
&lt;br /&gt;
  battleForm.addEventListener(&amp;quot;change&amp;quot;, handleBattleFormChange);&lt;br /&gt;
  battleForm.addEventListener(&amp;quot;invalid&amp;quot;, handleBattleFormInvalid, true);&lt;br /&gt;
  battleForm.addEventListener(&amp;quot;submit&amp;quot;, handleBattleFormSubmit);&lt;br /&gt;
&lt;br /&gt;
  function handleBattleFormChange(event) {&lt;br /&gt;
    var target = event.target;&lt;br /&gt;
    var { name: targetName, value: targetValue, type: targetType } = target;&lt;br /&gt;
&lt;br /&gt;
    if (targetType !== &amp;quot;radio&amp;quot;) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (targetName === &amp;quot;attackType&amp;quot;) {&lt;br /&gt;
      battleChoice.attackType.selectedText =&lt;br /&gt;
        target.previousElementSibling.textContent;&lt;br /&gt;
    } else {&lt;br /&gt;
      updateBattleChoiceButton(battleChoice, targetName, targetValue);&lt;br /&gt;
&lt;br /&gt;
      if (targetName === &amp;quot;attacker&amp;quot;) {&lt;br /&gt;
        filterAttackTypeSelection(characters, battleChoice, targetValue);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function handleBattleFormInvalid(event) {&lt;br /&gt;
    var currentTime = Date.now();&lt;br /&gt;
&lt;br /&gt;
    if (currentTime - lastInvalidTime &amp;lt; 100) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    lastInvalidTime = currentTime;&lt;br /&gt;
&lt;br /&gt;
    var target = event.target;&lt;br /&gt;
    var modal = target.closest(&amp;quot;.modal&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (!modal) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var dataModal = modal.dataset.modal;&lt;br /&gt;
&lt;br /&gt;
    if (!dataModal) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var category = dataModal.split(&amp;quot;-&amp;quot;)[0];&lt;br /&gt;
&lt;br /&gt;
    if (isValueInArray(category, battleChoice.categories)) {&lt;br /&gt;
      battleChoice[category].button.click();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function handleBattleFormSubmit(event) {&lt;br /&gt;
    event.preventDefault();&lt;br /&gt;
&lt;br /&gt;
    // auto save&lt;br /&gt;
    if (characters.unsavedChanges) {&lt;br /&gt;
      characters.saveButton.click();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var battleInfo = new FormData(event.target);&lt;br /&gt;
    var attackerData = battleInfo.get(&amp;quot;attacker&amp;quot;);&lt;br /&gt;
    var attackType = battleInfo.get(&amp;quot;attackType&amp;quot;);&lt;br /&gt;
    var victimData = battleInfo.get(&amp;quot;victim&amp;quot;);&lt;br /&gt;
    var attackerVariation;&lt;br /&gt;
    var victimVariation;&lt;br /&gt;
&lt;br /&gt;
    if (!attackerData &amp;amp;&amp;amp; !attackType &amp;amp;&amp;amp; !victimData) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var { nameOrVnum: attackerNameOrVnum, isCharacter: attackerIsPlayer } =&lt;br /&gt;
      parseTypeAndName(attackerData);&lt;br /&gt;
    var { nameOrVnum: victimNameOrVnum, isCharacter: victimIsPlayer } =&lt;br /&gt;
      parseTypeAndName(victimData);&lt;br /&gt;
&lt;br /&gt;
    if (attackerIsPlayer) {&lt;br /&gt;
      var attacker = copyObject(characters.savedCharacters[attackerNameOrVnum]);&lt;br /&gt;
      attackerVariation = attacker.bonusVariation;&lt;br /&gt;
    } else {&lt;br /&gt;
      var attacker = createMonster(&lt;br /&gt;
        attackerNameOrVnum,&lt;br /&gt;
        characters.translateMonsters&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (victimIsPlayer) {&lt;br /&gt;
      var victim = copyObject(characters.savedCharacters[victimNameOrVnum]);&lt;br /&gt;
      victimVariation = victim.bonusVariation;&lt;br /&gt;
    } else {&lt;br /&gt;
      var victim = createMonster(&lt;br /&gt;
        victimNameOrVnum,&lt;br /&gt;
        characters.translateMonsters,&lt;br /&gt;
        attacker&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (useBonusVariationMode(attacker, attackerVariation)) {&lt;br /&gt;
      damageWithVariation(&lt;br /&gt;
        attacker,&lt;br /&gt;
        victim,&lt;br /&gt;
        attackType,&lt;br /&gt;
        battle,&lt;br /&gt;
        attacker,&lt;br /&gt;
        attackerVariation&lt;br /&gt;
      );&lt;br /&gt;
    } else if (useBonusVariationMode(victim, victimVariation)) {&lt;br /&gt;
      damageWithVariation(&lt;br /&gt;
        attacker,&lt;br /&gt;
        victim,&lt;br /&gt;
        attackType,&lt;br /&gt;
        battle,&lt;br /&gt;
        victim,&lt;br /&gt;
        victimVariation&lt;br /&gt;
      );&lt;br /&gt;
    } else {&lt;br /&gt;
      damageWithoutVariation(attacker, victim, attackType, battle, characters);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createMapping() {&lt;br /&gt;
  return {&lt;br /&gt;
    typeFlag: [&lt;br /&gt;
      &amp;quot;animalBonus&amp;quot;, // 0&lt;br /&gt;
      &amp;quot;humanBonus&amp;quot;, // 1&lt;br /&gt;
      &amp;quot;orcBonus&amp;quot;, // 2&lt;br /&gt;
      &amp;quot;mysticBonus&amp;quot;, // 3&lt;br /&gt;
      &amp;quot;undeadBonus&amp;quot;, // 4&lt;br /&gt;
      &amp;quot;insectBonus&amp;quot;, // 5&lt;br /&gt;
      &amp;quot;desertBonus&amp;quot;, // 6&lt;br /&gt;
      &amp;quot;devilBonus&amp;quot;, // 7&lt;br /&gt;
    ],&lt;br /&gt;
    raceBonus: {&lt;br /&gt;
      warrior: &amp;quot;warriorBonus&amp;quot;,&lt;br /&gt;
      sura: &amp;quot;suraBonus&amp;quot;,&lt;br /&gt;
      ninja: &amp;quot;ninjaBonus&amp;quot;,&lt;br /&gt;
      shaman: &amp;quot;shamanBonus&amp;quot;,&lt;br /&gt;
      lycan: &amp;quot;lycanBonus&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    raceResistance: {&lt;br /&gt;
      warrior: &amp;quot;warriorResistance&amp;quot;,&lt;br /&gt;
      sura: &amp;quot;suraResistance&amp;quot;,&lt;br /&gt;
      ninja: &amp;quot;ninjaResistance&amp;quot;,&lt;br /&gt;
      shaman: &amp;quot;shamanResistance&amp;quot;,&lt;br /&gt;
      lycan: &amp;quot;lycanResistance&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    defenseWeapon: [&lt;br /&gt;
      &amp;quot;swordDefense&amp;quot;, // 0&lt;br /&gt;
      &amp;quot;daggerDefense&amp;quot;, // 1&lt;br /&gt;
      &amp;quot;arrowDefense&amp;quot;, // 2&lt;br /&gt;
      &amp;quot;twoHandedSwordDefense&amp;quot;, // 3&lt;br /&gt;
      &amp;quot;bellDefense&amp;quot;, // 4&lt;br /&gt;
      &amp;quot;clawDefense&amp;quot;, // 5&lt;br /&gt;
      &amp;quot;fanDefense&amp;quot;, // 6&lt;br /&gt;
      &amp;quot;swordDefense&amp;quot;, // 7&lt;br /&gt;
      &amp;quot;fistDefense&amp;quot;, // 8&lt;br /&gt;
    ],&lt;br /&gt;
    breakWeapon: [&lt;br /&gt;
      &amp;quot;breakSwordDefense&amp;quot;, // 0&lt;br /&gt;
      &amp;quot;breakDaggerDefense&amp;quot;, // 1&lt;br /&gt;
      &amp;quot;breakArrowDefense&amp;quot;, // 2&lt;br /&gt;
      &amp;quot;breakTwoHandedSwordDefense&amp;quot;, // 3&lt;br /&gt;
      &amp;quot;breakBellDefense&amp;quot;, // 4&lt;br /&gt;
      &amp;quot;breakClawDefense&amp;quot;, // 5&lt;br /&gt;
      &amp;quot;breakFanDefense&amp;quot;, // 6&lt;br /&gt;
      &amp;quot;breakSwordDefense&amp;quot;, // 7&lt;br /&gt;
    ],&lt;br /&gt;
    elementBonus: [&lt;br /&gt;
      &amp;quot;fireBonus&amp;quot;, // 0&lt;br /&gt;
      &amp;quot;iceBonus&amp;quot;, // 1&lt;br /&gt;
      &amp;quot;windBonus&amp;quot;, // 2&lt;br /&gt;
      &amp;quot;lightningBonus&amp;quot;, // 3&lt;br /&gt;
      &amp;quot;earthBonus&amp;quot;, // 4&lt;br /&gt;
      &amp;quot;darknessBonus&amp;quot;, // 5&lt;br /&gt;
    ],&lt;br /&gt;
    elementResistance: [&lt;br /&gt;
      &amp;quot;fireResistance&amp;quot;, // 0&lt;br /&gt;
      &amp;quot;iceResistance&amp;quot;, // 1&lt;br /&gt;
      &amp;quot;windResistance&amp;quot;, // 2&lt;br /&gt;
      &amp;quot;lightningResistance&amp;quot;, // 3&lt;br /&gt;
      &amp;quot;earthResistance&amp;quot;, // 4&lt;br /&gt;
      &amp;quot;darknessResistance&amp;quot;, // 5&lt;br /&gt;
    ],&lt;br /&gt;
    attackType: [&lt;br /&gt;
      &amp;quot;normalHit&amp;quot;,&lt;br /&gt;
      &amp;quot;criticalHit&amp;quot;,&lt;br /&gt;
      &amp;quot;piercingHit&amp;quot;,&lt;br /&gt;
      &amp;quot;criticalPiercingHit&amp;quot;,&lt;br /&gt;
    ],&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createConstants() {&lt;br /&gt;
  var constants = {&lt;br /&gt;
    polymorphPowerTable: [&lt;br /&gt;
      10, 11, 11, 12, 13, 13, 14, 15, 16, 17, 18, 19, 20, 22, 23, 24, 26, 27,&lt;br /&gt;
      29, 31, 33, 35, 37, 39, 41, 44, 46, 49, 52, 55, 59, 62, 66, 70, 74, 79,&lt;br /&gt;
      84, 89, 94, 100, 0,&lt;br /&gt;
    ],&lt;br /&gt;
    skillPowerTable: [&lt;br /&gt;
      0, 0.05, 0.06, 0.08, 0.1, 0.12, 0.14, 0.16, 0.18, 0.2, 0.22, 0.24, 0.26,&lt;br /&gt;
      0.28, 0.3, 0.32, 0.34, 0.36, 0.38, 0.4, 0.5, 0.52, 0.54, 0.56, 0.58, 0.6,&lt;br /&gt;
      0.63, 0.66, 0.69, 0.72, 0.82, 0.85, 0.88, 0.91, 0.94, 0.98, 1.02, 1.06,&lt;br /&gt;
      1.1, 1.15, 1.25,&lt;br /&gt;
    ],&lt;br /&gt;
    marriageTable: {&lt;br /&gt;
      harmonyEarrings: [4, 5, 6, 8],&lt;br /&gt;
      loveEarrings: [4, 5, 6, 8],&lt;br /&gt;
      harmonyBracelet: [4, 5, 6, 8],&lt;br /&gt;
      loveNecklace: [20, 25, 30, 40],&lt;br /&gt;
      harmonyNecklace: [12, 16, 20, 30],&lt;br /&gt;
    },&lt;br /&gt;
    allowedWeaponsPerRace: {&lt;br /&gt;
      warrior: [0, 3, 8],&lt;br /&gt;
      ninja: [0, 1, 2, 8],&lt;br /&gt;
      sura: [0, 7, 8],&lt;br /&gt;
      shaman: [4, 6, 8],&lt;br /&gt;
      lycan: [5, 8],&lt;br /&gt;
    },&lt;br /&gt;
  };&lt;br /&gt;
  return constants;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initResultTableHistory(battle) {&lt;br /&gt;
  var {&lt;br /&gt;
    tableResultHistory,&lt;br /&gt;
    savedFights,&lt;br /&gt;
    deleteFightTemplate,&lt;br /&gt;
    numberFormats: { default: numberFormat },&lt;br /&gt;
  } = battle;&lt;br /&gt;
  var startIndex = 3;&lt;br /&gt;
&lt;br /&gt;
  if (savedFights.length) {&lt;br /&gt;
    hideElement(tableResultHistory.rows[1]);&lt;br /&gt;
&lt;br /&gt;
    for (var savedFight of savedFights) {&lt;br /&gt;
      addRowToTableResultHistory(&lt;br /&gt;
        tableResultHistory,&lt;br /&gt;
        savedFight,&lt;br /&gt;
        deleteFightTemplate,&lt;br /&gt;
        numberFormat&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  tableResultHistory.addEventListener(&amp;quot;click&amp;quot;, function (event) {&lt;br /&gt;
    var deleteButton = event.target.closest(&amp;quot;.svg-icon-delete&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (deleteButton) {&lt;br /&gt;
      var row = deleteButton.closest(&amp;quot;tr&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
      if (row) {&lt;br /&gt;
        savedFights.splice(row.rowIndex - startIndex, 1);&lt;br /&gt;
        updateSavedFights(savedFights);&lt;br /&gt;
&lt;br /&gt;
        row.remove();&lt;br /&gt;
&lt;br /&gt;
        if (tableResultHistory.rows.length === startIndex) {&lt;br /&gt;
          showElement(tableResultHistory.rows[1]);&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initDamageChart(battle, currentLanguage, defaultText) {&lt;br /&gt;
  const { reduceChartPointsContainer, reduceChartPoints } = battle;&lt;br /&gt;
  const percentFormat = battle.numberFormats.percent;&lt;br /&gt;
  const customPlugins = {&lt;br /&gt;
    id: &amp;quot;customPlugins&amp;quot;,&lt;br /&gt;
    afterDraw(chart) {&lt;br /&gt;
      const missPercentage = chart.data.missPercentage;&lt;br /&gt;
&lt;br /&gt;
      if (!missPercentage) {&lt;br /&gt;
        return;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      const {&lt;br /&gt;
        ctx,&lt;br /&gt;
        chartArea: { top, right },&lt;br /&gt;
      } = chart;&lt;br /&gt;
      ctx.save();&lt;br /&gt;
      const text =&lt;br /&gt;
        defaultText.miss + &amp;quot; : &amp;quot; + percentFormat.format(missPercentage);&lt;br /&gt;
      const padding = 4;&lt;br /&gt;
      const fontSize = 14;&lt;br /&gt;
&lt;br /&gt;
      ctx.font = fontSize + &amp;quot;px Helvetica Neue&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
      const textWidth = ctx.measureText(text).width;&lt;br /&gt;
      const xPosition = right - textWidth - 5;&lt;br /&gt;
      const yPosition = top + 5;&lt;br /&gt;
&lt;br /&gt;
      ctx.fillStyle = &amp;quot;rgba(255, 0, 0, 0.2)&amp;quot;;&lt;br /&gt;
      ctx.fillRect(&lt;br /&gt;
        xPosition - padding,&lt;br /&gt;
        yPosition - padding,&lt;br /&gt;
        textWidth + 2 * padding,&lt;br /&gt;
        fontSize + 2 * padding&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      ctx.strokeStyle = &amp;quot;red&amp;quot;;&lt;br /&gt;
      ctx.strokeRect(&lt;br /&gt;
        xPosition - padding,&lt;br /&gt;
        yPosition - padding,&lt;br /&gt;
        textWidth + 2 * padding,&lt;br /&gt;
        fontSize + 2 * padding&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      ctx.fillStyle = &amp;quot;#666&amp;quot;;&lt;br /&gt;
      ctx.textBaseline = &amp;quot;top&amp;quot;;&lt;br /&gt;
      ctx.fillText(text, xPosition, yPosition + 1);&lt;br /&gt;
&lt;br /&gt;
      ctx.restore();&lt;br /&gt;
    },&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  Chart.register(customPlugins);&lt;br /&gt;
&lt;br /&gt;
  const ctx = battle.plotDamage.getContext(&amp;quot;2d&amp;quot;);&lt;br /&gt;
  const maxLabelsInTooltip = 10;&lt;br /&gt;
  const nullLabelText = &amp;quot; ...&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  const chart = new Chart(ctx, {&lt;br /&gt;
    type: &amp;quot;scatter&amp;quot;,&lt;br /&gt;
    data: {&lt;br /&gt;
      missPercentage: 0,&lt;br /&gt;
      datasets: [],&lt;br /&gt;
    },&lt;br /&gt;
    options: {&lt;br /&gt;
      locale: currentLanguage,&lt;br /&gt;
      responsive: true,&lt;br /&gt;
      maintainAspectRatio: false,&lt;br /&gt;
      plugins: {&lt;br /&gt;
        legend: {&lt;br /&gt;
          display: true,&lt;br /&gt;
          onHover: function (e) {&lt;br /&gt;
            e.native.target.style.cursor = &amp;quot;pointer&amp;quot;;&lt;br /&gt;
          },&lt;br /&gt;
          onLeave: function (e) {&lt;br /&gt;
            e.native.target.style.cursor = &amp;quot;default&amp;quot;;&lt;br /&gt;
          },&lt;br /&gt;
          onClick: function (e, legendItem, legend) {&lt;br /&gt;
            const currentIndex = legendItem.datasetIndex;&lt;br /&gt;
            const ci = legend.chart;&lt;br /&gt;
            const isCurrentDatasetVisible = ci.isDatasetVisible(currentIndex);&lt;br /&gt;
            const datasets = ci.data.datasets;&lt;br /&gt;
            const hideReducePoints = true;&lt;br /&gt;
            const isReducePointsChecked = reduceChartPoints.checked;&lt;br /&gt;
&lt;br /&gt;
            datasets[currentIndex].hidden = isCurrentDatasetVisible;&lt;br /&gt;
            legendItem.hidden = isCurrentDatasetVisible;&lt;br /&gt;
&lt;br /&gt;
            for (const index in datasets) {&lt;br /&gt;
              if (ci.isDatasetVisible(index) &amp;amp;&amp;amp; datasets[index].canBeReduced) {&lt;br /&gt;
                showElement(reduceChartPointsContainer);&lt;br /&gt;
                hideReducePoints = false;&lt;br /&gt;
                break;&lt;br /&gt;
              }&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            if (hideReducePoints) {&lt;br /&gt;
              hideElement(reduceChartPointsContainer);&lt;br /&gt;
              handleChartAnimations(ci, true);&lt;br /&gt;
            } else {&lt;br /&gt;
              handleChartAnimations(ci, isReducePointsChecked);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            ci.update();&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        title: {&lt;br /&gt;
          display: true,&lt;br /&gt;
          text: defaultText.damageRepartition,&lt;br /&gt;
          font: {&lt;br /&gt;
            size: 20,&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        tooltip: {&lt;br /&gt;
          callbacks: {&lt;br /&gt;
            label: function (context) {&lt;br /&gt;
              if (context.label === null) {&lt;br /&gt;
                return nullLabelText;&lt;br /&gt;
              }&lt;br /&gt;
&lt;br /&gt;
              const xValue = battle.numberFormats.default.format(&lt;br /&gt;
                context.parsed.x&lt;br /&gt;
              );&lt;br /&gt;
              const yValue = battle.numberFormats.percent.format(&lt;br /&gt;
                context.parsed.y&lt;br /&gt;
              );&lt;br /&gt;
              const label =&lt;br /&gt;
                &amp;quot; &amp;quot; +&lt;br /&gt;
                context.dataset.label +&lt;br /&gt;
                &amp;quot; : (&amp;quot; +&lt;br /&gt;
                xValue +&lt;br /&gt;
                &amp;quot;, &amp;quot; +&lt;br /&gt;
                yValue +&lt;br /&gt;
                &amp;quot;)&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
              return label;&lt;br /&gt;
            },&lt;br /&gt;
            beforeBody: function (tooltipItems) {&lt;br /&gt;
              if (tooltipItems.length &amp;gt; maxLabelsInTooltip + 1) {&lt;br /&gt;
                tooltipItems.splice(maxLabelsInTooltip + 1);&lt;br /&gt;
                tooltipItems[maxLabelsInTooltip].label = null;&lt;br /&gt;
              }&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          caretPadding: 10,&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
      scales: {&lt;br /&gt;
        x: {&lt;br /&gt;
          type: &amp;quot;linear&amp;quot;,&lt;br /&gt;
          position: &amp;quot;bottom&amp;quot;,&lt;br /&gt;
          title: {&lt;br /&gt;
            display: true,&lt;br /&gt;
            text: defaultText.damage,&lt;br /&gt;
            font: {&lt;br /&gt;
              size: 16,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          ticks: {&lt;br /&gt;
            callback: function (value) {&lt;br /&gt;
              return Number.isInteger(value) ? value : &amp;quot;&amp;quot;;&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        y: {&lt;br /&gt;
          title: {&lt;br /&gt;
            display: true,&lt;br /&gt;
            text: defaultText.percentage,&lt;br /&gt;
            font: {&lt;br /&gt;
              size: 16,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          ticks: {&lt;br /&gt;
            format: {&lt;br /&gt;
              style: &amp;quot;percent&amp;quot;,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
      elements: {&lt;br /&gt;
        point: {&lt;br /&gt;
          borderWidth: 1,&lt;br /&gt;
          radius: 3,&lt;br /&gt;
          hitRadius: 3,&lt;br /&gt;
          hoverRadius: 6,&lt;br /&gt;
          hoverBorderWidth: 2,&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
    },&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  const datasetsStyle = [&lt;br /&gt;
    {&lt;br /&gt;
      name: &amp;quot;normalHit&amp;quot;,&lt;br /&gt;
      canBeReduced: false,&lt;br /&gt;
      label: defaultText.normalHit,&lt;br /&gt;
      backgroundColor: &amp;quot;rgba(75, 192, 192, 0.2)&amp;quot;,&lt;br /&gt;
      borderColor: &amp;quot;rgba(75, 192, 192, 1)&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      name: &amp;quot;piercingHit&amp;quot;,&lt;br /&gt;
      canBeReduced: false,&lt;br /&gt;
      label: defaultText.piercingHit,&lt;br /&gt;
      backgroundColor: &amp;quot;rgba(192, 192, 75, 0.2)&amp;quot;,&lt;br /&gt;
      borderColor: &amp;quot;rgba(192, 192, 75, 1)&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      name: &amp;quot;criticalHit&amp;quot;,&lt;br /&gt;
      canBeReduced: false,&lt;br /&gt;
      label: defaultText.criticalHit,&lt;br /&gt;
      backgroundColor: &amp;quot;rgba(192, 75, 192, 0.2)&amp;quot;,&lt;br /&gt;
      borderColor: &amp;quot;rgba(192, 75, 192, 1)&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      name: &amp;quot;criticalPiercingHit&amp;quot;,&lt;br /&gt;
      canBeReduced: false,&lt;br /&gt;
      label: defaultText.criticalPiercingHit,&lt;br /&gt;
      backgroundColor: &amp;quot;rgba(75, 75, 192, 0.2)&amp;quot;,&lt;br /&gt;
      borderColor: &amp;quot;rgba(75, 75, 192, 1)&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
  ];&lt;br /&gt;
  battle.damageChart = {&lt;br /&gt;
    chart: chart,&lt;br /&gt;
    datasetsStyle: datasetsStyle,&lt;br /&gt;
    maxPoints: 500,&lt;br /&gt;
    reduceChartPointsContainer: reduceChartPointsContainer,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initBonusVariationChart(battle, currentLanguage, defaultText) {&lt;br /&gt;
  const { plotBonusVariation } = battle;&lt;br /&gt;
&lt;br /&gt;
  const ctx = plotBonusVariation.getContext(&amp;quot;2d&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  const chart = new Chart(ctx, {&lt;br /&gt;
    type: &amp;quot;line&amp;quot;,&lt;br /&gt;
    data: {&lt;br /&gt;
      datasets: [&lt;br /&gt;
        {&lt;br /&gt;
          label: defaultText.averageDamage,&lt;br /&gt;
          backgroundColor: &amp;quot;rgba(75, 192, 192, 0.2)&amp;quot;,&lt;br /&gt;
          borderColor: &amp;quot;rgba(75, 192, 192, 1)&amp;quot;,&lt;br /&gt;
          fill: true,&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          label: defaultText.damageAugmentation,&lt;br /&gt;
          backgroundColor: &amp;quot;rgba(192, 192, 75, 0.2)&amp;quot;,&lt;br /&gt;
          borderColor: &amp;quot;rgba(192, 192, 75, 1)&amp;quot;,&lt;br /&gt;
          hidden: true,&lt;br /&gt;
          yTicksFormat: { style: &amp;quot;percent&amp;quot; },&lt;br /&gt;
          fill: true,&lt;br /&gt;
        },&lt;br /&gt;
      ],&lt;br /&gt;
    },&lt;br /&gt;
    options: {&lt;br /&gt;
      locale: currentLanguage,&lt;br /&gt;
      responsive: true,&lt;br /&gt;
      maintainAspectRatio: false,&lt;br /&gt;
      plugins: {&lt;br /&gt;
        legend: {&lt;br /&gt;
          display: true,&lt;br /&gt;
          onHover: function (e) {&lt;br /&gt;
            e.native.target.style.cursor = &amp;quot;pointer&amp;quot;;&lt;br /&gt;
          },&lt;br /&gt;
          onLeave: function (e) {&lt;br /&gt;
            e.native.target.style.cursor = &amp;quot;default&amp;quot;;&lt;br /&gt;
          },&lt;br /&gt;
          onClick: function (e, legendItem, legend) {&lt;br /&gt;
            var currentIndex = legendItem.datasetIndex;&lt;br /&gt;
            var ci = legend.chart;&lt;br /&gt;
            var datasets = ci.data.datasets;&lt;br /&gt;
            var isCurrentDatasetVisible = ci.isDatasetVisible(currentIndex);&lt;br /&gt;
            var yAxis = ci.options.scales.y;&lt;br /&gt;
&lt;br /&gt;
            var otherIndex = currentIndex === 0 ? 1 : 0;&lt;br /&gt;
            var visibleDataset = isCurrentDatasetVisible&lt;br /&gt;
              ? datasets[otherIndex]&lt;br /&gt;
              : datasets[currentIndex];&lt;br /&gt;
&lt;br /&gt;
            datasets[currentIndex].hidden = isCurrentDatasetVisible;&lt;br /&gt;
            datasets[otherIndex].hidden = !isCurrentDatasetVisible;&lt;br /&gt;
&lt;br /&gt;
            yAxis.title.text = visibleDataset.label;&lt;br /&gt;
            yAxis.ticks.format = visibleDataset.yTicksFormat;&lt;br /&gt;
&lt;br /&gt;
            ci.update();&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        title: {&lt;br /&gt;
          display: true,&lt;br /&gt;
          text: defaultText.bonusVariationTitle.split(&amp;quot;[[]]&amp;quot;),&lt;br /&gt;
          font: {&lt;br /&gt;
            size: 18,&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        tooltip: {&lt;br /&gt;
          caretPadding: 10,&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
      scales: {&lt;br /&gt;
        x: {&lt;br /&gt;
          type: &amp;quot;linear&amp;quot;,&lt;br /&gt;
          position: &amp;quot;bottom&amp;quot;,&lt;br /&gt;
          title: {&lt;br /&gt;
            display: true,&lt;br /&gt;
            text: &amp;quot;Bonus&amp;quot;,&lt;br /&gt;
            font: {&lt;br /&gt;
              size: 16,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          ticks: {&lt;br /&gt;
            callback: function (value) {&lt;br /&gt;
              if (Number.isInteger(value)) {&lt;br /&gt;
                return Number(value);&lt;br /&gt;
              }&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        y: {&lt;br /&gt;
          title: {&lt;br /&gt;
            display: true,&lt;br /&gt;
            text: defaultText.averageDamage,&lt;br /&gt;
            font: {&lt;br /&gt;
              size: 16,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
      elements: {&lt;br /&gt;
        point: {&lt;br /&gt;
          borderWidth: 1,&lt;br /&gt;
          radius: 3,&lt;br /&gt;
          hitRadius: 3,&lt;br /&gt;
          hoverRadius: 6,&lt;br /&gt;
          hoverBorderWidth: 2,&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
    },&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  battle.bonusVariationChart = chart;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterAttackTypeSelection(characters, battleChoice, targetValue) {&lt;br /&gt;
  var { nameOrVnum: attackerNameOrVnum, isCharacter: isAttackerPlayer } =&lt;br /&gt;
    parseTypeAndName(targetValue);&lt;br /&gt;
&lt;br /&gt;
  if (isAttackerPlayer) {&lt;br /&gt;
    var attacker = characters.savedCharacters[attackerNameOrVnum];&lt;br /&gt;
    filterAttackTypeSelectionCharacter(attacker, battleChoice.attackType);&lt;br /&gt;
  } else {&lt;br /&gt;
    filterAttackTypeSelectionMonster(battleChoice.attackType);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addBattleData(battle) {&lt;br /&gt;
  var errorElements = document.querySelectorAll(&amp;quot;[data-error]&amp;quot;);&lt;br /&gt;
  var { elements: attackTypeElements, container: attackTypeContainer } =&lt;br /&gt;
    battle.battleChoice.attackType;&lt;br /&gt;
  var attackTypeChilds = attackTypeContainer.children;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; errorElements.length; index++) {&lt;br /&gt;
    var errorElement = errorElements[index];&lt;br /&gt;
    battle.errorInformation[errorElement.dataset.error] = errorElement;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (var index = 1; index &amp;lt; attackTypeChilds.length - 1; index++) {&lt;br /&gt;
    var attackTypeChild = attackTypeChilds[index];&lt;br /&gt;
    var input = attackTypeChild.querySelector(&amp;quot;input&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    attackTypeElements.push({&lt;br /&gt;
      container: attackTypeChild,&lt;br /&gt;
      input: input,&lt;br /&gt;
      inputClass: input.dataset.class,&lt;br /&gt;
      inputValue: input.value,&lt;br /&gt;
    });&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createDamageCalculatorInformation(&lt;br /&gt;
  defaultLang,&lt;br /&gt;
  currentLanguage,&lt;br /&gt;
  defaultText&lt;br /&gt;
) {&lt;br /&gt;
  const characters = {&lt;br /&gt;
    unsavedChanges: false,&lt;br /&gt;
    savedCharacters: {},&lt;br /&gt;
    currentCharacter: null,&lt;br /&gt;
    savedMonsters: getSavedMonsters(),&lt;br /&gt;
    monsterElements: {},&lt;br /&gt;
    characterCreation: document.getElementById(&amp;quot;character-creation&amp;quot;),&lt;br /&gt;
    addNewCharacterButton: document.getElementById(&amp;quot;add-new-character&amp;quot;),&lt;br /&gt;
    dropZone: document.getElementById(&amp;quot;character-drop-zone&amp;quot;),&lt;br /&gt;
    characterInput: document.getElementById(&amp;quot;character-input&amp;quot;),&lt;br /&gt;
    newCharacterTemplate: document.getElementById(&amp;quot;new-character-template&amp;quot;)&lt;br /&gt;
      .children[0],&lt;br /&gt;
    charactersContainer: document.getElementById(&amp;quot;characters-container&amp;quot;),&lt;br /&gt;
    monsterButtonTemplates: document.getElementById(&amp;quot;monster-button-templates&amp;quot;),&lt;br /&gt;
    monsterTemplate: document.getElementById(&amp;quot;new-monster-template&amp;quot;)&lt;br /&gt;
      .children[0],&lt;br /&gt;
    monstersContainer: document.getElementById(&amp;quot;monsters-container&amp;quot;),&lt;br /&gt;
    monsteriFrame: document.getElementById(&amp;quot;monster-iframe&amp;quot;),&lt;br /&gt;
    stoneiFrame: document.getElementById(&amp;quot;stone-iframe&amp;quot;),&lt;br /&gt;
    saveButton: document.getElementById(&amp;quot;save-character&amp;quot;),&lt;br /&gt;
    weaponCategory: document.getElementById(&amp;quot;weapon-category&amp;quot;),&lt;br /&gt;
    weaponDisplay: document.getElementById(&amp;quot;weapon-display&amp;quot;),&lt;br /&gt;
    randomAttackValue: document.getElementById(&amp;quot;random-attack-value&amp;quot;),&lt;br /&gt;
    randomMagicAttackValue: document.getElementById(&lt;br /&gt;
      &amp;quot;random-magic-attack-value&amp;quot;&lt;br /&gt;
    ),&lt;br /&gt;
    toggleSiblings: {},&lt;br /&gt;
    polymorphDisplay: document.getElementById(&amp;quot;polymorph-display&amp;quot;),&lt;br /&gt;
    bonusVariation: {&lt;br /&gt;
      tabButton: document.getElementById(&amp;quot;Variation&amp;quot;),&lt;br /&gt;
      checkbox: document.getElementById(&amp;quot;use-bonus-variation&amp;quot;),&lt;br /&gt;
      input: document.getElementById(&amp;quot;bonus-variation&amp;quot;),&lt;br /&gt;
      inputName: document.getElementById(&amp;quot;bonus-variation-name&amp;quot;),&lt;br /&gt;
      container: document.getElementById(&amp;quot;bonus-variation-creation&amp;quot;),&lt;br /&gt;
      minValue: document.getElementById(&amp;quot;bonus-variation-min-value&amp;quot;),&lt;br /&gt;
      maxValue: document.getElementById(&amp;quot;bonus-variation-max-value&amp;quot;),&lt;br /&gt;
      disabledText: document.getElementById(&amp;quot;bonus-variation-disabled&amp;quot;),&lt;br /&gt;
      selectedText: document.getElementById(&amp;quot;bonus-variation-selected&amp;quot;),&lt;br /&gt;
      displaySpan: document.getElementById(&amp;quot;bonus-variation-display&amp;quot;),&lt;br /&gt;
    },&lt;br /&gt;
    skillElementsToFilter: document.querySelectorAll(&lt;br /&gt;
      &amp;quot;#skill-container [data-class]&amp;quot;&lt;br /&gt;
    ),&lt;br /&gt;
    translateMonsters: defaultLang !== currentLanguage,&lt;br /&gt;
    defaultText: defaultText,&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  for (const [pseudo, character] of Object.entries(getSavedCharacters())) {&lt;br /&gt;
    characters.savedCharacters[pseudo] = character;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  document.querySelectorAll(&amp;quot;.toggle-sibling&amp;quot;).forEach(function (element) {&lt;br /&gt;
    const target = element.dataset.target;&lt;br /&gt;
    const sibling = document.getElementById(target);&lt;br /&gt;
    characters.toggleSiblings[element.name] = sibling;&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  const constants = createConstants();&lt;br /&gt;
&lt;br /&gt;
  const battle = {&lt;br /&gt;
    savedFights: getSavedFights(),&lt;br /&gt;
    battleChoice: {&lt;br /&gt;
      resetAttackType: false,&lt;br /&gt;
      form: document.getElementById(&amp;quot;create-battle&amp;quot;),&lt;br /&gt;
      template: document.getElementById(&amp;quot;battle-selection-template&amp;quot;)&lt;br /&gt;
        .children[0],&lt;br /&gt;
      raceToImage: {&lt;br /&gt;
        warrior: &amp;quot;/images/0/0f/Bandeaurougehomme.png&amp;quot;,&lt;br /&gt;
        ninja: &amp;quot;/images/0/0e/Queuedechevalclair.png&amp;quot;,&lt;br /&gt;
        sura: &amp;quot;/images/3/37/Couperespectablerouge.png&amp;quot;,&lt;br /&gt;
        shaman: &amp;quot;/images/6/6a/Coupeeleganteclairfemme.png&amp;quot;,&lt;br /&gt;
        lycan: &amp;quot;/images/4/4e/Protectionfrontalerouge.png&amp;quot;,&lt;br /&gt;
      },&lt;br /&gt;
      categories: [&amp;quot;attacker&amp;quot;, &amp;quot;victim&amp;quot;],&lt;br /&gt;
      translateMonsters: defaultLang !== currentLanguage,&lt;br /&gt;
      attacker: {&lt;br /&gt;
        character: {&lt;br /&gt;
          count: 0,&lt;br /&gt;
          container: document.getElementById(&amp;quot;attacker-selection-characters&amp;quot;),&lt;br /&gt;
          elements: {},&lt;br /&gt;
        },&lt;br /&gt;
        monster: {&lt;br /&gt;
          count: 0,&lt;br /&gt;
          container: document.getElementById(&amp;quot;attacker-selection-monsters&amp;quot;),&lt;br /&gt;
          elements: {},&lt;br /&gt;
        },&lt;br /&gt;
        button: document.getElementById(&amp;quot;attacker-trigger&amp;quot;),&lt;br /&gt;
        defaultButtonContent: document.getElementById(&lt;br /&gt;
          &amp;quot;attacker-default-button-content&amp;quot;&lt;br /&gt;
        ),&lt;br /&gt;
        buttonContent: document.getElementById(&amp;quot;attacker-button-content&amp;quot;),&lt;br /&gt;
        container: document.getElementById(&amp;quot;attacker-selection&amp;quot;),&lt;br /&gt;
        selected: null,&lt;br /&gt;
      },&lt;br /&gt;
      victim: {&lt;br /&gt;
        character: {&lt;br /&gt;
          count: 0,&lt;br /&gt;
          container: document.getElementById(&amp;quot;victim-selection-characters&amp;quot;),&lt;br /&gt;
          elements: {},&lt;br /&gt;
        },&lt;br /&gt;
        monster: {&lt;br /&gt;
          count: 0,&lt;br /&gt;
          container: document.getElementById(&amp;quot;victim-selection-monsters&amp;quot;),&lt;br /&gt;
          elements: {},&lt;br /&gt;
        },&lt;br /&gt;
        stone: {&lt;br /&gt;
          count: 0,&lt;br /&gt;
          container: document.getElementById(&amp;quot;victim-selection-stones&amp;quot;),&lt;br /&gt;
          elements: {},&lt;br /&gt;
        },&lt;br /&gt;
        button: document.getElementById(&amp;quot;victim-trigger&amp;quot;),&lt;br /&gt;
        defaultButtonContent: document.getElementById(&lt;br /&gt;
          &amp;quot;victim-default-button-content&amp;quot;&lt;br /&gt;
        ),&lt;br /&gt;
        buttonContent: document.getElementById(&amp;quot;victim-button-content&amp;quot;),&lt;br /&gt;
        selected: null,&lt;br /&gt;
      },&lt;br /&gt;
      attackType: {&lt;br /&gt;
        container: document.getElementById(&amp;quot;attack-type-selection&amp;quot;),&lt;br /&gt;
        elements: [],&lt;br /&gt;
        defaultInput: document.getElementById(&amp;quot;physical-attack&amp;quot;),&lt;br /&gt;
        selectedText: &amp;quot;&amp;quot;,&lt;br /&gt;
      },&lt;br /&gt;
    },&lt;br /&gt;
    damageWeightedByType: {},&lt;br /&gt;
    scatterDataByType: {},&lt;br /&gt;
    damageByBonus: [],&lt;br /&gt;
    tableResultFight: document.getElementById(&amp;quot;result-table-fight&amp;quot;),&lt;br /&gt;
    tableResultHistory: document.getElementById(&amp;quot;result-table-history&amp;quot;),&lt;br /&gt;
    deleteFightTemplate: document.getElementById(&amp;quot;delete-fight-template&amp;quot;)&lt;br /&gt;
      .children[0],&lt;br /&gt;
    errorInformation: {},&lt;br /&gt;
    fightResultTitle: document.getElementById(&amp;quot;fight-result-title&amp;quot;),&lt;br /&gt;
    fightResultContainer: document.getElementById(&amp;quot;fight-result-container&amp;quot;),&lt;br /&gt;
    downLoadRawData: document.getElementById(&amp;quot;download-raw-data&amp;quot;),&lt;br /&gt;
    downLoadRawDataVariation: document.getElementById(&lt;br /&gt;
      &amp;quot;download-raw-data-variation&amp;quot;&lt;br /&gt;
    ),&lt;br /&gt;
    bonusVariationResultContainer: document.getElementById(&lt;br /&gt;
      &amp;quot;bonus-variation-result-container&amp;quot;&lt;br /&gt;
    ),&lt;br /&gt;
    reduceChartPointsContainer: document.getElementById(&lt;br /&gt;
      &amp;quot;reduce-chart-points-container&amp;quot;&lt;br /&gt;
    ),&lt;br /&gt;
    reduceChartPoints: document.getElementById(&amp;quot;reduce-chart-points&amp;quot;),&lt;br /&gt;
    plotDamage: document.getElementById(&amp;quot;plot-damage&amp;quot;),&lt;br /&gt;
    plotBonusVariation: document.getElementById(&amp;quot;plot-bonus-variation&amp;quot;),&lt;br /&gt;
    uniqueDamageCounters: document.querySelectorAll(&amp;quot;.unique-damage-counter&amp;quot;),&lt;br /&gt;
    possibleDamageCounter: document.getElementById(&amp;quot;possible-damage-counter&amp;quot;),&lt;br /&gt;
    damageTime: document.getElementById(&amp;quot;damage-time&amp;quot;),&lt;br /&gt;
    displayTime: document.getElementById(&amp;quot;display-time&amp;quot;),&lt;br /&gt;
    simulationCounter: document.getElementById(&amp;quot;simulation-counter&amp;quot;),&lt;br /&gt;
    simulationTime: document.getElementById(&amp;quot;simulation-time&amp;quot;),&lt;br /&gt;
    numberFormats: {&lt;br /&gt;
      default: new Intl.NumberFormat(currentLanguage, {&lt;br /&gt;
        minimumFractionDigits: 0,&lt;br /&gt;
        maximumFractionDigits: 1,&lt;br /&gt;
      }),&lt;br /&gt;
      percent: new Intl.NumberFormat(currentLanguage, {&lt;br /&gt;
        style: &amp;quot;percent&amp;quot;,&lt;br /&gt;
        maximumFractionDigits: 3,&lt;br /&gt;
      }),&lt;br /&gt;
      second: new Intl.NumberFormat(currentLanguage, {&lt;br /&gt;
        style: &amp;quot;unit&amp;quot;,&lt;br /&gt;
        unit: &amp;quot;second&amp;quot;,&lt;br /&gt;
        unitDisplay: &amp;quot;long&amp;quot;,&lt;br /&gt;
        maximumFractionDigits: 3,&lt;br /&gt;
      }),&lt;br /&gt;
    },&lt;br /&gt;
    mapping: createMapping(),&lt;br /&gt;
    constants: constants,&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  addBattleData(battle);&lt;br /&gt;
  initResultTableHistory(battle);&lt;br /&gt;
  initDamageChart(battle, currentLanguage, defaultText);&lt;br /&gt;
  initBonusVariationChart(battle, currentLanguage, defaultText);&lt;br /&gt;
  reduceChartPointsListener(battle);&lt;br /&gt;
  downloadRawDataListener(battle);&lt;br /&gt;
&lt;br /&gt;
  return [characters, battle];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function parseText(input) {&lt;br /&gt;
  const regex = /\[\[(.*?)\]\]|([^\[]+)/g;&lt;br /&gt;
  const result = [];&lt;br /&gt;
&lt;br /&gt;
  input.replace(regex, (_, matchA, matchText) =&amp;gt; {&lt;br /&gt;
    if (matchA !== undefined) {&lt;br /&gt;
      result.push({&lt;br /&gt;
        text: matchA,&lt;br /&gt;
        category: matchA === &amp;quot;&amp;quot; ? &amp;quot;NOTRANSLATE&amp;quot; : &amp;quot;A&amp;quot;,&lt;br /&gt;
      });&lt;br /&gt;
    } else if (matchText) {&lt;br /&gt;
      result.push({ text: matchText, category: &amp;quot;#text&amp;quot; });&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  return result;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function translateText(general) {&lt;br /&gt;
  const nodesToTranslate = [&amp;quot;A&amp;quot;, &amp;quot;I&amp;quot;, &amp;quot;B&amp;quot;];&lt;br /&gt;
&lt;br /&gt;
  for (const element of document.querySelectorAll(&amp;quot;[data-t]&amp;quot;)) {&lt;br /&gt;
    const translateText = general[element.dataset.t];&lt;br /&gt;
&lt;br /&gt;
    if (!translateText) continue;&lt;br /&gt;
&lt;br /&gt;
    const childNodes = element.childNodes;&lt;br /&gt;
&lt;br /&gt;
    if (childNodes.length === 1) {&lt;br /&gt;
      childNodes[0].textContent = translateText;&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    const parsedText = parseText(translateText);&lt;br /&gt;
&lt;br /&gt;
    let childIndex = 0;&lt;br /&gt;
    let textIndex = 0;&lt;br /&gt;
&lt;br /&gt;
    while (childIndex &amp;lt; childNodes.length) {&lt;br /&gt;
      const child = childNodes[childIndex];&lt;br /&gt;
      const parsed = parsedText[textIndex];&lt;br /&gt;
&lt;br /&gt;
      let childName = child.nodeName;&lt;br /&gt;
      const isNodeToTranslate = nodesToTranslate.includes(childName);&lt;br /&gt;
&lt;br /&gt;
      if (&lt;br /&gt;
        (childName === &amp;quot;A&amp;quot; &amp;amp;&amp;amp; child.firstChild?.nodeName === &amp;quot;IMG&amp;quot;) ||&lt;br /&gt;
        !(isNodeToTranslate || childName === &amp;quot;#text&amp;quot;) ||&lt;br /&gt;
        child.dataset?.notranslate&lt;br /&gt;
      ) {&lt;br /&gt;
        childName = &amp;quot;NOTRANSLATE&amp;quot;;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (&lt;br /&gt;
        childName === parsed.category ||&lt;br /&gt;
        (parsed.category === &amp;quot;A&amp;quot; &amp;amp;&amp;amp; isNodeToTranslate)&lt;br /&gt;
      ) {&lt;br /&gt;
        if (childName !== &amp;quot;NOTRANSLATE&amp;quot;) {&lt;br /&gt;
          child.textContent = parsed.text;&lt;br /&gt;
        }&lt;br /&gt;
        childIndex++;&lt;br /&gt;
        textIndex++;&lt;br /&gt;
      } else if (childName === &amp;quot;NOTRANSLATE&amp;quot;) {&lt;br /&gt;
        childIndex++;&lt;br /&gt;
      } else if (isNodeToTranslate) {&lt;br /&gt;
        element.insertBefore(document.createTextNode(parsed.text), child);&lt;br /&gt;
        textIndex++;&lt;br /&gt;
      } else {&lt;br /&gt;
        child.textContent = &amp;quot;&amp;quot;;&lt;br /&gt;
        childIndex++;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (textIndex &amp;lt; parsedText.length) {&lt;br /&gt;
      const textNode = document.createTextNode(parsedText[textIndex].text);&lt;br /&gt;
      element.appendChild(textNode);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function translateWeapons(weapons) {&lt;br /&gt;
  const characterCreation = document.getElementById(&amp;quot;character-creation&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  for (const weaponInput of characterCreation.elements[&amp;quot;weapon&amp;quot;]) {&lt;br /&gt;
    const weaponTranslation = weapons[weaponInput.value];&lt;br /&gt;
&lt;br /&gt;
    if (weaponTranslation) {&lt;br /&gt;
      weaponInput.parentElement.lastElementChild.textContent =&lt;br /&gt;
        weaponTranslation;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleSpecialIndexes(generalTranslations, specialIndexes) {&lt;br /&gt;
  const specialTranslations = {};&lt;br /&gt;
&lt;br /&gt;
  translation.special = specialTranslations;&lt;br /&gt;
&lt;br /&gt;
  for (const [generalIndex, specialKey] of Object.entries(specialIndexes)) {&lt;br /&gt;
    const translatedValue = generalTranslations[generalIndex];&lt;br /&gt;
&lt;br /&gt;
    if (translatedValue) {&lt;br /&gt;
      specialTranslations[specialKey] = translatedValue;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  translation.mapping = {&lt;br /&gt;
    &amp;quot;Demi-humain&amp;quot;: specialTranslations.halfHuman,&lt;br /&gt;
    Mal: specialTranslations.devil,&lt;br /&gt;
    Désert: specialTranslations.desert,&lt;br /&gt;
    Animal: specialTranslations.animal,&lt;br /&gt;
    Orc: specialTranslations.orc,&lt;br /&gt;
    Mystique: specialTranslations.mystic,&lt;br /&gt;
    &amp;quot;Mort-vivant&amp;quot;: specialTranslations.undead,&lt;br /&gt;
    Insecte: specialTranslations.insect,&lt;br /&gt;
    Zodiaque: specialTranslations.zodiac,&lt;br /&gt;
    &amp;quot;Aucun type&amp;quot;: specialTranslations.noType,&lt;br /&gt;
    Mêlée: specialTranslations.melee,&lt;br /&gt;
    Flèche: specialTranslations.arrow,&lt;br /&gt;
    Magique: specialTranslations.magic,&lt;br /&gt;
    DC: specialTranslations.skill,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function translateTitle() {&lt;br /&gt;
  const translatedTitle = translation.special.pageTitle;&lt;br /&gt;
&lt;br /&gt;
  if (translatedTitle) {&lt;br /&gt;
    document.querySelector(&amp;quot;h1&amp;quot;).textContent = translatedTitle;&lt;br /&gt;
    document.querySelector(&amp;quot;ul.subpage&amp;quot;).lastElementChild.textContent =&lt;br /&gt;
      translatedTitle;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function translateSummary() {&lt;br /&gt;
  const tocContainer = document.getElementById(&amp;quot;toc&amp;quot;);&lt;br /&gt;
  const { toc, hide } = translation.special;&lt;br /&gt;
&lt;br /&gt;
  if (tocContainer) {&lt;br /&gt;
    if (toc) {&lt;br /&gt;
      tocContainer.querySelector(&amp;quot;h2&amp;quot;).textContent = toc;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (hide) {&lt;br /&gt;
      tocContainer.querySelector(&amp;quot;a.togglelink&amp;quot;).textContent = hide;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    for (const link of tocContainer.querySelectorAll(&amp;quot;ul a&amp;quot;)) {&lt;br /&gt;
      const hash = link.hash.substr(1);&lt;br /&gt;
      const title = document.getElementById(hash);&lt;br /&gt;
&lt;br /&gt;
      if (title) {&lt;br /&gt;
        const toctext = link.querySelector(&amp;quot;span.toctext&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        if (toctext) {&lt;br /&gt;
          toctext.firstElementChild.textContent = title.textContent;&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function translateDefaultText(defaultText) {&lt;br /&gt;
  const specialTranslations = translation.special;&lt;br /&gt;
&lt;br /&gt;
  for (const key of Object.keys(defaultText)) {&lt;br /&gt;
    if (specialTranslations.hasOwnProperty(key)) {&lt;br /&gt;
      defaultText[key] = specialTranslations[key];&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function translatePage(defaultText) {&lt;br /&gt;
  const { general, weapons } = translation;&lt;br /&gt;
  const specialIndexes = {&lt;br /&gt;
    471: &amp;quot;placeholder&amp;quot;,&lt;br /&gt;
    473: &amp;quot;boss&amp;quot;,&lt;br /&gt;
    474: &amp;quot;pageTitle&amp;quot;,&lt;br /&gt;
    475: &amp;quot;toc&amp;quot;,&lt;br /&gt;
    476: &amp;quot;hide&amp;quot;,&lt;br /&gt;
    502: &amp;quot;unsavedWarning&amp;quot;,&lt;br /&gt;
    503: &amp;quot;deleteWarning&amp;quot;,&lt;br /&gt;
    504: &amp;quot;pseudo&amp;quot;,&lt;br /&gt;
    481: &amp;quot;damage&amp;quot;,&lt;br /&gt;
    505: &amp;quot;percentage&amp;quot;,&lt;br /&gt;
    506: &amp;quot;miss&amp;quot;,&lt;br /&gt;
    507: &amp;quot;normalHit&amp;quot;,&lt;br /&gt;
    508: &amp;quot;criticalHit&amp;quot;,&lt;br /&gt;
    509: &amp;quot;piercingHit&amp;quot;,&lt;br /&gt;
    510: &amp;quot;criticalPiercingHit&amp;quot;,&lt;br /&gt;
    511: &amp;quot;damageRepartition&amp;quot;,&lt;br /&gt;
    512: &amp;quot;averageDamage&amp;quot;,&lt;br /&gt;
    513: &amp;quot;damageAugmentation&amp;quot;,&lt;br /&gt;
    514: &amp;quot;bonusVariationTitle&amp;quot;,&lt;br /&gt;
    489: &amp;quot;halfHuman&amp;quot;,&lt;br /&gt;
    490: &amp;quot;devil&amp;quot;,&lt;br /&gt;
    491: &amp;quot;desert&amp;quot;,&lt;br /&gt;
    492: &amp;quot;animal&amp;quot;,&lt;br /&gt;
    493: &amp;quot;orc&amp;quot;,&lt;br /&gt;
    494: &amp;quot;mystic&amp;quot;,&lt;br /&gt;
    495: &amp;quot;undead&amp;quot;,&lt;br /&gt;
    496: &amp;quot;insect&amp;quot;,&lt;br /&gt;
    497: &amp;quot;zodiac&amp;quot;,&lt;br /&gt;
    515: &amp;quot;noType&amp;quot;,&lt;br /&gt;
    498: &amp;quot;melee&amp;quot;,&lt;br /&gt;
    499: &amp;quot;arrow&amp;quot;,&lt;br /&gt;
    500: &amp;quot;magic&amp;quot;,&lt;br /&gt;
    516: &amp;quot;skill&amp;quot;,&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  translateText(general);&lt;br /&gt;
  translateWeapons(weapons);&lt;br /&gt;
  handleSpecialIndexes(general, specialIndexes);&lt;br /&gt;
  translateTitle();&lt;br /&gt;
  translateSummary();&lt;br /&gt;
  translateDefaultText(defaultText);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getDefaultText() {&lt;br /&gt;
  return {&lt;br /&gt;
    unsavedWarning:&lt;br /&gt;
      &amp;quot;Voulez-vous continuer ? Les dernières modifications ne seront pas sauvegardées.&amp;quot;,&lt;br /&gt;
    deleteWarning:&lt;br /&gt;
      &amp;quot;Voulez-vous vraiment supprimer définitivement le personnage [[]] ?&amp;quot;,&lt;br /&gt;
    pseudo: &amp;quot;Pseudo&amp;quot;,&lt;br /&gt;
    damage: &amp;quot;Dégâts&amp;quot;,&lt;br /&gt;
    percentage: &amp;quot;Pourcentage&amp;quot;,&lt;br /&gt;
    miss: &amp;quot;Miss&amp;quot;,&lt;br /&gt;
    normalHit: &amp;quot;Coup classique&amp;quot;,&lt;br /&gt;
    criticalHit: &amp;quot;Coup critique&amp;quot;,&lt;br /&gt;
    piercingHit: &amp;quot;Coup perçant&amp;quot;,&lt;br /&gt;
    criticalPiercingHit: &amp;quot;Coup critique perçant&amp;quot;,&lt;br /&gt;
    damageRepartition: &amp;quot;Distribution des dégâts&amp;quot;,&lt;br /&gt;
    averageDamage: &amp;quot;Dégâts moyens&amp;quot;,&lt;br /&gt;
    damageAugmentation: &amp;quot;Augmentation des dégâts&amp;quot;,&lt;br /&gt;
    bonusVariationTitle:&lt;br /&gt;
      &amp;quot;Évolution des dégâts moyens[[]]par rapport à la valeur d'un bonus&amp;quot;,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function setLanguage(radios, lang, url, reload = false) {&lt;br /&gt;
  url.searchParams.set(&amp;quot;lang&amp;quot;, lang);&lt;br /&gt;
  updateLastLang(lang);&lt;br /&gt;
&lt;br /&gt;
  if (reload) {&lt;br /&gt;
    window.location.href = url.toString();&lt;br /&gt;
  } else {&lt;br /&gt;
    radios.value = lang;&lt;br /&gt;
    history.replaceState(null, &amp;quot;&amp;quot;, url);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getCurrentLanguage(defaultLang) {&lt;br /&gt;
  const url = new URL(window.location.href);&lt;br /&gt;
  const URLlang = url.searchParams.get(&amp;quot;lang&amp;quot;);&lt;br /&gt;
  const lastLang = getLastLang();&lt;br /&gt;
  const browserLang = navigator.language.split(&amp;quot;-&amp;quot;)[0];&lt;br /&gt;
  const languageSelection = document.getElementById(&amp;quot;language-selection&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (!languageSelection) {&lt;br /&gt;
    return defaultLang;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  const radios = languageSelection.elements[&amp;quot;country&amp;quot;];&lt;br /&gt;
&lt;br /&gt;
  if (!radios) {&lt;br /&gt;
    return defaultLang;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  languageSelection.addEventListener(&amp;quot;change&amp;quot;, changeLanguage);&lt;br /&gt;
&lt;br /&gt;
  function changeLanguage(event) {&lt;br /&gt;
    const newLang = event.target.value;&lt;br /&gt;
    const newUrl = new URL(window.location.href);&lt;br /&gt;
    setLanguage(radios, newLang, newUrl, true);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  const allowedLanguages = Array.from(radios).map((input) =&amp;gt; input.value);&lt;br /&gt;
&lt;br /&gt;
  for (const lang of [URLlang, lastLang, browserLang]) {&lt;br /&gt;
    if (allowedLanguages.includes(lang)) {&lt;br /&gt;
      setLanguage(radios, lang, url);&lt;br /&gt;
      return lang;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return defaultLang;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadStyle(src) {&lt;br /&gt;
  var link = document.createElement(&amp;quot;link&amp;quot;);&lt;br /&gt;
  link.href = src;&lt;br /&gt;
  link.rel = &amp;quot;stylesheet&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  document.head.appendChild(link);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
async function addScript(src) {&lt;br /&gt;
  return new Promise((resolve, reject) =&amp;gt; {&lt;br /&gt;
    const script = document.createElement(&amp;quot;script&amp;quot;);&lt;br /&gt;
    script.src = src;&lt;br /&gt;
    script.async = true;&lt;br /&gt;
&lt;br /&gt;
    script.onload = () =&amp;gt; resolve();&lt;br /&gt;
    script.onerror = () =&amp;gt; reject(new Error(`Failed to load script: ${src}`));&lt;br /&gt;
&lt;br /&gt;
    document.head.appendChild(script);&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
(async function () {&lt;br /&gt;
  const basePath = &amp;quot;/index.php?title=Utilisateur:Ankhseram/&amp;quot;;&lt;br /&gt;
  const dataScript = `${basePath}WeaponsAndMonsters.js&amp;amp;action=raw&amp;amp;ctype=text/javascript`;&lt;br /&gt;
  const simulatorStyle = `${basePath}SimulatorStyle.css&amp;amp;action=raw&amp;amp;ctype=text/css`;&lt;br /&gt;
  const chartLibrary = &amp;quot;https://cdn.jsdelivr.net/npm/chart.js&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  const defaultLang = &amp;quot;fr&amp;quot;;&lt;br /&gt;
  const defaultText = getDefaultText();&lt;br /&gt;
&lt;br /&gt;
  loadStyle(simulatorStyle);&lt;br /&gt;
&lt;br /&gt;
  const currentLanguage = getCurrentLanguage(defaultLang);&lt;br /&gt;
  let translationScript;&lt;br /&gt;
&lt;br /&gt;
  if (currentLanguage !== defaultLang) {&lt;br /&gt;
    translationScript = `${basePath}Calculator/${currentLanguage}.js&amp;amp;action=raw&amp;amp;ctype=text/javascript`;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  const scriptsToLoad = [addScript(chartLibrary), addScript(dataScript)];&lt;br /&gt;
&lt;br /&gt;
  if (translationScript) {&lt;br /&gt;
    scriptsToLoad.push(addScript(translationScript));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  await Promise.all(scriptsToLoad);&lt;br /&gt;
&lt;br /&gt;
  if (translationScript) {&lt;br /&gt;
    translatePage(defaultText);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  const [characters, battle] = createDamageCalculatorInformation(&lt;br /&gt;
    defaultLang,&lt;br /&gt;
    currentLanguage,&lt;br /&gt;
    defaultText&lt;br /&gt;
  );&lt;br /&gt;
  characterManagement(characters, battle);&lt;br /&gt;
  monsterManagement(characters, battle);&lt;br /&gt;
  updateBattleChoice(characters, battle.battleChoice);&lt;br /&gt;
  createBattle(characters, battle);&lt;br /&gt;
})();&lt;/div&gt;</summary>
		<author><name>Dexter</name></author>
		
	</entry>
	<entry>
		<id>https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Script/Calculator.js&amp;diff=106406</id>
		<title>MediaWiki:Script/Calculator.js</title>
		<link rel="alternate" type="text/html" href="https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Script/Calculator.js&amp;diff=106406"/>
		<updated>2025-02-21T21:30:19Z</updated>

		<summary type="html">&lt;p&gt;Dexter : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;function removeAccent(str) {&lt;br /&gt;
  return str.normalize(&amp;quot;NFD&amp;quot;).replace(/[\u0300-\u036f]/g, &amp;quot;&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function pseudoFormat(str) {&lt;br /&gt;
  return removeAccent(str).replace(/[^A-Za-z0-9 \(\)\+_-]+/g, &amp;quot;&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isValueInArray(value, array) {&lt;br /&gt;
  return array.indexOf(value) !== -1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function splitFirst(value, delimiter) {&lt;br /&gt;
  var parts = value.split(delimiter);&lt;br /&gt;
  var first = parts[0];&lt;br /&gt;
  var rest = parts.slice(1).join(delimiter);&lt;br /&gt;
  return [first, rest];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function copyObject(object) {&lt;br /&gt;
  var copy = {};&lt;br /&gt;
  for (var key in object) {&lt;br /&gt;
    copy[key] = object[key];&lt;br /&gt;
  }&lt;br /&gt;
  return copy;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function compareNumbers(a, b) {&lt;br /&gt;
  return b - a;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isChecked(attribute) {&lt;br /&gt;
  return attribute === &amp;quot;on&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function floorMultiplication(firstFactor, secondFactor) {&lt;br /&gt;
  return Math.floor((firstFactor * secondFactor).toFixed(8));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function truncateNumber(number, precision) {&lt;br /&gt;
  return Math.floor(number * 10 ** precision) / 10 ** precision;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function newChangeEvent() {&lt;br /&gt;
  return new Event(&amp;quot;change&amp;quot;, { bubbles: true });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function openTargetTab(target) {&lt;br /&gt;
  var tabberContainer = target.closest(&amp;quot;.tabber-container&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (!tabberContainer) {&lt;br /&gt;
    return;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var [buttonsContainer, tabsContainer] = tabberContainer.children;&lt;br /&gt;
  var buttons = buttonsContainer.children;&lt;br /&gt;
  var tabs = tabsContainer.children;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; tabs.length; index++) {&lt;br /&gt;
    var tab = tabs[index];&lt;br /&gt;
    if (tab.contains(target) &amp;amp;&amp;amp; !tab.checkVisibility()) {&lt;br /&gt;
      buttons[index].click();&lt;br /&gt;
      break;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function openTargetCollapsible(target) {&lt;br /&gt;
  var collapsible = target.closest(&amp;quot;.improved-collapsible&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (!collapsible) {&lt;br /&gt;
    return;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var span = collapsible.firstElementChild;&lt;br /&gt;
&lt;br /&gt;
  if (!span.classList.contains(&amp;quot;mw-collapsible-toggle-expanded&amp;quot;)) {&lt;br /&gt;
    span.click();&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function editTableResultRow(row, valuesToDisplay, numberFormat) {&lt;br /&gt;
  row.innerHTML = &amp;quot;&amp;quot;;&lt;br /&gt;
  for (var index = 0; index &amp;lt; valuesToDisplay.length; index++) {&lt;br /&gt;
    var cell = row.insertCell();&lt;br /&gt;
    var textContent;&lt;br /&gt;
&lt;br /&gt;
    if (index &amp;gt;= 3) {&lt;br /&gt;
      textContent = numberFormat.format(valuesToDisplay[index]);&lt;br /&gt;
    } else {&lt;br /&gt;
      textContent = valuesToDisplay[index];&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    cell.textContent = textContent;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return row;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addRowToTableResultHistory(&lt;br /&gt;
  tableResultHistory,&lt;br /&gt;
  valuesToDisplay,&lt;br /&gt;
  deleteFightTemplate,&lt;br /&gt;
  numberFormat&lt;br /&gt;
) {&lt;br /&gt;
  var row = tableResultHistory.insertRow();&lt;br /&gt;
  editTableResultRow(row, valuesToDisplay, numberFormat);&lt;br /&gt;
  var cell = row.insertCell();&lt;br /&gt;
  cell.appendChild(deleteFightTemplate.cloneNode(true));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function processSavedDamage(savedDamage, damageWeightedByType, battleValues) {&lt;br /&gt;
  const { damageTypeWeights, attackTypeMapping } = battleValues;&lt;br /&gt;
&lt;br /&gt;
  for (const key in savedDamage) {&lt;br /&gt;
    const [weight, damageByType] = savedDamage[key];&lt;br /&gt;
&lt;br /&gt;
    for (let index = 0; index &amp;lt; 4; index++) {&lt;br /&gt;
      const damageWeighted = damageWeightedByType[attackTypeMapping[index]];&lt;br /&gt;
      const damageByTypeIndex = damageByType[index];&lt;br /&gt;
&lt;br /&gt;
      if (damageByTypeIndex.length === 0) continue;&lt;br /&gt;
&lt;br /&gt;
      const currentWeight =&lt;br /&gt;
        (weight * damageTypeWeights[index]) / damageByTypeIndex.length;&lt;br /&gt;
&lt;br /&gt;
      for (const damage of damageByTypeIndex) {&lt;br /&gt;
        damageWeighted[damage] = (damageWeighted[damage] || 0) + currentWeight;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcMeanDamage(damageWeightedByType, totalCardinal) {&lt;br /&gt;
  var sumDamage = 0;&lt;br /&gt;
&lt;br /&gt;
  for (var damageTypeName in damageWeightedByType) {&lt;br /&gt;
    if (damageTypeName === &amp;quot;miss&amp;quot;) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var damageWeighted = damageWeightedByType[damageTypeName];&lt;br /&gt;
&lt;br /&gt;
    for (var damage in damageWeighted) {&lt;br /&gt;
      sumDamage += damage * damageWeighted[damage];&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return sumDamage / totalCardinal;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function prepareDamageData(damageWeightedByType, attackValues) {&lt;br /&gt;
  const totalCardinal = attackValues.totalCardinal;&lt;br /&gt;
  const scatterDataByType = {};&lt;br /&gt;
  const criticalAttackRange = attackValues.criticalAttackRange;&lt;br /&gt;
&lt;br /&gt;
  let minDamage = Infinity;&lt;br /&gt;
  let maxDamage = 0;&lt;br /&gt;
  let sumDamage = 0;&lt;br /&gt;
&lt;br /&gt;
  let possibleDamageCount = 0;&lt;br /&gt;
  let possibleDamageCountTemp = 0;&lt;br /&gt;
  let uniqueDamageCount = 0;&lt;br /&gt;
&lt;br /&gt;
  for (const damageTypeName in damageWeightedByType) {&lt;br /&gt;
    if (damageTypeName === &amp;quot;miss&amp;quot;) {&lt;br /&gt;
      scatterDataByType.miss = damageWeightedByType.miss;&lt;br /&gt;
      possibleDamageCount++;&lt;br /&gt;
      uniqueDamageCount++;&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
    const damageWeighted = damageWeightedByType[damageTypeName];&lt;br /&gt;
    const scatterData = [];&lt;br /&gt;
&lt;br /&gt;
    scatterDataByType[damageTypeName] = scatterData;&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      (damageTypeName === &amp;quot;criticalHit&amp;quot; ||&lt;br /&gt;
        damageTypeName === &amp;quot;criticalPiercingHit&amp;quot;) &amp;amp;&amp;amp;&lt;br /&gt;
      criticalAttackRange&lt;br /&gt;
    ) {&lt;br /&gt;
      possibleDamageCountTemp =&lt;br /&gt;
        attackValues.possibleDamageCount * criticalAttackRange.length;&lt;br /&gt;
    } else {&lt;br /&gt;
      possibleDamageCountTemp = attackValues.possibleDamageCount;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    for (let damage in damageWeighted) {&lt;br /&gt;
      damage = +damage;&lt;br /&gt;
&lt;br /&gt;
      if (damage &amp;lt; minDamage) {&lt;br /&gt;
        minDamage = damage;&lt;br /&gt;
      }&lt;br /&gt;
      if (damage &amp;gt; maxDamage) {&lt;br /&gt;
        maxDamage = damage;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      const weight = damageWeighted[damage];&lt;br /&gt;
      const probability = weight / totalCardinal;&lt;br /&gt;
&lt;br /&gt;
      sumDamage += damage * weight;&lt;br /&gt;
      damageWeighted[damage] = probability;&lt;br /&gt;
      scatterData.push({ x: damage, y: probability });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    const scatterDataLength = scatterData.length;&lt;br /&gt;
&lt;br /&gt;
    if (!scatterDataLength) {&lt;br /&gt;
      delete scatterDataByType[damageTypeName];&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    possibleDamageCount += possibleDamageCountTemp;&lt;br /&gt;
    uniqueDamageCount += scatterDataLength;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (minDamage === Infinity) {&lt;br /&gt;
    minDamage = 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  attackValues.possibleDamageCount = possibleDamageCount;&lt;br /&gt;
&lt;br /&gt;
  return [&lt;br /&gt;
    sumDamage / totalCardinal,&lt;br /&gt;
    minDamage,&lt;br /&gt;
    maxDamage,&lt;br /&gt;
    scatterDataByType,&lt;br /&gt;
    uniqueDamageCount,&lt;br /&gt;
  ];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function aggregateDamage(scatterData, maxPoints) {&lt;br /&gt;
  var dataLength = scatterData.length;&lt;br /&gt;
  var remainingData = dataLength;&lt;br /&gt;
  var aggregateScatterData = [];&lt;br /&gt;
&lt;br /&gt;
  for (var groupIndex = 0; groupIndex &amp;lt; maxPoints; groupIndex++) {&lt;br /&gt;
    var groupLength = Math.floor(remainingData / (maxPoints - groupIndex));&lt;br /&gt;
    var startIndex = dataLength - remainingData;&lt;br /&gt;
    var aggregateDamage = 0;&lt;br /&gt;
    var aggregateProbability = 0;&lt;br /&gt;
&lt;br /&gt;
    for (var index = startIndex; index &amp;lt; startIndex + groupLength; index++) {&lt;br /&gt;
      var { x: damage, y: probability } = scatterData[index];&lt;br /&gt;
      aggregateDamage += damage * probability;&lt;br /&gt;
      aggregateProbability += probability;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    aggregateScatterData.push({&lt;br /&gt;
      x: aggregateDamage / aggregateProbability,&lt;br /&gt;
      y: aggregateProbability,&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    remainingData -= groupLength;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return aggregateScatterData;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addToDamageChart(&lt;br /&gt;
  scatterDataByType,&lt;br /&gt;
  damageChart,&lt;br /&gt;
  isReducePointsChecked&lt;br /&gt;
) {&lt;br /&gt;
  var { chart, datasetsStyle, maxPoints, reduceChartPointsContainer } =&lt;br /&gt;
    damageChart;&lt;br /&gt;
  var isFirstDataset = true;&lt;br /&gt;
  var datasets = chart.data.datasets;&lt;br /&gt;
&lt;br /&gt;
  datasets.length = 0;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; datasetsStyle.length; index++) {&lt;br /&gt;
    var dataset = copyObject(datasetsStyle[index]);&lt;br /&gt;
&lt;br /&gt;
    if (!scatterDataByType.hasOwnProperty(dataset.name)) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var scatterData = scatterDataByType[dataset.name];&lt;br /&gt;
    var canBeReduced = scatterData.length &amp;gt; 2 * maxPoints;&lt;br /&gt;
&lt;br /&gt;
    dataset.hidden = !isFirstDataset;&lt;br /&gt;
    dataset.canBeReduced = canBeReduced;&lt;br /&gt;
&lt;br /&gt;
    if (canBeReduced &amp;amp;&amp;amp; isReducePointsChecked) {&lt;br /&gt;
      dataset.data = aggregateDamage(scatterData, maxPoints);&lt;br /&gt;
    } else {&lt;br /&gt;
      dataset.data = scatterData;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isFirstDataset) {&lt;br /&gt;
      isFirstDataset = false;&lt;br /&gt;
&lt;br /&gt;
      if (canBeReduced) {&lt;br /&gt;
        showElement(reduceChartPointsContainer);&lt;br /&gt;
&lt;br /&gt;
        if (!isReducePointsChecked) {&lt;br /&gt;
          handleChartAnimations(chart, false);&lt;br /&gt;
        }&lt;br /&gt;
      } else {&lt;br /&gt;
        hideElement(reduceChartPointsContainer);&lt;br /&gt;
        handleChartAnimations(chart, true);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    datasets.push(dataset);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  chart.data.missPercentage = scatterDataByType.miss;&lt;br /&gt;
  chart.update();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addToBonusVariationChart(&lt;br /&gt;
  damageByBonus,&lt;br /&gt;
  augmentationByBonus,&lt;br /&gt;
  xLabel,&lt;br /&gt;
  chart&lt;br /&gt;
) {&lt;br /&gt;
  chart.data.datasets[0].data = damageByBonus;&lt;br /&gt;
  chart.data.datasets[1].data = augmentationByBonus;&lt;br /&gt;
  chart.options.scales.x.title.text = xLabel;&lt;br /&gt;
  chart.update();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleChartAnimations(chart, addAnimations) {&lt;br /&gt;
  chart.options.animation = addAnimations;&lt;br /&gt;
  chart.options.animations.colors = addAnimations;&lt;br /&gt;
  chart.options.animations.x = addAnimations;&lt;br /&gt;
  chart.options.transitions.active.animation.duration = addAnimations * 1000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateDamageChartDescription(&lt;br /&gt;
  uniqueDamageCounters,&lt;br /&gt;
  uniqueDamageCount,&lt;br /&gt;
  formatNumber&lt;br /&gt;
) {&lt;br /&gt;
  uniqueDamageCounters.forEach(function (element) {&lt;br /&gt;
    if (uniqueDamageCount &amp;lt;= 1) {&lt;br /&gt;
      hideElement(element.parentElement);&lt;br /&gt;
    } else {&lt;br /&gt;
      showElement(element.parentElement);&lt;br /&gt;
      element.textContent = formatNumber.format(uniqueDamageCount);&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getMonsterName(monsterVnum) {&lt;br /&gt;
  var monsterAttributes = monsterData[monsterVnum];&lt;br /&gt;
  return monsterAttributes[monsterAttributes.length - 1];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterClass(selectedRace, classChoice, selectValueIsChanged = false) {&lt;br /&gt;
  for (var radioNode of classChoice) {&lt;br /&gt;
    var radioGrandParent = radioNode.parentElement.parentElement;&lt;br /&gt;
&lt;br /&gt;
    if (radioNode.getAttribute(&amp;quot;data-race&amp;quot;) === selectedRace) {&lt;br /&gt;
      if (!selectValueIsChanged) {&lt;br /&gt;
        radioNode.checked = true;&lt;br /&gt;
        selectValueIsChanged = true;&lt;br /&gt;
      }&lt;br /&gt;
      showElement(radioGrandParent);&lt;br /&gt;
    } else {&lt;br /&gt;
      hideElement(radioGrandParent);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterWeapon(&lt;br /&gt;
  selectedRace,&lt;br /&gt;
  weaponElement,&lt;br /&gt;
  weaponCategory,&lt;br /&gt;
  allowedWeaponsPerRace,&lt;br /&gt;
  selectValueIsChanged = false&lt;br /&gt;
) {&lt;br /&gt;
  var allowedWeapons = allowedWeaponsPerRace[selectedRace];&lt;br /&gt;
&lt;br /&gt;
  if (!selectValueIsChanged) {&lt;br /&gt;
    var weaponType = createWeapon(weaponElement.value).type;&lt;br /&gt;
&lt;br /&gt;
    if (!isValueInArray(weaponType, allowedWeapons)) {&lt;br /&gt;
      weaponElement.value = 0;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var children = weaponCategory.children;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; children.length; index++) {&lt;br /&gt;
    var child = children[index];&lt;br /&gt;
&lt;br /&gt;
    if (isValueInArray(index, allowedWeapons)) {&lt;br /&gt;
      showElement(child);&lt;br /&gt;
    } else {&lt;br /&gt;
      hideElement(child);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function changePolymorphValues(characterCreation, monsterVnum, monsterImage) {&lt;br /&gt;
  var { polymorphMonster, polymorphMonsterImage } = characterCreation;&lt;br /&gt;
&lt;br /&gt;
  polymorphMonster.value = monsterVnum;&lt;br /&gt;
  polymorphMonsterImage.value = monsterImage;&lt;br /&gt;
&lt;br /&gt;
  polymorphMonster.dispatchEvent(newChangeEvent());&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function resetImageFromWiki(image) {&lt;br /&gt;
  image.removeAttribute(&amp;quot;srcset&amp;quot;);&lt;br /&gt;
  image.removeAttribute(&amp;quot;data-file-width&amp;quot;);&lt;br /&gt;
  image.removeAttribute(&amp;quot;data-file-height&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleImageFromWiki(image, newSrc) {&lt;br /&gt;
  image.src = newSrc;&lt;br /&gt;
  image.alt = newSrc.split(&amp;quot;/&amp;quot;).pop();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handlePolymorphDisplay(polymorphDisplay, monsterVnum, monsterSrc) {&lt;br /&gt;
  var oldImage = polymorphDisplay.firstChild;&lt;br /&gt;
  var oldLink = oldImage.nextElementSibling;&lt;br /&gt;
  var monsterName = getMonsterName(monsterVnum);&lt;br /&gt;
  var newLink = createWikiLink(monsterName);&lt;br /&gt;
&lt;br /&gt;
  resetImageFromWiki(oldImage);&lt;br /&gt;
  handleImageFromWiki(oldImage, monsterSrc);&lt;br /&gt;
&lt;br /&gt;
  polymorphDisplay.replaceChild(newLink, oldLink);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createWikiLink(pageName) {&lt;br /&gt;
  var wikiLink = document.createElement(&amp;quot;a&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  wikiLink.href = mw.util.getUrl(pageName);&lt;br /&gt;
  wikiLink.title = pageName;&lt;br /&gt;
  wikiLink.textContent = pageName;&lt;br /&gt;
&lt;br /&gt;
  return wikiLink;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSelectedWeapon(weaponCategory) {&lt;br /&gt;
  return weaponCategory.querySelector(&amp;quot;input[type='radio']:checked&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleWeaponDisplay(&lt;br /&gt;
  weaponCategory,&lt;br /&gt;
  weaponDisplay,&lt;br /&gt;
  weaponVnum,&lt;br /&gt;
  newWeapon&lt;br /&gt;
) {&lt;br /&gt;
  var newWeapon = newWeapon || getSelectedWeapon(weaponCategory);&lt;br /&gt;
&lt;br /&gt;
  var newImage = newWeapon.nextElementSibling;&lt;br /&gt;
  var newText = document.createElement(&amp;quot;span&amp;quot;);&lt;br /&gt;
  var oldImage = weaponDisplay.firstChild;&lt;br /&gt;
  var oldText = oldImage.nextElementSibling;&lt;br /&gt;
  var weaponName = newImage.nextElementSibling.dataset.o;&lt;br /&gt;
&lt;br /&gt;
  if (weaponVnum == 0) {&lt;br /&gt;
    newText.textContent = weaponName;&lt;br /&gt;
  } else {&lt;br /&gt;
    var weaponLink = createWikiLink(weaponName);&lt;br /&gt;
    newText.appendChild(weaponLink);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  weaponDisplay.replaceChild(newImage.cloneNode(), oldImage);&lt;br /&gt;
  weaponDisplay.replaceChild(newText, oldText);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterUpgrade(&lt;br /&gt;
  weaponUpgrade,&lt;br /&gt;
  weaponVnum,&lt;br /&gt;
  randomAttackValue,&lt;br /&gt;
  randomMagicAttackValue&lt;br /&gt;
) {&lt;br /&gt;
  var weapon = createWeapon(weaponVnum);&lt;br /&gt;
  var currentUpgrade = Number(weaponUpgrade.value);&lt;br /&gt;
  var weaponUpgradeChildren = weaponUpgrade.children;&lt;br /&gt;
&lt;br /&gt;
  if (weapon.isSerpent) {&lt;br /&gt;
    showElement(randomAttackValue);&lt;br /&gt;
&lt;br /&gt;
    if (weapon.isMagic) {&lt;br /&gt;
      showElement(randomMagicAttackValue);&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    hideElement(randomAttackValue);&lt;br /&gt;
    hideElement(randomMagicAttackValue);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (weapon.maxUpgrade &amp;lt; 1) {&lt;br /&gt;
    hideElement(weaponUpgrade.parentElement);&lt;br /&gt;
  } else {&lt;br /&gt;
    showElement(weaponUpgrade.parentElement);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (var upgrade = 0; upgrade &amp;lt;= weapon.maxUpgrade; upgrade++) {&lt;br /&gt;
    showElement(weaponUpgradeChildren[upgrade]);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (&lt;br /&gt;
    var upgrade = weapon.maxUpgrade + 1;&lt;br /&gt;
    upgrade &amp;lt; weaponUpgradeChildren.length;&lt;br /&gt;
    upgrade++&lt;br /&gt;
  ) {&lt;br /&gt;
    hideElement(weaponUpgradeChildren[upgrade]);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (currentUpgrade &amp;gt; weapon.maxUpgrade) {&lt;br /&gt;
    weaponUpgrade.value = weapon.maxUpgrade;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterCheckbox(checkbox, element) {&lt;br /&gt;
  if (checkbox.checked) {&lt;br /&gt;
    showElement(element);&lt;br /&gt;
  } else {&lt;br /&gt;
    hideElement(element);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterSkills(selectedClass, skillElementsToFilter) {&lt;br /&gt;
  for (var element of skillElementsToFilter) {&lt;br /&gt;
    if (isValueInArray(selectedClass, element.dataset.class)) {&lt;br /&gt;
      showElement(element);&lt;br /&gt;
    } else {&lt;br /&gt;
      hideElement(element);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterForm(characters, battle) {&lt;br /&gt;
  var { saveButton, characterCreation, toggleSiblings } = characters;&lt;br /&gt;
  var allowedWeaponsPerRace = battle.constants.allowedWeaponsPerRace;&lt;br /&gt;
  var battleChoice = battle.battleChoice;&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;change&amp;quot;, function (event) {&lt;br /&gt;
    var target = event.target;&lt;br /&gt;
    var targetName = target.name;&lt;br /&gt;
&lt;br /&gt;
    saveButtonOrange(saveButton);&lt;br /&gt;
    characters.unsavedChanges = true;&lt;br /&gt;
&lt;br /&gt;
    switch (targetName) {&lt;br /&gt;
      case &amp;quot;race&amp;quot;:&lt;br /&gt;
        var selectedRace = target.value;&lt;br /&gt;
        var classChoice = characterCreation.class;&lt;br /&gt;
        var weaponElement = characterCreation.weapon;&lt;br /&gt;
&lt;br /&gt;
        filterClass(selectedRace, classChoice);&lt;br /&gt;
        filterWeapon(&lt;br /&gt;
          selectedRace,&lt;br /&gt;
          weaponElement,&lt;br /&gt;
          characters.weaponCategory,&lt;br /&gt;
          allowedWeaponsPerRace&lt;br /&gt;
        );&lt;br /&gt;
        handleWeaponDisplay(&lt;br /&gt;
          characters.weaponCategory,&lt;br /&gt;
          characters.weaponDisplay,&lt;br /&gt;
          weaponElement.value&lt;br /&gt;
        );&lt;br /&gt;
        filterUpgrade(&lt;br /&gt;
          characterCreation.weaponUpgrade,&lt;br /&gt;
          weaponElement.value,&lt;br /&gt;
          characters.randomAttackValue,&lt;br /&gt;
          characters.randomMagicAttackValue&lt;br /&gt;
        );&lt;br /&gt;
        filterSkills(classChoice.value, characters.skillElementsToFilter);&lt;br /&gt;
        handleBonusVariationUpdate(&lt;br /&gt;
          characterCreation,&lt;br /&gt;
          characters.bonusVariation,&lt;br /&gt;
          true&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        battleChoice.resetAttackType = true;&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;class&amp;quot;:&lt;br /&gt;
        filterSkills(target.value, characters.skillElementsToFilter);&lt;br /&gt;
        handleBonusVariationUpdate(&lt;br /&gt;
          characterCreation,&lt;br /&gt;
          characters.bonusVariation,&lt;br /&gt;
          true&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        battleChoice.resetAttackType = true;&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;weapon&amp;quot;:&lt;br /&gt;
        var weaponElement = characterCreation.weapon;&lt;br /&gt;
&lt;br /&gt;
        handleWeaponDisplay(&lt;br /&gt;
          characters.weaponCategory,&lt;br /&gt;
          characters.weaponDisplay,&lt;br /&gt;
          weaponElement.value,&lt;br /&gt;
          target&lt;br /&gt;
        );&lt;br /&gt;
        filterUpgrade(&lt;br /&gt;
          characterCreation.weaponUpgrade,&lt;br /&gt;
          target.value,&lt;br /&gt;
          characters.randomAttackValue,&lt;br /&gt;
          characters.randomMagicAttackValue&lt;br /&gt;
        );&lt;br /&gt;
        handleBonusVariationUpdate(&lt;br /&gt;
          characterCreation,&lt;br /&gt;
          characters.bonusVariation&lt;br /&gt;
        );&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;isRiding&amp;quot;:&lt;br /&gt;
        battleChoice.resetAttackType = true;&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;isPolymorph&amp;quot;:&lt;br /&gt;
        battleChoice.resetAttackType = true;&lt;br /&gt;
        break;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (toggleSiblings.hasOwnProperty(targetName)) {&lt;br /&gt;
      filterCheckbox(target, toggleSiblings[targetName]);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      targetName.startsWith(&amp;quot;attackSkill&amp;quot;) ||&lt;br /&gt;
      targetName.startsWith(&amp;quot;horseSkill&amp;quot;)&lt;br /&gt;
    ) {&lt;br /&gt;
      battleChoice.resetAttackType = true;&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addUniquePseudo(characterDataObject, savedCharactersPseudo) {&lt;br /&gt;
  var characterPseudo = String(characterDataObject.name);&lt;br /&gt;
  var originalPseudo = characterPseudo;&lt;br /&gt;
  var count = 0;&lt;br /&gt;
&lt;br /&gt;
  var regex = /(.*)(\d)$/;&lt;br /&gt;
  var match = characterPseudo.match(regex);&lt;br /&gt;
&lt;br /&gt;
  if (match) {&lt;br /&gt;
    originalPseudo = match[1];&lt;br /&gt;
    count = match[2];&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  while (isValueInArray(characterPseudo, savedCharactersPseudo)) {&lt;br /&gt;
    characterPseudo = originalPseudo + count;&lt;br /&gt;
    count++;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  characterDataObject.name = characterPseudo;&lt;br /&gt;
  return [characterDataObject, characterPseudo];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function convertToNumber(value) {&lt;br /&gt;
  var valueNumber = Number(value);&lt;br /&gt;
  return isNaN(valueNumber) ? value : valueNumber;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getLocalStorageValue(key, defaultValue) {&lt;br /&gt;
  var storedValue = localStorage.getItem(key);&lt;br /&gt;
&lt;br /&gt;
  if (storedValue) {&lt;br /&gt;
    return JSON.parse(storedValue);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return defaultValue;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSavedCharacters() {&lt;br /&gt;
  return getLocalStorageValue(&amp;quot;savedCharactersCalculator&amp;quot;, {});&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSavedMonsters() {&lt;br /&gt;
  var savedMonsters = getLocalStorageValue(&amp;quot;savedMonstersCalculator&amp;quot;, {});&lt;br /&gt;
&lt;br /&gt;
  if (Array.isArray(savedMonsters)) {&lt;br /&gt;
    return {};&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var filteredMonsters = {};&lt;br /&gt;
&lt;br /&gt;
  for (var vnum in savedMonsters) {&lt;br /&gt;
    if (&lt;br /&gt;
      String(Number(vnum)) === vnum &amp;amp;&amp;amp;&lt;br /&gt;
      savedMonsters[vnum].hasOwnProperty(&amp;quot;category&amp;quot;)&lt;br /&gt;
    ) {&lt;br /&gt;
      filteredMonsters[vnum] = savedMonsters[vnum];&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  updateSavedMonsters(filteredMonsters);&lt;br /&gt;
&lt;br /&gt;
  return filteredMonsters;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSavedFights() {&lt;br /&gt;
  return getLocalStorageValue(&amp;quot;savedFightsCalculator&amp;quot;, []);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveToLocalStorage(key, value) {&lt;br /&gt;
  localStorage.setItem(key, JSON.stringify(value));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateSavedCharacters(savedCharacters) {&lt;br /&gt;
  saveToLocalStorage(&amp;quot;savedCharactersCalculator&amp;quot;, savedCharacters);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateSavedMonsters(savedMonsters) {&lt;br /&gt;
  saveToLocalStorage(&amp;quot;savedMonstersCalculator&amp;quot;, savedMonsters);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateSavedFights(savedFights) {&lt;br /&gt;
  saveToLocalStorage(&amp;quot;savedFightsCalculator&amp;quot;, savedFights);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveCharacter(&lt;br /&gt;
  savedCharacters,&lt;br /&gt;
  characterCreation,&lt;br /&gt;
  battle,&lt;br /&gt;
  newCharacter,&lt;br /&gt;
  characterDataObject&lt;br /&gt;
) {&lt;br /&gt;
  if (!characterDataObject) {&lt;br /&gt;
    var characterData = new FormData(characterCreation);&lt;br /&gt;
    var characterDataObject = {};&lt;br /&gt;
&lt;br /&gt;
    characterData.forEach(function (value, key) {&lt;br /&gt;
      characterDataObject[key] = convertToNumber(value);&lt;br /&gt;
    });&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var characterPseudo = characterDataObject.name;&lt;br /&gt;
  var { battleChoice } = battle;&lt;br /&gt;
&lt;br /&gt;
  savedCharacters[characterPseudo] = characterDataObject;&lt;br /&gt;
  updateSavedCharacters(savedCharacters);&lt;br /&gt;
&lt;br /&gt;
  if (newCharacter) {&lt;br /&gt;
    addBattleChoice(battleChoice, characterPseudo, characterDataObject);&lt;br /&gt;
  } else {&lt;br /&gt;
    updateBattleChoiceImage(&lt;br /&gt;
      battleChoice,&lt;br /&gt;
      characterPseudo,&lt;br /&gt;
      characterDataObject.race&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (battleChoice.resetAttackType) {&lt;br /&gt;
    if (isCharacterSelected(characterPseudo, battleChoice.attacker.selected)) {&lt;br /&gt;
      filterAttackTypeSelectionCharacter(&lt;br /&gt;
        characterDataObject,&lt;br /&gt;
        battleChoice.attackType&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
    battleChoice.resetAttackType = false;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveButtonGreen(saveButton) {&lt;br /&gt;
  saveButton.classList.remove(&amp;quot;unsaved-character&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveButtonOrange(saveButton) {&lt;br /&gt;
  saveButton.classList.add(&amp;quot;unsaved-character&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function characterCreationListener(characters, battle) {&lt;br /&gt;
  var { characterCreation, saveButton, weaponCategory } = characters;&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;submit&amp;quot;, handleSubmitForm);&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;invalid&amp;quot;, handleInvalidInput, true);&lt;br /&gt;
  document.addEventListener(&amp;quot;keydown&amp;quot;, handleSaveShortcut);&lt;br /&gt;
  weaponCategory.addEventListener(&amp;quot;mouseover&amp;quot;, handleTooltipOverflow);&lt;br /&gt;
&lt;br /&gt;
  function handleSubmitForm(event) {&lt;br /&gt;
    event.preventDefault();&lt;br /&gt;
&lt;br /&gt;
    if (characters.unsavedChanges) {&lt;br /&gt;
      saveCharacter(characters.savedCharacters, characterCreation, battle);&lt;br /&gt;
      saveButtonGreen(saveButton);&lt;br /&gt;
      characters.unsavedChanges = false;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function handleInvalidInput(event) {&lt;br /&gt;
    var target = event.target;&lt;br /&gt;
&lt;br /&gt;
    if (target.checkVisibility()) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var autoCorrectInput = target.closest(&amp;quot;.auto-correct-input&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      autoCorrectInput &amp;amp;&amp;amp;&lt;br /&gt;
      autoCorrectInput.classList.contains(&amp;quot;tabber-noactive&amp;quot;)&lt;br /&gt;
    ) {&lt;br /&gt;
      target.value = target.defaultValue;&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    openTargetTab(target);&lt;br /&gt;
    openTargetCollapsible(target);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function handleSaveShortcut(event) {&lt;br /&gt;
    if (event.ctrlKey &amp;amp;&amp;amp; event.key === &amp;quot;s&amp;quot;) {&lt;br /&gt;
      event.preventDefault();&lt;br /&gt;
      saveButton.click();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function handleTooltipOverflow(event) {&lt;br /&gt;
    var label = event.target.closest(&amp;quot;label&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (label) {&lt;br /&gt;
      var tooltip = label.lastChild;&lt;br /&gt;
&lt;br /&gt;
      if (tooltip.classList.contains(&amp;quot;popContenu&amp;quot;)) {&lt;br /&gt;
        var tooltipRect = tooltip.getBoundingClientRect();&lt;br /&gt;
        var modalRect = weaponCategory.getBoundingClientRect();&lt;br /&gt;
&lt;br /&gt;
        if (tooltipRect.right &amp;gt; modalRect.right) {&lt;br /&gt;
          tooltip.style.left = &amp;quot;-100%&amp;quot;;&lt;br /&gt;
        } else if (tooltipRect.left &amp;lt; modalRect.left) {&lt;br /&gt;
          tooltip.style.left = &amp;quot;200%&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function downloadData(content, type, filename) {&lt;br /&gt;
  var link = document.createElement(&amp;quot;a&amp;quot;);&lt;br /&gt;
  var blob = new Blob([content], { type: type });&lt;br /&gt;
  var blobURL = URL.createObjectURL(blob);&lt;br /&gt;
&lt;br /&gt;
  link.href = blobURL;&lt;br /&gt;
  link.download = filename;&lt;br /&gt;
  document.body.appendChild(link);&lt;br /&gt;
&lt;br /&gt;
  link.click();&lt;br /&gt;
  document.body.removeChild(link);&lt;br /&gt;
  URL.revokeObjectURL(blobURL);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function uploadCharacter(&lt;br /&gt;
  selectedFiles,&lt;br /&gt;
  characters,&lt;br /&gt;
  characterTemplate,&lt;br /&gt;
  charactersContainer,&lt;br /&gt;
  battle&lt;br /&gt;
) {&lt;br /&gt;
  var selectFilesLength = selectedFiles.length;&lt;br /&gt;
&lt;br /&gt;
  for (var fileIndex = 0; fileIndex &amp;lt; selectFilesLength; fileIndex++) {&lt;br /&gt;
    var selectedFile = selectedFiles[fileIndex];&lt;br /&gt;
&lt;br /&gt;
    if (selectedFile.type === &amp;quot;text/plain&amp;quot;) {&lt;br /&gt;
      var reader = new FileReader();&lt;br /&gt;
      reader.onload = function (e) {&lt;br /&gt;
        var fileContent = e.target.result;&lt;br /&gt;
        try {&lt;br /&gt;
          var characterDataObject = JSON.parse(fileContent);&lt;br /&gt;
&lt;br /&gt;
          if (characterDataObject.hasOwnProperty(&amp;quot;name&amp;quot;)) {&lt;br /&gt;
            var characterPseudo = String(characterDataObject.name);&lt;br /&gt;
&lt;br /&gt;
            hideElement(characters.characterCreation);&lt;br /&gt;
            characterPseudo = validPseudo(characterPseudo);&lt;br /&gt;
&lt;br /&gt;
            [characterDataObject, characterPseudo] = addUniquePseudo(&lt;br /&gt;
              characterDataObject,&lt;br /&gt;
              Object.keys(characters.savedCharacters)&lt;br /&gt;
            );&lt;br /&gt;
            var selectedCharacter = handleNewCharacter(&lt;br /&gt;
              characters,&lt;br /&gt;
              characterTemplate,&lt;br /&gt;
              charactersContainer,&lt;br /&gt;
              battle,&lt;br /&gt;
              characterPseudo&lt;br /&gt;
            )[0];&lt;br /&gt;
&lt;br /&gt;
            if (selectFilesLength === 1) {&lt;br /&gt;
              updateForm(&lt;br /&gt;
                characterDataObject,&lt;br /&gt;
                characters.characterCreation,&lt;br /&gt;
                characters,&lt;br /&gt;
                selectedCharacter,&lt;br /&gt;
                battle&lt;br /&gt;
              );&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            saveCharacter(&lt;br /&gt;
              characters.savedCharacters,&lt;br /&gt;
              characters.characterCreation,&lt;br /&gt;
              battle,&lt;br /&gt;
              true,&lt;br /&gt;
              characterDataObject&lt;br /&gt;
            );&lt;br /&gt;
          }&lt;br /&gt;
        } catch (error) {&lt;br /&gt;
          console.warn(error);&lt;br /&gt;
          if (error.name === &amp;quot;TypeError&amp;quot;) {&lt;br /&gt;
            // delete the character&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
      };&lt;br /&gt;
      reader.readAsText(selectedFile);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleUploadCharacter(&lt;br /&gt;
  characters,&lt;br /&gt;
  characterTemplate,&lt;br /&gt;
  charactersContainer,&lt;br /&gt;
  battle&lt;br /&gt;
) {&lt;br /&gt;
  var characterInput = characters.characterInput;&lt;br /&gt;
  var dropZone = characters.dropZone;&lt;br /&gt;
&lt;br /&gt;
  characterInput.accept = &amp;quot;.txt&amp;quot;;&lt;br /&gt;
  characterInput.multiple = true;&lt;br /&gt;
  dropZone.setAttribute(&amp;quot;tabindex&amp;quot;, &amp;quot;0&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  dropZone.addEventListener(&amp;quot;click&amp;quot;, function () {&lt;br /&gt;
    characterInput.click();&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  dropZone.addEventListener(&amp;quot;dragover&amp;quot;, function (event) {&lt;br /&gt;
    event.preventDefault();&lt;br /&gt;
    dropZone.classList.add(&amp;quot;drop-zone--dragover&amp;quot;);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  [&amp;quot;dragleave&amp;quot;, &amp;quot;dragend&amp;quot;].forEach(function (type) {&lt;br /&gt;
    dropZone.addEventListener(type, function () {&lt;br /&gt;
      dropZone.classList.remove(&amp;quot;drop-zone--dragover&amp;quot;);&lt;br /&gt;
    });&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  dropZone.addEventListener(&amp;quot;drop&amp;quot;, function (event) {&lt;br /&gt;
    event.preventDefault();&lt;br /&gt;
    uploadCharacter(&lt;br /&gt;
      event.dataTransfer.files,&lt;br /&gt;
      characters,&lt;br /&gt;
      characterTemplate,&lt;br /&gt;
      charactersContainer,&lt;br /&gt;
      battle&lt;br /&gt;
    );&lt;br /&gt;
    dropZone.classList.remove(&amp;quot;drop-zone--dragover&amp;quot;);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  characterInput.addEventListener(&amp;quot;change&amp;quot;, function (event) {&lt;br /&gt;
    uploadCharacter(&lt;br /&gt;
      event.target.files,&lt;br /&gt;
      characters,&lt;br /&gt;
      characterTemplate,&lt;br /&gt;
      charactersContainer,&lt;br /&gt;
      battle&lt;br /&gt;
    );&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function deleteCharacter(characters, pseudo, element, battle) {&lt;br /&gt;
  delete characters.savedCharacters[pseudo];&lt;br /&gt;
  element.remove();&lt;br /&gt;
&lt;br /&gt;
  updateSavedCharacters(characters.savedCharacters);&lt;br /&gt;
  removeBattleChoice(battle.battleChoice, pseudo, &amp;quot;character&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (&lt;br /&gt;
    !Object.keys(characters.savedCharacters).length ||&lt;br /&gt;
    characters.characterCreation.name.value === pseudo&lt;br /&gt;
  ) {&lt;br /&gt;
    saveButtonGreen(characters.saveButton);&lt;br /&gt;
    characters.unsavedChanges = false;&lt;br /&gt;
    hideElement(characters.characterCreation);&lt;br /&gt;
    showElement(characters.characterCreation.previousElementSibling);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function deleteMonster(characters, battle, monsterVnum) {&lt;br /&gt;
  var monsterElements = characters.monsterElements;&lt;br /&gt;
  var monsterType = characters.savedMonsters[monsterVnum].category;&lt;br /&gt;
&lt;br /&gt;
  if (monsterElements.hasOwnProperty(monsterVnum)) {&lt;br /&gt;
    monsterElements[monsterVnum].remove();&lt;br /&gt;
    delete monsterElements[monsterVnum];&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  delete characters.savedMonsters[monsterVnum];&lt;br /&gt;
&lt;br /&gt;
  updateSavedMonsters(characters.savedMonsters);&lt;br /&gt;
  removeBattleChoice(battle.battleChoice, monsterVnum, monsterType);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleStyle(characters, selectedElement) {&lt;br /&gt;
  var currentCharacter = characters.currentCharacter;&lt;br /&gt;
&lt;br /&gt;
  if (currentCharacter) {&lt;br /&gt;
    currentCharacter.classList.remove(&amp;quot;selected-character&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  selectedElement.classList.add(&amp;quot;selected-character&amp;quot;);&lt;br /&gt;
  characters.currentCharacter = selectedElement;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateForm(&lt;br /&gt;
  formData,&lt;br /&gt;
  characterCreation,&lt;br /&gt;
  characters,&lt;br /&gt;
  selectedElement,&lt;br /&gt;
  battle&lt;br /&gt;
) {&lt;br /&gt;
  saveButtonGreen(characters.saveButton);&lt;br /&gt;
  hideElement(characterCreation.previousElementSibling);&lt;br /&gt;
  showElement(characterCreation);&lt;br /&gt;
  handleStyle(characters, selectedElement);&lt;br /&gt;
&lt;br /&gt;
  characterCreation.reset();&lt;br /&gt;
&lt;br /&gt;
  for (var [name, value] of Object.entries(formData)) {&lt;br /&gt;
    var formElement = characterCreation[name];&lt;br /&gt;
&lt;br /&gt;
    if (!formElement) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (formElement.type === &amp;quot;checkbox&amp;quot;) {&lt;br /&gt;
      if (isChecked(value)) {&lt;br /&gt;
        formElement.checked = true;&lt;br /&gt;
      }&lt;br /&gt;
    } else {&lt;br /&gt;
      formElement.value = value;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  var selectedRace = characterCreation.race.value;&lt;br /&gt;
  var classChoice = characterCreation.class;&lt;br /&gt;
  var weaponElement = characterCreation.weapon;&lt;br /&gt;
&lt;br /&gt;
  filterClass(selectedRace, classChoice, true);&lt;br /&gt;
  filterWeapon(&lt;br /&gt;
    selectedRace,&lt;br /&gt;
    weaponElement,&lt;br /&gt;
    characters.weaponCategory,&lt;br /&gt;
    battle.constants.allowedWeaponsPerRace,&lt;br /&gt;
    true&lt;br /&gt;
  );&lt;br /&gt;
  handlePolymorphDisplay(&lt;br /&gt;
    characters.polymorphDisplay,&lt;br /&gt;
    characterCreation.polymorphMonster.value,&lt;br /&gt;
    characterCreation.polymorphMonsterImage.value&lt;br /&gt;
  );&lt;br /&gt;
  handleWeaponDisplay(&lt;br /&gt;
    characters.weaponCategory,&lt;br /&gt;
    characters.weaponDisplay,&lt;br /&gt;
    weaponElement.value&lt;br /&gt;
  );&lt;br /&gt;
  filterUpgrade(&lt;br /&gt;
    characterCreation.weaponUpgrade,&lt;br /&gt;
    weaponElement.value,&lt;br /&gt;
    characters.randomAttackValue,&lt;br /&gt;
    characters.randomMagicAttackValue&lt;br /&gt;
  );&lt;br /&gt;
  for (var [targetName, sibling] of Object.entries(characters.toggleSiblings)) {&lt;br /&gt;
    filterCheckbox(characterCreation[targetName], sibling);&lt;br /&gt;
  }&lt;br /&gt;
  filterSkills(classChoice.value, characters.skillElementsToFilter);&lt;br /&gt;
  handleBonusVariationUpdate(characterCreation, characters.bonusVariation);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleClickOnCharacter(&lt;br /&gt;
  spanInput,&lt;br /&gt;
  target,&lt;br /&gt;
  characters,&lt;br /&gt;
  characterElement,&lt;br /&gt;
  battle,&lt;br /&gt;
  edition&lt;br /&gt;
) {&lt;br /&gt;
  var displayedPseudo = characters.characterCreation.name.value;&lt;br /&gt;
  var pseudo = spanInput.dataset.name;&lt;br /&gt;
&lt;br /&gt;
  if (edition) {&lt;br /&gt;
    if (!characters.unsavedChanges) {&lt;br /&gt;
      updateForm(&lt;br /&gt;
        characters.savedCharacters[pseudo],&lt;br /&gt;
        characters.characterCreation,&lt;br /&gt;
        characters,&lt;br /&gt;
        characterElement,&lt;br /&gt;
        battle&lt;br /&gt;
      );&lt;br /&gt;
    } else if (displayedPseudo === pseudo) {&lt;br /&gt;
      // pass&lt;br /&gt;
    } else {&lt;br /&gt;
      var result = confirm(&lt;br /&gt;
        &amp;quot;Voulez-vous continuer ? Les dernières modifications ne seront pas sauvegardées.&amp;quot;&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      if (result) {&lt;br /&gt;
        updateForm(&lt;br /&gt;
          characters.savedCharacters[pseudo],&lt;br /&gt;
          characters.characterCreation,&lt;br /&gt;
          characters,&lt;br /&gt;
          characterElement,&lt;br /&gt;
          battle&lt;br /&gt;
        );&lt;br /&gt;
        characters.unsavedChanges = false;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    if (target.tagName === &amp;quot;path&amp;quot;) {&lt;br /&gt;
      target = target.parentElement;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    switch (target.dataset.icon) {&lt;br /&gt;
      case &amp;quot;duplicate&amp;quot;:&lt;br /&gt;
        if (!characters.unsavedChanges) {&lt;br /&gt;
          addNewCharacter(&lt;br /&gt;
            characters,&lt;br /&gt;
            characters.newCharacterTemplate,&lt;br /&gt;
            characters.charactersContainer,&lt;br /&gt;
            battle,&lt;br /&gt;
            pseudo&lt;br /&gt;
          );&lt;br /&gt;
        } else {&lt;br /&gt;
          var result = confirm(&lt;br /&gt;
            &amp;quot;Voulez-vous continuer ? Les dernières modifications ne seront pas sauvegardées.&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
&lt;br /&gt;
          if (result) {&lt;br /&gt;
            addNewCharacter(&lt;br /&gt;
              characters,&lt;br /&gt;
              characters.newCharacterTemplate,&lt;br /&gt;
              characters.charactersContainer,&lt;br /&gt;
              battle,&lt;br /&gt;
              pseudo&lt;br /&gt;
            );&lt;br /&gt;
            saveButtonGreen(characters.saveButton);&lt;br /&gt;
            characters.unsavedChanges = false;&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
        break;&lt;br /&gt;
&lt;br /&gt;
      case &amp;quot;download&amp;quot;:&lt;br /&gt;
        var character = characters.savedCharacters[pseudo];&lt;br /&gt;
        downloadData(&lt;br /&gt;
          JSON.stringify(character),&lt;br /&gt;
          &amp;quot;text/plain&amp;quot;,&lt;br /&gt;
          character.name + &amp;quot;.txt&amp;quot;&lt;br /&gt;
        );&lt;br /&gt;
        break;&lt;br /&gt;
&lt;br /&gt;
      case &amp;quot;delete&amp;quot;:&lt;br /&gt;
        var result = confirm(&lt;br /&gt;
          &amp;quot;Voulez-vous vraiment supprimer définitivement le personnage &amp;quot; +&lt;br /&gt;
            pseudo +&lt;br /&gt;
            &amp;quot; ?&amp;quot;&lt;br /&gt;
        );&lt;br /&gt;
        if (result) {&lt;br /&gt;
          deleteCharacter(characters, pseudo, characterElement, battle);&lt;br /&gt;
        }&lt;br /&gt;
        break;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleNewCharacter(&lt;br /&gt;
  characters,&lt;br /&gt;
  characterTemplate,&lt;br /&gt;
  charactersContainer,&lt;br /&gt;
  battle,&lt;br /&gt;
  pseudo&lt;br /&gt;
) {&lt;br /&gt;
  var newCharacterTemplate = characterTemplate.cloneNode(true);&lt;br /&gt;
  var spanInput = newCharacterTemplate.querySelector(&amp;quot;span.input&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  newCharacterTemplate.setAttribute(&amp;quot;tabindex&amp;quot;, &amp;quot;0&amp;quot;);&lt;br /&gt;
  charactersContainer.appendChild(newCharacterTemplate);&lt;br /&gt;
&lt;br /&gt;
  if (pseudo) {&lt;br /&gt;
    spanInput.textContent = pseudo;&lt;br /&gt;
    spanInput.setAttribute(&amp;quot;data-name&amp;quot;, pseudo);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  newCharacterTemplate.addEventListener(&amp;quot;click&amp;quot;, function (event) {&lt;br /&gt;
    var target = event.target;&lt;br /&gt;
&lt;br /&gt;
    if (target.tagName === &amp;quot;path&amp;quot; || target.tagName === &amp;quot;svg&amp;quot;) {&lt;br /&gt;
      handleClickOnCharacter(&lt;br /&gt;
        spanInput,&lt;br /&gt;
        target,&lt;br /&gt;
        characters,&lt;br /&gt;
        newCharacterTemplate,&lt;br /&gt;
        battle&lt;br /&gt;
      );&lt;br /&gt;
    } else {&lt;br /&gt;
      handleClickOnCharacter(&lt;br /&gt;
        spanInput,&lt;br /&gt;
        null,&lt;br /&gt;
        characters,&lt;br /&gt;
        newCharacterTemplate,&lt;br /&gt;
        battle,&lt;br /&gt;
        true&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  newCharacterTemplate.addEventListener(&amp;quot;keydown&amp;quot;, function (event) {&lt;br /&gt;
    if (event.keyCode === 13) {&lt;br /&gt;
      event.target.click();&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  return [newCharacterTemplate, spanInput];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function validPseudo(pseudo) {&lt;br /&gt;
  var newPseudo = pseudoFormat(pseudo);&lt;br /&gt;
&lt;br /&gt;
  if (!newPseudo) {&lt;br /&gt;
    return &amp;quot;Pseudo&amp;quot;;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return newPseudo;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addNewCharacter(&lt;br /&gt;
  characters,&lt;br /&gt;
  characterTemplate,&lt;br /&gt;
  charactersContainer,&lt;br /&gt;
  battle,&lt;br /&gt;
  pseudoToDuplicate&lt;br /&gt;
) {&lt;br /&gt;
  function editAndSetCharacterPseudoInput(selectedCharacter, spanInput) {&lt;br /&gt;
    var maxPseudoLength = 20;&lt;br /&gt;
&lt;br /&gt;
    var selection = window.getSelection();&lt;br /&gt;
    var range = document.createRange();&lt;br /&gt;
&lt;br /&gt;
    if (pseudoToDuplicate) {&lt;br /&gt;
      spanInput.textContent = pseudoToDuplicate;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    spanInput.contentEditable = true;&lt;br /&gt;
    spanInput.focus();&lt;br /&gt;
    range.selectNodeContents(spanInput);&lt;br /&gt;
    selection.removeAllRanges();&lt;br /&gt;
    selection.addRange(range);&lt;br /&gt;
&lt;br /&gt;
    function pseudoValidation() {&lt;br /&gt;
      var characterPseudo = validPseudo(spanInput.textContent);&lt;br /&gt;
      var characterDataObject = { name: characterPseudo };&lt;br /&gt;
&lt;br /&gt;
      if (pseudoToDuplicate) {&lt;br /&gt;
        characterDataObject = copyObject(&lt;br /&gt;
          characters.savedCharacters[pseudoToDuplicate]&lt;br /&gt;
        );&lt;br /&gt;
        characterDataObject.name = characterPseudo;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      [characterDataObject, characterPseudo] = addUniquePseudo(&lt;br /&gt;
        characterDataObject,&lt;br /&gt;
        Object.keys(characters.savedCharacters)&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      selection.removeAllRanges();&lt;br /&gt;
      spanInput.contentEditable = false;&lt;br /&gt;
      spanInput.textContent = characterPseudo;&lt;br /&gt;
      spanInput.setAttribute(&amp;quot;data-name&amp;quot;, characterPseudo);&lt;br /&gt;
&lt;br /&gt;
      updateForm(&lt;br /&gt;
        characterDataObject,&lt;br /&gt;
        characters.characterCreation,&lt;br /&gt;
        characters,&lt;br /&gt;
        selectedCharacter,&lt;br /&gt;
        battle&lt;br /&gt;
      );&lt;br /&gt;
      saveCharacter(&lt;br /&gt;
        characters.savedCharacters,&lt;br /&gt;
        characters.characterCreation,&lt;br /&gt;
        battle,&lt;br /&gt;
        true&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handleMaxLength(event) {&lt;br /&gt;
      if (spanInput.textContent.length &amp;gt; maxPseudoLength) {&lt;br /&gt;
        spanInput.textContent = spanInput.textContent.slice(0, maxPseudoLength);&lt;br /&gt;
        range.setStart(spanInput.childNodes[0], maxPseudoLength);&lt;br /&gt;
        selection.removeAllRanges();&lt;br /&gt;
        selection.addRange(range);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handleBlur() {&lt;br /&gt;
      spanInput.removeEventListener(&amp;quot;blur&amp;quot;, handleBlur);&lt;br /&gt;
      spanInput.removeEventListener(&amp;quot;input&amp;quot;, handleMaxLength);&lt;br /&gt;
      pseudoValidation();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handleKeyDown(event) {&lt;br /&gt;
      if (event.key === &amp;quot;Enter&amp;quot;) {&lt;br /&gt;
        event.preventDefault();&lt;br /&gt;
&lt;br /&gt;
        spanInput.removeEventListener(&amp;quot;keydown&amp;quot;, handleKeyDown);&lt;br /&gt;
        spanInput.removeEventListener(&amp;quot;blur&amp;quot;, handleBlur);&lt;br /&gt;
        spanInput.removeEventListener(&amp;quot;input&amp;quot;, handleMaxLength);&lt;br /&gt;
&lt;br /&gt;
        pseudoValidation();&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    spanInput.addEventListener(&amp;quot;input&amp;quot;, handleMaxLength);&lt;br /&gt;
    spanInput.addEventListener(&amp;quot;keydown&amp;quot;, handleKeyDown);&lt;br /&gt;
    spanInput.addEventListener(&amp;quot;blur&amp;quot;, handleBlur);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  hideElement(characters.characterCreation);&lt;br /&gt;
  var [selectedCharacter, spanInput] = handleNewCharacter(&lt;br /&gt;
    characters,&lt;br /&gt;
    characterTemplate,&lt;br /&gt;
    charactersContainer,&lt;br /&gt;
    battle&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  editAndSetCharacterPseudoInput(selectedCharacter, spanInput);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleFocus() {&lt;br /&gt;
  var tooltipLinks = document.querySelectorAll(&amp;quot;div.tooltip a&amp;quot;);&lt;br /&gt;
  tooltipLinks.forEach(function (link) {&lt;br /&gt;
    link.setAttribute(&amp;quot;tabindex&amp;quot;, -1);&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function resetBonusVariation(bonusVariation) {&lt;br /&gt;
  function resetInput(input) {&lt;br /&gt;
    input.removeAttribute(&amp;quot;min&amp;quot;);&lt;br /&gt;
    input.removeAttribute(&amp;quot;max&amp;quot;);&lt;br /&gt;
    input.defaultValue = 0;&lt;br /&gt;
    input.value = input.defaultValue;&lt;br /&gt;
  }&lt;br /&gt;
  var { minValue, maxValue, checkbox, container, disabledText, selectedText } =&lt;br /&gt;
    bonusVariation;&lt;br /&gt;
&lt;br /&gt;
  resetInput(minValue);&lt;br /&gt;
  resetInput(maxValue);&lt;br /&gt;
  showElement(disabledText);&lt;br /&gt;
  hideElement(selectedText);&lt;br /&gt;
  hideElement(container);&lt;br /&gt;
  checkbox.checked = false;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleBonusVariationUpdate(&lt;br /&gt;
  characterCreation,&lt;br /&gt;
  bonusVariation,&lt;br /&gt;
  resetSkill&lt;br /&gt;
) {&lt;br /&gt;
  var selectedBonus = characterCreation.bonusVariation.value;&lt;br /&gt;
  var displayName = characterCreation.bonusVariationName.value;&lt;br /&gt;
&lt;br /&gt;
  if (&lt;br /&gt;
    resetSkill &amp;amp;&amp;amp;&lt;br /&gt;
    (selectedBonus.startsWith(&amp;quot;attackSkill&amp;quot;) ||&lt;br /&gt;
      selectedBonus.startsWith(&amp;quot;horseSkill&amp;quot;) ||&lt;br /&gt;
      selectedBonus.startsWith(&amp;quot;skillBonus&amp;quot;))&lt;br /&gt;
  ) {&lt;br /&gt;
    resetBonusVariation(bonusVariation);&lt;br /&gt;
    return;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (&lt;br /&gt;
    characterCreation.hasOwnProperty(selectedBonus) &amp;amp;&amp;amp;&lt;br /&gt;
    selectedBonus != 0 &amp;amp;&amp;amp;&lt;br /&gt;
    displayName != 0&lt;br /&gt;
  ) {&lt;br /&gt;
    handleBonusVariation(&lt;br /&gt;
      characterCreation[selectedBonus],&lt;br /&gt;
      bonusVariation,&lt;br /&gt;
      displayName&lt;br /&gt;
    );&lt;br /&gt;
  } else {&lt;br /&gt;
    resetBonusVariation(bonusVariation);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getTargetContent(targetParent, targetName, isSkill) {&lt;br /&gt;
  var targetContent = &amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  if (targetParent.children.length &amp;lt;= 1) {&lt;br /&gt;
    targetContent = targetParent.textContent;&lt;br /&gt;
  } else if (targetName === &amp;quot;weaponUpgrade&amp;quot;) {&lt;br /&gt;
    targetContent = targetParent.children[1].textContent;&lt;br /&gt;
  } else if (targetName === &amp;quot;level&amp;quot;) {&lt;br /&gt;
    targetContent = targetParent.textContent.replace(&amp;quot;Lv&amp;quot;, &amp;quot;&amp;quot;).trim();&lt;br /&gt;
  } else if (isSkill) {&lt;br /&gt;
    var container = targetParent.children[1];&lt;br /&gt;
&lt;br /&gt;
    for (var index = 0; index &amp;lt; container.children.length; index++) {&lt;br /&gt;
      var element = container.children[index];&lt;br /&gt;
&lt;br /&gt;
      if (element.checkVisibility()) {&lt;br /&gt;
        targetContent += element.textContent;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    for (var index = 1; index &amp;lt; targetParent.children.length; index++) {&lt;br /&gt;
      var element = targetParent.children[index];&lt;br /&gt;
&lt;br /&gt;
      if (element.checkVisibility()) {&lt;br /&gt;
        targetContent += element.textContent;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return targetContent.trim();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleBonusVariation(target, bonusVariation, displayName) {&lt;br /&gt;
  var {&lt;br /&gt;
    minValue,&lt;br /&gt;
    maxValue,&lt;br /&gt;
    checkbox,&lt;br /&gt;
    container,&lt;br /&gt;
    disabledText,&lt;br /&gt;
    selectedText,&lt;br /&gt;
    displaySpan,&lt;br /&gt;
  } = bonusVariation;&lt;br /&gt;
&lt;br /&gt;
  var {&lt;br /&gt;
    min: targetMin,&lt;br /&gt;
    max: targetMax,&lt;br /&gt;
    name: targetName,&lt;br /&gt;
    value: targetValue,&lt;br /&gt;
    parentElement: targetParent,&lt;br /&gt;
    tagName,&lt;br /&gt;
  } = target;&lt;br /&gt;
&lt;br /&gt;
  targetMin = Number(targetMin);&lt;br /&gt;
  targetMax = Number(targetMax);&lt;br /&gt;
  targetValue = Number(targetValue);&lt;br /&gt;
&lt;br /&gt;
  var isSkill = tagName === &amp;quot;SELECT&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  if (isSkill) {&lt;br /&gt;
    var options = target.options;&lt;br /&gt;
&lt;br /&gt;
    targetMin = options[0].value;&lt;br /&gt;
    targetMax = options[options.length - 1].value;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  minValue.min = targetMin;&lt;br /&gt;
  minValue.max = targetMax;&lt;br /&gt;
  minValue.defaultValue = targetMin;&lt;br /&gt;
&lt;br /&gt;
  maxValue.min = targetMin;&lt;br /&gt;
  maxValue.max = targetMax;&lt;br /&gt;
  maxValue.defaultValue = targetMin;&lt;br /&gt;
&lt;br /&gt;
  hideElement(disabledText);&lt;br /&gt;
  showElement(selectedText);&lt;br /&gt;
&lt;br /&gt;
  if (displayName) {&lt;br /&gt;
    minValue.value = Math.min(Math.max(minValue.value, targetMin), targetMax);&lt;br /&gt;
    maxValue.value = Math.max(Math.min(maxValue.value, targetMax), targetMin);&lt;br /&gt;
&lt;br /&gt;
    displaySpan.textContent = displayName;&lt;br /&gt;
  } else {&lt;br /&gt;
    var { input, inputName, tabButton } = bonusVariation;&lt;br /&gt;
    var targetContent = getTargetContent(targetParent, targetName, isSkill);&lt;br /&gt;
&lt;br /&gt;
    input.value = targetName;&lt;br /&gt;
    inputName.value = targetContent;&lt;br /&gt;
    displaySpan.textContent = targetContent;&lt;br /&gt;
&lt;br /&gt;
    minValue.value = Math.max(targetValue - 10, targetMin);&lt;br /&gt;
    maxValue.value = Math.min(targetValue + 10, targetMax);&lt;br /&gt;
&lt;br /&gt;
    showElement(container);&lt;br /&gt;
    checkbox.checked = true;&lt;br /&gt;
&lt;br /&gt;
    tabButton.click();&lt;br /&gt;
    tabButton.scrollIntoView(true);&lt;br /&gt;
&lt;br /&gt;
    input.dispatchEvent(newChangeEvent());&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function characterManagement(characters, battle) {&lt;br /&gt;
  var {&lt;br /&gt;
    newCharacterTemplate: characterTemplate,&lt;br /&gt;
    charactersContainer,&lt;br /&gt;
    addNewCharacterButton,&lt;br /&gt;
    saveButton,&lt;br /&gt;
    characterCreation,&lt;br /&gt;
    bonusVariation,&lt;br /&gt;
  } = characters;&lt;br /&gt;
&lt;br /&gt;
  Object.keys(characters.savedCharacters).forEach(function (pseudo) {&lt;br /&gt;
    handleNewCharacter(&lt;br /&gt;
      characters,&lt;br /&gt;
      characterTemplate,&lt;br /&gt;
      charactersContainer,&lt;br /&gt;
      battle,&lt;br /&gt;
      pseudo&lt;br /&gt;
    );&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  addNewCharacterButton.addEventListener(&amp;quot;click&amp;quot;, function (event) {&lt;br /&gt;
    if (!characters.unsavedChanges) {&lt;br /&gt;
      addNewCharacter(&lt;br /&gt;
        characters,&lt;br /&gt;
        characterTemplate,&lt;br /&gt;
        charactersContainer,&lt;br /&gt;
        battle&lt;br /&gt;
      );&lt;br /&gt;
    } else {&lt;br /&gt;
      var result = confirm(&lt;br /&gt;
        &amp;quot;Voulez-vous continuer ? Les dernières modifications ne seront pas sauvegardées.&amp;quot;&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      if (result) {&lt;br /&gt;
        addNewCharacter(&lt;br /&gt;
          characters,&lt;br /&gt;
          characterTemplate,&lt;br /&gt;
          charactersContainer,&lt;br /&gt;
          battle&lt;br /&gt;
        );&lt;br /&gt;
        saveButtonGreen(saveButton);&lt;br /&gt;
        characters.unsavedChanges = false;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  handleUploadCharacter(&lt;br /&gt;
    characters,&lt;br /&gt;
    characterTemplate,&lt;br /&gt;
    charactersContainer,&lt;br /&gt;
    battle&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  function handleLongPress(target) {&lt;br /&gt;
    if (target.tagName !== &amp;quot;INPUT&amp;quot; &amp;amp;&amp;amp; target.tagName !== &amp;quot;SELECT&amp;quot;) {&lt;br /&gt;
      target = target.querySelector(&amp;quot;input&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      !target ||&lt;br /&gt;
      (target.type !== &amp;quot;number&amp;quot; &amp;amp;&amp;amp;&lt;br /&gt;
        !target.classList.contains(&amp;quot;skill-select&amp;quot;) &amp;amp;&amp;amp;&lt;br /&gt;
        target.name !== &amp;quot;weaponUpgrade&amp;quot;) ||&lt;br /&gt;
      target.classList.contains(&amp;quot;disabled-variation&amp;quot;)&lt;br /&gt;
    ) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    handleBonusVariation(target, bonusVariation, null);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;click&amp;quot;, function (event) {&lt;br /&gt;
    if (event.shiftKey || event.ctrlKey) {&lt;br /&gt;
      handleLongPress(event.target);&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  var longPressTimer;&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;touchstart&amp;quot;, function (event) {&lt;br /&gt;
    longPressTimer = setTimeout(function () {&lt;br /&gt;
      handleLongPress(event.target);&lt;br /&gt;
    }, 800);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;touchend&amp;quot;, function () {&lt;br /&gt;
    clearTimeout(longPressTimer);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;touchmove&amp;quot;, function () {&lt;br /&gt;
    clearTimeout(longPressTimer);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  filterForm(characters, battle);&lt;br /&gt;
  characterCreationListener(characters, battle);&lt;br /&gt;
  handleFocus();&lt;br /&gt;
&lt;br /&gt;
  window.addEventListener(&amp;quot;beforeunload&amp;quot;, function (event) {&lt;br /&gt;
    if (characters.unsavedChanges) {&lt;br /&gt;
      event.preventDefault();&lt;br /&gt;
      return &amp;quot;&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addMonsterElement(characters, battle, monsterVnum, iframeInfo) {&lt;br /&gt;
  var { monsterTemplate, monstersContainer } = characters;&lt;br /&gt;
  var monsterElement = monsterTemplate.cloneNode(true);&lt;br /&gt;
  var spanInput = monsterElement.querySelector(&amp;quot;span.input&amp;quot;);&lt;br /&gt;
  var deleteSvg = monsterElement.querySelector(&amp;quot;svg&amp;quot;);&lt;br /&gt;
  var monsterName = getMonsterName(monsterVnum);&lt;br /&gt;
  var link = createWikiLink(monsterName);&lt;br /&gt;
&lt;br /&gt;
  monsterElement.setAttribute(&amp;quot;tabindex&amp;quot;, &amp;quot;0&amp;quot;);&lt;br /&gt;
  spanInput.appendChild(link);&lt;br /&gt;
  monstersContainer.appendChild(monsterElement);&lt;br /&gt;
  characters.monsterElements[monsterVnum] = monsterElement;&lt;br /&gt;
&lt;br /&gt;
  deleteSvg.addEventListener(&amp;quot;click&amp;quot;, function () {&lt;br /&gt;
    var monster = characters.savedMonsters[monsterVnum];&lt;br /&gt;
    iframeInfo[monster.category].shouldBeUpdated = true;&lt;br /&gt;
&lt;br /&gt;
    deleteMonster(characters, battle, monsterVnum);&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addNewMonster(&lt;br /&gt;
  characters,&lt;br /&gt;
  battle,&lt;br /&gt;
  monsterVnum,&lt;br /&gt;
  monsterImage,&lt;br /&gt;
  iframeInfo,&lt;br /&gt;
  category&lt;br /&gt;
) {&lt;br /&gt;
  if (isValueInArray(monsterVnum, Object.keys(characters.savedMonsters)))&lt;br /&gt;
    return;&lt;br /&gt;
&lt;br /&gt;
  var newMonster = {&lt;br /&gt;
    image: monsterImage,&lt;br /&gt;
    category: category,&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  characters.savedMonsters[monsterVnum] = newMonster;&lt;br /&gt;
&lt;br /&gt;
  addMonsterElement(characters, battle, monsterVnum, iframeInfo);&lt;br /&gt;
  updateSavedMonsters(characters.savedMonsters);&lt;br /&gt;
  addBattleChoice(battle.battleChoice, monsterVnum, newMonster, true);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addButtonsToCards(characters, iframeDoc, iframeInfo, category) {&lt;br /&gt;
  var buttonTemplates = characters.monsterButtonTemplates.children[0];&lt;br /&gt;
  var cardToEdit = iframeDoc.getElementById(&amp;quot;cards-container&amp;quot;).children;&lt;br /&gt;
  var { nameToVnum } = iframeInfo;&lt;br /&gt;
  var vnumToButtons = iframeInfo[category].vnumToButtons;&lt;br /&gt;
&lt;br /&gt;
  for (var cardIndex = 0; cardIndex &amp;lt; cardToEdit.length; cardIndex++) {&lt;br /&gt;
    var card = cardToEdit[cardIndex];&lt;br /&gt;
    var cardName = card.querySelector(&amp;quot;[data-name]&amp;quot;).firstChild.title;&lt;br /&gt;
    var buttonTemplatesClone = buttonTemplates.cloneNode(true);&lt;br /&gt;
&lt;br /&gt;
    cardName = cardName.replace(/\s/g, &amp;quot; &amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (!nameToVnum.hasOwnProperty(cardName)) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var monsterVnum = nameToVnum[cardName];&lt;br /&gt;
&lt;br /&gt;
    buttonTemplatesClone.dataset.monsterId = monsterVnum;&lt;br /&gt;
    card.lastElementChild.appendChild(buttonTemplatesClone);&lt;br /&gt;
    vnumToButtons[monsterVnum] = buttonTemplatesClone.children;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateiFrameButtons(characters, iframeInfo, category) {&lt;br /&gt;
  var addedMonsters = Object.keys(characters.savedMonsters);&lt;br /&gt;
  var { currentiFrameIsMonster } = iframeInfo;&lt;br /&gt;
  var vnumToButtons = iframeInfo[category].vnumToButtons;&lt;br /&gt;
  var isPolymorphModal = category === &amp;quot;monster&amp;quot; &amp;amp;&amp;amp; !currentiFrameIsMonster;&lt;br /&gt;
&lt;br /&gt;
  for (var monsterVnum in vnumToButtons) {&lt;br /&gt;
    var [addButton, deleteButton, selectButton] = vnumToButtons[monsterVnum];&lt;br /&gt;
&lt;br /&gt;
    if (isPolymorphModal) {&lt;br /&gt;
      hideElement(addButton);&lt;br /&gt;
      hideElement(deleteButton);&lt;br /&gt;
      showElement(selectButton);&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isValueInArray(monsterVnum, addedMonsters)) {&lt;br /&gt;
      hideElement(addButton);&lt;br /&gt;
      showElement(deleteButton);&lt;br /&gt;
      hideElement(selectButton);&lt;br /&gt;
    } else {&lt;br /&gt;
      showElement(addButton);&lt;br /&gt;
      hideElement(deleteButton);&lt;br /&gt;
      hideElement(selectButton);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  iframeInfo.lastiFrameIsMonster = currentiFrameIsMonster;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getMonsterImage(buttonsContainer) {&lt;br /&gt;
  var elder = buttonsContainer.parentElement.firstElementChild;&lt;br /&gt;
  var image = elder.querySelector(&amp;quot;img&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (image) {&lt;br /&gt;
    return image.getAttribute(&amp;quot;src&amp;quot;) || &amp;quot;&amp;quot;;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return &amp;quot;&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleiFrame(iframeInfo, category) {&lt;br /&gt;
  var { characters, battle } = iframeInfo;&lt;br /&gt;
  var iframeInfoCategory = iframeInfo[category];&lt;br /&gt;
  var { iframe, pageName, vnumToButtons } = iframeInfoCategory;&lt;br /&gt;
  var loadingAnimation = iframeInfoCategory.iframe.previousElementSibling;&lt;br /&gt;
&lt;br /&gt;
  iframe.src = mw.util.getUrl(pageName);&lt;br /&gt;
&lt;br /&gt;
  iframe.addEventListener(&amp;quot;load&amp;quot;, function () {&lt;br /&gt;
    var iframeDoc = this.contentDocument || this.contentWindow.document;&lt;br /&gt;
    var iframeBody = iframeDoc.body;&lt;br /&gt;
    var content = iframeDoc.getElementById(&amp;quot;show-after-loading&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    iframeBody.firstElementChild.replaceWith(content);&lt;br /&gt;
&lt;br /&gt;
    iframeBody.style.background = &amp;quot;transparent&amp;quot;;&lt;br /&gt;
    iframeBody.style.paddingRight = &amp;quot;10px&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    addButtonsToCards(characters, iframeDoc, iframeInfo, category);&lt;br /&gt;
    updateiFrameButtons(characters, iframeInfo, category);&lt;br /&gt;
&lt;br /&gt;
    iframeInfoCategory.loadIsFinished = true;&lt;br /&gt;
&lt;br /&gt;
    hideElement(loadingAnimation);&lt;br /&gt;
    showElement(iframe);&lt;br /&gt;
&lt;br /&gt;
    iframeDoc.addEventListener(&amp;quot;click&amp;quot;, handleButtonClick);&lt;br /&gt;
&lt;br /&gt;
    function handleButtonClick(event) {&lt;br /&gt;
      var target = event.target;&lt;br /&gt;
      var link = target.closest(&amp;quot;a&amp;quot;);&lt;br /&gt;
      var buttonsContainer = target.closest(&amp;quot;.handle-monster&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
      if (link) {&lt;br /&gt;
        event.preventDefault();&lt;br /&gt;
        window.open(link.href, &amp;quot;_blank&amp;quot;);&lt;br /&gt;
      } else if (buttonsContainer) {&lt;br /&gt;
        var { monsterId: monsterVnum } = buttonsContainer.dataset;&lt;br /&gt;
&lt;br /&gt;
        // polymorph iframe&lt;br /&gt;
        if (category === &amp;quot;monster&amp;quot; &amp;amp;&amp;amp; !iframeInfo.currentiFrameIsMonster) {&lt;br /&gt;
          var monsterImage = getMonsterImage(buttonsContainer);&lt;br /&gt;
          changePolymorphValues(&lt;br /&gt;
            characters.characterCreation,&lt;br /&gt;
            monsterVnum,&lt;br /&gt;
            monsterImage&lt;br /&gt;
          );&lt;br /&gt;
          handlePolymorphDisplay(&lt;br /&gt;
            characters.polymorphDisplay,&lt;br /&gt;
            monsterVnum,&lt;br /&gt;
            monsterImage&lt;br /&gt;
          );&lt;br /&gt;
          iframe.dispatchEvent(newChangeEvent());&lt;br /&gt;
        } else {&lt;br /&gt;
          var addedMonsters = Object.keys(characters.savedMonsters);&lt;br /&gt;
          var [addButton, deleteButton] = vnumToButtons[monsterVnum];&lt;br /&gt;
&lt;br /&gt;
          if (isValueInArray(monsterVnum, addedMonsters)) {&lt;br /&gt;
            deleteMonster(characters, battle, monsterVnum);&lt;br /&gt;
            showElement(addButton);&lt;br /&gt;
            hideElement(deleteButton);&lt;br /&gt;
          } else {&lt;br /&gt;
            var monsterImage = getMonsterImage(buttonsContainer);&lt;br /&gt;
            addNewMonster(&lt;br /&gt;
              characters,&lt;br /&gt;
              battle,&lt;br /&gt;
              monsterVnum,&lt;br /&gt;
              monsterImage,&lt;br /&gt;
              iframeInfo,&lt;br /&gt;
              category&lt;br /&gt;
            );&lt;br /&gt;
            hideElement(addButton);&lt;br /&gt;
            showElement(deleteButton);&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getNameToVnumMapping() {&lt;br /&gt;
  var nameToVnum = {};&lt;br /&gt;
&lt;br /&gt;
  for (var monsterVnum in monsterData) {&lt;br /&gt;
    nameToVnum[monsterData[monsterVnum][monsterData[monsterVnum].length - 1]] =&lt;br /&gt;
      monsterVnum;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return nameToVnum;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function monsterManagement(characters, battle) {&lt;br /&gt;
  var { monsteriFrame, stoneiFrame } = characters;&lt;br /&gt;
  var monsterVnums = Object.keys(monsterData);&lt;br /&gt;
&lt;br /&gt;
  var iframeInfo = {&lt;br /&gt;
    lastiFrameIsMonster: false,&lt;br /&gt;
    currentiFrameIsMonster: false,&lt;br /&gt;
    characters: characters,&lt;br /&gt;
    battle: battle,&lt;br /&gt;
    nameToVnum: getNameToVnumMapping(),&lt;br /&gt;
    monster: {&lt;br /&gt;
      isLoaded: false,&lt;br /&gt;
      loadIsFinished: false,&lt;br /&gt;
      shouldBeUpdated: false,&lt;br /&gt;
      vnumToButtons: {},&lt;br /&gt;
      pageName: &amp;quot;Monstres&amp;quot;,&lt;br /&gt;
      iframe: monsteriFrame,&lt;br /&gt;
    },&lt;br /&gt;
    stone: {&lt;br /&gt;
      isLoaded: false,&lt;br /&gt;
      loadIsFinished: false,&lt;br /&gt;
      shouldBeUpdated: false,&lt;br /&gt;
      vnumToButtons: {},&lt;br /&gt;
      pageName: &amp;quot;Pierres Metin&amp;quot;,&lt;br /&gt;
      iframe: stoneiFrame,&lt;br /&gt;
    },&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  document.addEventListener(&amp;quot;modalOpen&amp;quot;, function (event) {&lt;br /&gt;
    var modalName = event.detail.name;&lt;br /&gt;
&lt;br /&gt;
    if (modalName === &amp;quot;monster&amp;quot; || modalName === &amp;quot;stone&amp;quot;) {&lt;br /&gt;
      handleModal(event.target, modalName);&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  function handleModal(target, modalName) {&lt;br /&gt;
    var iframeInfoCategory = iframeInfo[modalName];&lt;br /&gt;
&lt;br /&gt;
    if (modalName === &amp;quot;monster&amp;quot;) {&lt;br /&gt;
      var isMonsteriFrame = target.id === &amp;quot;add-new-monster&amp;quot;;&lt;br /&gt;
      iframeInfo.currentiFrameIsMonster = isMonsteriFrame;&lt;br /&gt;
&lt;br /&gt;
      if (&lt;br /&gt;
        iframeInfoCategory.loadIsFinished &amp;amp;&amp;amp;&lt;br /&gt;
        ((isMonsteriFrame &amp;amp;&amp;amp; !iframeInfo.lastiFrameIsMonster) ||&lt;br /&gt;
          (!isMonsteriFrame &amp;amp;&amp;amp; iframeInfo.lastiFrameIsMonster))&lt;br /&gt;
      ) {&lt;br /&gt;
        iframeInfoCategory.shouldBeUpdated = true;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!iframeInfoCategory.isLoaded) {&lt;br /&gt;
      handleiFrame(iframeInfo, modalName);&lt;br /&gt;
      iframeInfoCategory.isLoaded = true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      iframeInfoCategory.loadIsFinished &amp;amp;&amp;amp;&lt;br /&gt;
      iframeInfoCategory.shouldBeUpdated&lt;br /&gt;
    ) {&lt;br /&gt;
      updateiFrameButtons(characters, iframeInfo, modalName);&lt;br /&gt;
      iframeInfoCategory.shouldBeUpdated = false;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  Object.keys(characters.savedMonsters)&lt;br /&gt;
    .slice()&lt;br /&gt;
    .forEach(function (monsterVnum) {&lt;br /&gt;
      if (isValueInArray(monsterVnum, monsterVnums)) {&lt;br /&gt;
        addMonsterElement(characters, battle, monsterVnum, iframeInfo);&lt;br /&gt;
      } else {&lt;br /&gt;
        deleteMonster(characters, battle, monsterVnum);&lt;br /&gt;
      }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function hideAttackType(container, input, attackType) {&lt;br /&gt;
  hideElement(container);&lt;br /&gt;
&lt;br /&gt;
  if (input.checked) {&lt;br /&gt;
    var defaultInput = attackType.defaultInput;&lt;br /&gt;
&lt;br /&gt;
    input.checked = false;&lt;br /&gt;
    defaultInput.checked = true;&lt;br /&gt;
    defaultInput.dispatchEvent(newChangeEvent());&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterAttackTypeSelectionCharacter(attacker, attackType) {&lt;br /&gt;
  var attackerClass = attacker.class;&lt;br /&gt;
  var attackerIsNotPolymorph = !isPolymorph(attacker);&lt;br /&gt;
  var { elements: attackTypeElements } = attackType;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; attackTypeElements.length; index++) {&lt;br /&gt;
    var { container, input, inputClass, inputValue } =&lt;br /&gt;
      attackTypeElements[index];&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      attackerIsNotPolymorph &amp;amp;&amp;amp;&lt;br /&gt;
      attacker[inputValue] &amp;amp;&amp;amp;&lt;br /&gt;
      (attackerClass === inputClass ||&lt;br /&gt;
        (inputValue.startsWith(&amp;quot;horseSkill&amp;quot;) &amp;amp;&amp;amp;&lt;br /&gt;
          isRiding(attacker) &amp;amp;&amp;amp;&lt;br /&gt;
          (!inputClass || isValueInArray(attackerClass, inputClass))))&lt;br /&gt;
    ) {&lt;br /&gt;
      showElement(container);&lt;br /&gt;
    } else {&lt;br /&gt;
      hideAttackType(container, input, attackType);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterAttackTypeSelectionMonster(attackType) {&lt;br /&gt;
  var attackTypeElements = attackType.elements;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; attackTypeElements.length; index++) {&lt;br /&gt;
    var { container, input } = attackTypeElements[index];&lt;br /&gt;
    hideAttackType(container, input, attackType);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function removeBattleElement(battleChoice, nameOrVnum, category, type) {&lt;br /&gt;
  var elements = battleChoice[category][type].elements;&lt;br /&gt;
&lt;br /&gt;
  if (elements.hasOwnProperty(nameOrVnum)) {&lt;br /&gt;
    elements[nameOrVnum].container.remove();&lt;br /&gt;
    delete elements[nameOrVnum];&lt;br /&gt;
    battleChoice[category][type].count--;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function removeBattleChoice(battleChoice, nameOrVnum, type) {&lt;br /&gt;
  battleChoice.categories.forEach(function (category) {&lt;br /&gt;
    if (category === &amp;quot;attacker&amp;quot; &amp;amp;&amp;amp; type === &amp;quot;stone&amp;quot;) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
    var selected = battleChoice[category].selected;&lt;br /&gt;
&lt;br /&gt;
    if (selected) {&lt;br /&gt;
      var { type: selectedType, nameOrVnum: selectedNameOrVnum } =&lt;br /&gt;
        parseTypeAndName(selected);&lt;br /&gt;
&lt;br /&gt;
      if (nameOrVnum === selectedNameOrVnum &amp;amp;&amp;amp; type === selectedType) {&lt;br /&gt;
        resetBattleChoiceButton(battleChoice, category);&lt;br /&gt;
        battleChoice[category].selected = null;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    removeBattleElement(battleChoice, nameOrVnum, category, type);&lt;br /&gt;
    updateBattleChoiceText(battleChoice, category, type);&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addBattleElement(&lt;br /&gt;
  battleChoice,&lt;br /&gt;
  pseudoOrVnum,&lt;br /&gt;
  characterOrMonster,&lt;br /&gt;
  category,&lt;br /&gt;
  isMonster&lt;br /&gt;
) {&lt;br /&gt;
  var { template, raceToImage } = battleChoice;&lt;br /&gt;
  var battleChoiceCategory = battleChoice[category];&lt;br /&gt;
  var templateClone = template.cloneNode(true);&lt;br /&gt;
  var label = templateClone.firstElementChild;&lt;br /&gt;
  var [input, image, span] = label.children;&lt;br /&gt;
  var imageSrc;&lt;br /&gt;
  var name;&lt;br /&gt;
  var type;&lt;br /&gt;
&lt;br /&gt;
  if (isMonster) {&lt;br /&gt;
    type = characterOrMonster.category;&lt;br /&gt;
&lt;br /&gt;
    if (type === &amp;quot;stone&amp;quot; &amp;amp;&amp;amp; category === &amp;quot;attacker&amp;quot;) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
    imageSrc = characterOrMonster.image;&lt;br /&gt;
    name = getMonsterName(pseudoOrVnum);&lt;br /&gt;
  } else {&lt;br /&gt;
    type = &amp;quot;character&amp;quot;;&lt;br /&gt;
    imageSrc = raceToImage[characterOrMonster.race];&lt;br /&gt;
    name = pseudoOrVnum;&lt;br /&gt;
    label.classList.add(&amp;quot;notranslate&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var value = type + &amp;quot;-&amp;quot; + pseudoOrVnum;&lt;br /&gt;
  var id = category + &amp;quot;-&amp;quot; + value;&lt;br /&gt;
  var currentBattleChoice = battleChoiceCategory[type];&lt;br /&gt;
&lt;br /&gt;
  label.setAttribute(&amp;quot;for&amp;quot;, id);&lt;br /&gt;
  input.value = value;&lt;br /&gt;
  input.id = id;&lt;br /&gt;
  input.name = category;&lt;br /&gt;
  span.textContent = name;&lt;br /&gt;
&lt;br /&gt;
  handleImageFromWiki(image, imageSrc);&lt;br /&gt;
&lt;br /&gt;
  currentBattleChoice.container.appendChild(templateClone);&lt;br /&gt;
  currentBattleChoice.count++;&lt;br /&gt;
  currentBattleChoice.elements[pseudoOrVnum] = {&lt;br /&gt;
    container: templateClone,&lt;br /&gt;
    image: image,&lt;br /&gt;
    name: name,&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  updateBattleChoiceText(battleChoice, category, type);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addBattleChoice(&lt;br /&gt;
  battleChoice,&lt;br /&gt;
  pseudoOrVnum,&lt;br /&gt;
  characterOrMonster,&lt;br /&gt;
  isMonster = false&lt;br /&gt;
) {&lt;br /&gt;
  addBattleElement(&lt;br /&gt;
    battleChoice,&lt;br /&gt;
    pseudoOrVnum,&lt;br /&gt;
    characterOrMonster,&lt;br /&gt;
    &amp;quot;attacker&amp;quot;,&lt;br /&gt;
    isMonster&lt;br /&gt;
  );&lt;br /&gt;
  addBattleElement(&lt;br /&gt;
    battleChoice,&lt;br /&gt;
    pseudoOrVnum,&lt;br /&gt;
    characterOrMonster,&lt;br /&gt;
    &amp;quot;victim&amp;quot;,&lt;br /&gt;
    isMonster&lt;br /&gt;
  );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateBattleChoiceImage(battleChoice, characterName, newRace) {&lt;br /&gt;
  var imageSrc = battleChoice.raceToImage[newRace];&lt;br /&gt;
&lt;br /&gt;
  battleChoice.categories.forEach(function (category) {&lt;br /&gt;
    handleImageFromWiki(&lt;br /&gt;
      battleChoice[category].character.elements[characterName].image,&lt;br /&gt;
      imageSrc&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    var selected = battleChoice[category].selected;&lt;br /&gt;
&lt;br /&gt;
    if (isCharacterSelected(characterName, selected)) {&lt;br /&gt;
      updateBattleChoiceButton(battleChoice, category, selected);&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateBattleChoiceText(battleChoice, category, type) {&lt;br /&gt;
  var { count, container } = battleChoice[category][type];&lt;br /&gt;
  var parentContainer = container.parentElement;&lt;br /&gt;
&lt;br /&gt;
  if (count === 0) {&lt;br /&gt;
    hideElement(parentContainer);&lt;br /&gt;
    showElement(parentContainer.nextElementSibling);&lt;br /&gt;
  } else if (count === 1) {&lt;br /&gt;
    showElement(parentContainer);&lt;br /&gt;
    hideElement(parentContainer.nextElementSibling);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateBattleChoice(characters, battleChoice) {&lt;br /&gt;
  var templateImage = battleChoice.template.querySelector(&amp;quot;img&amp;quot;);&lt;br /&gt;
  var attackerImage = battleChoice.attacker.buttonContent.querySelector(&amp;quot;img&amp;quot;);&lt;br /&gt;
  var victimImage = battleChoice.victim.buttonContent.querySelector(&amp;quot;img&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  resetImageFromWiki(templateImage);&lt;br /&gt;
  resetImageFromWiki(attackerImage);&lt;br /&gt;
  resetImageFromWiki(victimImage);&lt;br /&gt;
&lt;br /&gt;
  for (var [pseudo, character] of Object.entries(characters.savedCharacters)) {&lt;br /&gt;
    addBattleChoice(battleChoice, pseudo, character);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (var [vnum, monster] of Object.entries(characters.savedMonsters)) {&lt;br /&gt;
    addBattleChoice(battleChoice, vnum, monster, true);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateBattleChoiceButton(battleChoice, category, data) {&lt;br /&gt;
  var battleChoiceCategory = battleChoice[category];&lt;br /&gt;
  var { defaultButtonContent, buttonContent } = battleChoiceCategory;&lt;br /&gt;
  var [buttonImage, buttonSpan] = buttonContent.firstElementChild.children;&lt;br /&gt;
  var { type, nameOrVnum } = parseTypeAndName(data);&lt;br /&gt;
  var { name, image } = battleChoiceCategory[type].elements[nameOrVnum];&lt;br /&gt;
&lt;br /&gt;
  hideElement(defaultButtonContent);&lt;br /&gt;
  showElement(buttonContent);&lt;br /&gt;
&lt;br /&gt;
  buttonSpan.textContent = name;&lt;br /&gt;
  buttonImage.src = image.src;&lt;br /&gt;
  battleChoiceCategory.selected = data;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function resetBattleChoiceButton(battleChoice, category) {&lt;br /&gt;
  var { defaultButtonContent, buttonContent } = battleChoice[category];&lt;br /&gt;
&lt;br /&gt;
  showElement(defaultButtonContent);&lt;br /&gt;
  hideElement(buttonContent);&lt;br /&gt;
&lt;br /&gt;
  if (category === &amp;quot;attacker&amp;quot;) {&lt;br /&gt;
    filterAttackTypeSelectionMonster(battleChoice.attackType);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isPC(character) {&lt;br /&gt;
  if (character.race === 0 || character.race === 1) {&lt;br /&gt;
    return false;&lt;br /&gt;
  }&lt;br /&gt;
  return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isBoss(character) {&lt;br /&gt;
  return character.race === 0 &amp;amp;&amp;amp; character.rank &amp;gt;= 5;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isStone(character) {&lt;br /&gt;
  return character.race === 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isMeleeAttacker(monster) {&lt;br /&gt;
  return monster.attack == 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isRangeAttacker(monster) {&lt;br /&gt;
  return monster.attack == 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isMagicAttacker(monster) {&lt;br /&gt;
  return monster.attack == 2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isMagicClass(character) {&lt;br /&gt;
  return character.race === &amp;quot;shaman&amp;quot; || character.class === &amp;quot;black_magic&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isDispell(character, skillId) {&lt;br /&gt;
  return character.class === &amp;quot;weaponary&amp;quot; &amp;amp;&amp;amp; skillId === 6;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isPolymorph(character) {&lt;br /&gt;
  return isChecked(character.isPolymorph);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isRiding(character) {&lt;br /&gt;
  return isChecked(character.isRiding);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isBow(weaponType) {&lt;br /&gt;
  return weaponType === 2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcAttackFactor(attacker, victim) {&lt;br /&gt;
  function calcCoeffK(dex, level) {&lt;br /&gt;
    return Math.min(90, Math.floor((2 * dex + level) / 3));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var K1 = calcCoeffK(attacker.polymorphDex, attacker.level);&lt;br /&gt;
  var K2 = calcCoeffK(victim.polymorphDex, attacker.level);&lt;br /&gt;
&lt;br /&gt;
  var AR = (K1 + 210) / 300;&lt;br /&gt;
  var ER = (((2 * K2 + 5) / (K2 + 95)) * 3) / 10;&lt;br /&gt;
&lt;br /&gt;
  return truncateNumber(AR - ER, 8);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcMainAttackValue(attacker) {&lt;br /&gt;
  var leadership = 0;&lt;br /&gt;
  var weaponGrowth = 0;&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker)) {&lt;br /&gt;
    weaponGrowth = attacker.weapon.growth;&lt;br /&gt;
    leadership = attacker.leadership;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return 2 * (attacker.level + weaponGrowth) + leadership;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcStatAttackValue(character) {&lt;br /&gt;
  switch (character.race) {&lt;br /&gt;
    case &amp;quot;warrior&amp;quot;:&lt;br /&gt;
    case &amp;quot;sura&amp;quot;:&lt;br /&gt;
      return 2 * character.str;&lt;br /&gt;
    case &amp;quot;ninja&amp;quot;:&lt;br /&gt;
      return Math.floor((1 / 4) * (character.str + 7 * character.dex));&lt;br /&gt;
    case &amp;quot;shaman&amp;quot;:&lt;br /&gt;
      return Math.floor((1 / 3) * (5 * character.int + character.dex));&lt;br /&gt;
    case &amp;quot;lycan&amp;quot;:&lt;br /&gt;
      return character.vit + 2 * character.dex;&lt;br /&gt;
    default:&lt;br /&gt;
      return 2 * character.str;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcPvpCriticalAttackRange(minAttackValue, maxAttackValue, growth) {&lt;br /&gt;
  return Array.from(&lt;br /&gt;
    { length: maxAttackValue - minAttackValue + 1 },&lt;br /&gt;
    (_, index) =&amp;gt; (minAttackValue + growth + index) * 2&lt;br /&gt;
  );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcSecondaryAttackValue(attacker, isPlayerVsPlayer) {&lt;br /&gt;
  let attackValueOther = 0;&lt;br /&gt;
&lt;br /&gt;
  let minAttackValue = 0;&lt;br /&gt;
  let maxAttackValue = 0;&lt;br /&gt;
&lt;br /&gt;
  let minAttackValueSlash = 0;&lt;br /&gt;
  let maxAttackValueSlash = 0;&lt;br /&gt;
&lt;br /&gt;
  let type, isSerpent, growth;&lt;br /&gt;
&lt;br /&gt;
  let criticalAttackRange;&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker)) {&lt;br /&gt;
    ({ type, isSerpent, minAttackValue, maxAttackValue, growth } =&lt;br /&gt;
      attacker.weapon);&lt;br /&gt;
&lt;br /&gt;
    if (isSerpent) {&lt;br /&gt;
      minAttackValue = Math.max(0, attacker.minAttackValueRandom - growth);&lt;br /&gt;
      maxAttackValue = Math.max(&lt;br /&gt;
        minAttackValue,&lt;br /&gt;
        attacker.maxAttackValueRandom - growth&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    minAttackValueSlash = Math.min(&lt;br /&gt;
      attacker.minAttackValueSlash,&lt;br /&gt;
      attacker.maxAttackValueSlash&lt;br /&gt;
    );&lt;br /&gt;
    maxAttackValueSlash = Math.max(&lt;br /&gt;
      attacker.minAttackValueSlash,&lt;br /&gt;
      attacker.maxAttackValueSlash&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    attackValueOther += attacker.attackValue;&lt;br /&gt;
&lt;br /&gt;
    if (isBow(type) &amp;amp;&amp;amp; !isPolymorph(attacker)) {&lt;br /&gt;
      attackValueOther += 25;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isPlayerVsPlayer) {&lt;br /&gt;
      criticalAttackRange = calcPvpCriticalAttackRange(&lt;br /&gt;
        minAttackValue,&lt;br /&gt;
        maxAttackValue,&lt;br /&gt;
        growth&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    minAttackValue = attacker.minAttackValue;&lt;br /&gt;
    maxAttackValue = attacker.maxAttackValue;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  minAttackValue += attacker.minAttackValuePolymorph;&lt;br /&gt;
  maxAttackValue += attacker.maxAttackValuePolymorph;&lt;br /&gt;
&lt;br /&gt;
  attackValueOther += attacker.statAttackValue;&lt;br /&gt;
  attackValueOther += attacker.horseAttackValue;&lt;br /&gt;
&lt;br /&gt;
  const weaponInterval = maxAttackValue - minAttackValue + 1;&lt;br /&gt;
  const slashInterval = maxAttackValueSlash - minAttackValueSlash + 1;&lt;br /&gt;
&lt;br /&gt;
  const totalCardinal = weaponInterval * slashInterval * 1_000_000;&lt;br /&gt;
  const minInterval = Math.min(weaponInterval, slashInterval);&lt;br /&gt;
&lt;br /&gt;
  minAttackValue += minAttackValueSlash;&lt;br /&gt;
  maxAttackValue += maxAttackValueSlash;&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    minAttackValue: minAttackValue,&lt;br /&gt;
    maxAttackValue: maxAttackValue,&lt;br /&gt;
    attackValueOther: attackValueOther,&lt;br /&gt;
    totalCardinal: totalCardinal,&lt;br /&gt;
    weights: calcWeights(minAttackValue, maxAttackValue, minInterval),&lt;br /&gt;
    possibleDamageCount: maxAttackValue - minAttackValue + 1,&lt;br /&gt;
    criticalAttackRange: criticalAttackRange,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcMagicAttackValue(attacker, isPlayerVsPlayer) {&lt;br /&gt;
  let minMagicAttackValueSlash = 0;&lt;br /&gt;
  let maxMagicAttackValueSlash = 0;&lt;br /&gt;
&lt;br /&gt;
  let criticalAttackRange;&lt;br /&gt;
&lt;br /&gt;
  let {&lt;br /&gt;
    isSerpent,&lt;br /&gt;
    minMagicAttackValue,&lt;br /&gt;
    maxMagicAttackValue,&lt;br /&gt;
    minAttackValue,&lt;br /&gt;
    maxAttackValue,&lt;br /&gt;
    growth,&lt;br /&gt;
  } = attacker.weapon;&lt;br /&gt;
&lt;br /&gt;
  if (isSerpent) {&lt;br /&gt;
    minMagicAttackValue = Math.max(0, attacker.minMagicAttackValueRandom);&lt;br /&gt;
    maxMagicAttackValue = Math.max(&lt;br /&gt;
      minMagicAttackValue,&lt;br /&gt;
      attacker.maxMagicAttackValueRandom&lt;br /&gt;
    );&lt;br /&gt;
    minAttackValue = Math.max(0, attacker.minAttackValueRandom - growth);&lt;br /&gt;
    maxAttackValue = Math.max(&lt;br /&gt;
      minAttackValue,&lt;br /&gt;
      attacker.maxAttackValueRandom - growth&lt;br /&gt;
    );&lt;br /&gt;
  } else {&lt;br /&gt;
    minMagicAttackValue += growth;&lt;br /&gt;
    maxMagicAttackValue += growth;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (isPlayerVsPlayer) {&lt;br /&gt;
    criticalAttackRange = calcPvpCriticalAttackRange(&lt;br /&gt;
      minAttackValue,&lt;br /&gt;
      maxAttackValue,&lt;br /&gt;
      growth&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  minMagicAttackValueSlash = Math.min(&lt;br /&gt;
    attacker.minMagicAttackValueSlash,&lt;br /&gt;
    attacker.maxMagicAttackValueSlash&lt;br /&gt;
  );&lt;br /&gt;
  maxMagicAttackValueSlash = Math.max(&lt;br /&gt;
    attacker.minMagicAttackValueSlash,&lt;br /&gt;
    attacker.maxMagicAttackValueSlash&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  const weaponInterval = maxMagicAttackValue - minMagicAttackValue + 1;&lt;br /&gt;
  const slashInterval = maxMagicAttackValueSlash - minMagicAttackValueSlash + 1;&lt;br /&gt;
&lt;br /&gt;
  const totalCardinal = weaponInterval * slashInterval * 1_000_000;&lt;br /&gt;
  const minInterval = Math.min(weaponInterval, slashInterval);&lt;br /&gt;
&lt;br /&gt;
  minMagicAttackValue += minMagicAttackValueSlash;&lt;br /&gt;
  maxMagicAttackValue += maxMagicAttackValueSlash;&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    minMagicAttackValue: minMagicAttackValue,&lt;br /&gt;
    maxMagicAttackValue: maxMagicAttackValue,&lt;br /&gt;
    magicAttackValueAugmentation: getMagicAttackValueAugmentation(&lt;br /&gt;
      minMagicAttackValue,&lt;br /&gt;
      maxMagicAttackValue,&lt;br /&gt;
      attacker.magicAttackValue&lt;br /&gt;
    ),&lt;br /&gt;
    totalCardinal: totalCardinal,&lt;br /&gt;
    weights: calcWeights(minMagicAttackValue, maxMagicAttackValue, minInterval),&lt;br /&gt;
    possibleDamageCount: maxMagicAttackValue - minMagicAttackValue + 1,&lt;br /&gt;
    criticalAttackRange: criticalAttackRange,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getPolymorphPower(polymorphPoint, polymorphPowerTable) {&lt;br /&gt;
  return polymorphPowerTable[polymorphPoint];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSkillPower(skillPoint, skillPowerTable) {&lt;br /&gt;
  return skillPowerTable[skillPoint];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getMarriageBonusValue(character, marriageTable, itemName) {&lt;br /&gt;
  let index;&lt;br /&gt;
  const lovePoint = character.lovePoint;&lt;br /&gt;
&lt;br /&gt;
  if (lovePoint &amp;lt; 65) {&lt;br /&gt;
    index = 0;&lt;br /&gt;
  } else if (lovePoint &amp;lt; 80) {&lt;br /&gt;
    index = 1;&lt;br /&gt;
  } else if (lovePoint &amp;lt; 100) {&lt;br /&gt;
    index = 2;&lt;br /&gt;
  } else {&lt;br /&gt;
    index = 3;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return marriageTable[itemName][index];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcDamageWithPrimaryBonuses(damage, bonusValues) {&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.attackValueCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  damage += bonusValues.attackValueMarriage;&lt;br /&gt;
&lt;br /&gt;
  damage = Math.floor(&lt;br /&gt;
    (damage * bonusValues.monsterResistanceMarriageCoeff) / 100&lt;br /&gt;
  );&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.monsterResistanceCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  damage += Math.floor((damage * bonusValues.typeBonusCoeff) / 100);&lt;br /&gt;
  damage +=&lt;br /&gt;
    Math.floor((damage * bonusValues.raceBonusCoeff) / 100) -&lt;br /&gt;
    Math.floor((damage * bonusValues.raceResistanceCoeff) / 100);&lt;br /&gt;
  damage += Math.floor((damage * bonusValues.stoneBonusCoeff) / 100);&lt;br /&gt;
  damage += Math.floor((damage * bonusValues.monsterBonusCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  const elementBonusCoeff = bonusValues.elementBonusCoeff;&lt;br /&gt;
&lt;br /&gt;
  damage +=&lt;br /&gt;
    Math.trunc((damage * elementBonusCoeff[0]) / 10000) +&lt;br /&gt;
    Math.trunc((damage * elementBonusCoeff[1]) / 10000) +&lt;br /&gt;
    Math.trunc((damage * elementBonusCoeff[2]) / 10000) +&lt;br /&gt;
    Math.trunc((damage * elementBonusCoeff[3]) / 10000) +&lt;br /&gt;
    Math.trunc((damage * elementBonusCoeff[4]) / 10000) +&lt;br /&gt;
    Math.trunc((damage * elementBonusCoeff[5]) / 10000);&lt;br /&gt;
&lt;br /&gt;
  damage = Math.floor(damage * bonusValues.damageMultiplier);&lt;br /&gt;
&lt;br /&gt;
  return damage;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcFinalDamage(&lt;br /&gt;
  finalDamage,&lt;br /&gt;
  minPiercingDamage,&lt;br /&gt;
  tempDamage,&lt;br /&gt;
  bonusValues,&lt;br /&gt;
  criticalAttackRange,&lt;br /&gt;
  damageByType&lt;br /&gt;
) {&lt;br /&gt;
  for (let criticalIndex = 0; criticalIndex &amp;lt; 2; criticalIndex++) {&lt;br /&gt;
    if (bonusValues.skipCriticalStep[criticalIndex]) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
    let beforeCriticalDamage = finalDamage;&lt;br /&gt;
    let damageValues = criticalIndex&lt;br /&gt;
      ? criticalAttackRange || [finalDamage]&lt;br /&gt;
      : [0];&lt;br /&gt;
&lt;br /&gt;
    for (let index = 0, len = damageValues.length; index &amp;lt; len; index++) {&lt;br /&gt;
      let afterCriticalDamage = beforeCriticalDamage + damageValues[index];&lt;br /&gt;
&lt;br /&gt;
      for (let piercingIndex = 0; piercingIndex &amp;lt; 2; piercingIndex++) {&lt;br /&gt;
        if (bonusValues.skipPiercingStep[piercingIndex]) {&lt;br /&gt;
          continue;&lt;br /&gt;
        }&lt;br /&gt;
        let damage = afterCriticalDamage;&lt;br /&gt;
&lt;br /&gt;
        if (piercingIndex) {&lt;br /&gt;
          damage += bonusValues.defenseBoost + Math.min(0, minPiercingDamage);&lt;br /&gt;
          damage += Math.floor(&lt;br /&gt;
            (tempDamage * bonusValues.extraPiercingHitCoeff) / 1000&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        damage = Math.floor((damage * bonusValues.averageDamageCoeff) / 100);&lt;br /&gt;
        damage = Math.floor(&lt;br /&gt;
          (damage * bonusValues.averageDamageResistanceCoeff) / 100&lt;br /&gt;
        );&lt;br /&gt;
        damage = Math.floor((damage * bonusValues.skillDamageCoeff) / 100);&lt;br /&gt;
        damage = Math.floor(&lt;br /&gt;
          (damage * bonusValues.skillDamageResistanceCoeff) / 100&lt;br /&gt;
        );&lt;br /&gt;
        damage = Math.floor((damage * bonusValues.rankBonusCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
        if (bonusValues.useDarkProtection) {&lt;br /&gt;
          const { darkProtectionPoint, darkProtectionSp } = bonusValues;&lt;br /&gt;
&lt;br /&gt;
          const damageReduction = Math.floor(damage / 3);&lt;br /&gt;
          const spAbsorption = Math.floor(&lt;br /&gt;
            (damageReduction * darkProtectionPoint) / 100&lt;br /&gt;
          );&lt;br /&gt;
&lt;br /&gt;
          if (spAbsorption &amp;lt;= darkProtectionSp) {&lt;br /&gt;
            damage -= damageReduction;&lt;br /&gt;
          } else {&lt;br /&gt;
            damage -= Math.floor(&lt;br /&gt;
              (darkProtectionSp * 100) / darkProtectionPoint&lt;br /&gt;
            );&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        damage = Math.max(0, damage + bonusValues.defensePercent);&lt;br /&gt;
        damage += Math.min(&lt;br /&gt;
          300,&lt;br /&gt;
          Math.floor((damage * bonusValues.damageBonusCoeff) / 100)&lt;br /&gt;
        );&lt;br /&gt;
        damage = Math.floor((damage * bonusValues.empireMalusCoeff) / 10);&lt;br /&gt;
        damage = Math.floor((damage * bonusValues.sungMaStrBonusCoeff) / 10000);&lt;br /&gt;
        damage -= Math.floor(damage * bonusValues.sungmaStrMalusCoeff);&lt;br /&gt;
&lt;br /&gt;
        damage = Math.floor(&lt;br /&gt;
          (damage * bonusValues.whiteDragonElixirCoeff) / 100&lt;br /&gt;
        );&lt;br /&gt;
        damage = Math.floor(&lt;br /&gt;
          (damage * bonusValues.steelDragonElixirCoeff) / 100&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        damageByType[criticalIndex + 2 * piercingIndex].push(damage);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveFinalDamage(&lt;br /&gt;
  damage,&lt;br /&gt;
  minPiercingDamage,&lt;br /&gt;
  damageWithPrimaryBonuses,&lt;br /&gt;
  bonusValues,&lt;br /&gt;
  criticalAttackRange,&lt;br /&gt;
  damageByType&lt;br /&gt;
) {&lt;br /&gt;
  damage = Math.floor(damage * bonusValues.magicResistanceCoeff);&lt;br /&gt;
  damage = Math.trunc((damage * bonusValues.weaponDefenseCoeff) / 100);&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.tigerStrengthCoeff) / 100);&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.berserkBonusCoeff) / 100);&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.fearBonusCoeff) / 100);&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.blessingBonusCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  calcFinalDamage(&lt;br /&gt;
    damage,&lt;br /&gt;
    minPiercingDamage,&lt;br /&gt;
    damageWithPrimaryBonuses,&lt;br /&gt;
    bonusValues,&lt;br /&gt;
    criticalAttackRange,&lt;br /&gt;
    damageByType&lt;br /&gt;
  );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveFinalSkillDamage(&lt;br /&gt;
  damage,&lt;br /&gt;
  minPiercingDamage,&lt;br /&gt;
  bonusValues,&lt;br /&gt;
  criticalAttackRange,&lt;br /&gt;
  damageByType&lt;br /&gt;
) {&lt;br /&gt;
  damage = Math.floor(damage * bonusValues.magicResistanceCoeff);&lt;br /&gt;
  damage = Math.trunc((damage * bonusValues.weaponDefenseCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  damage -= bonusValues.defense;&lt;br /&gt;
&lt;br /&gt;
  damage = floorMultiplication(damage, bonusValues.skillWardCoeff);&lt;br /&gt;
  damage = floorMultiplication(damage, bonusValues.skillBonusCoeff);&lt;br /&gt;
&lt;br /&gt;
  const tempDamage = Math.floor(&lt;br /&gt;
    (damage * bonusValues.skillBonusByBonusCoeff) / 100&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  damage = Math.floor(&lt;br /&gt;
    (tempDamage * bonusValues.magicAttackValueCoeff) / 100 + 0.5&lt;br /&gt;
  );&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.tigerStrengthCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  calcFinalDamage(&lt;br /&gt;
    damage,&lt;br /&gt;
    minPiercingDamage,&lt;br /&gt;
    tempDamage,&lt;br /&gt;
    bonusValues,&lt;br /&gt;
    criticalAttackRange,&lt;br /&gt;
    damageByType&lt;br /&gt;
  );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function computePolymorphPoint(attacker, victim, polymorphPowerTable) {&lt;br /&gt;
  attacker.polymorphDex = attacker.dex;&lt;br /&gt;
  victim.polymorphDex = victim.dex;&lt;br /&gt;
&lt;br /&gt;
  attacker.minAttackValuePolymorph = 0;&lt;br /&gt;
  attacker.maxAttackValuePolymorph = 0;&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker) &amp;amp;&amp;amp; isPolymorph(attacker)) {&lt;br /&gt;
    var polymorphPowerPct =&lt;br /&gt;
      getPolymorphPower(attacker.polymorphPoint, polymorphPowerTable) / 100;&lt;br /&gt;
    var polymorphMonster = createMonster(attacker.polymorphMonster, null, true);&lt;br /&gt;
&lt;br /&gt;
    var polymorphStr = floorMultiplication(&lt;br /&gt;
      polymorphPowerPct,&lt;br /&gt;
      polymorphMonster.str&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    attacker.polymorphDex += floorMultiplication(&lt;br /&gt;
      polymorphPowerPct,&lt;br /&gt;
      polymorphMonster.dex&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    attacker.minAttackValuePolymorph = floorMultiplication(&lt;br /&gt;
      polymorphPowerPct,&lt;br /&gt;
      polymorphMonster.minAttackValue&lt;br /&gt;
    );&lt;br /&gt;
    attacker.maxAttackValuePolymorph = floorMultiplication(&lt;br /&gt;
      polymorphPowerPct,&lt;br /&gt;
      polymorphMonster.maxAttackValue&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    if (!attacker.weapon) {&lt;br /&gt;
      attacker.maxAttackValuePolymorph += 1;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    attacker.attackValue = 0;&lt;br /&gt;
&lt;br /&gt;
    if (isMagicClass(attacker)) {&lt;br /&gt;
      attacker.statAttackValue = 2 * (polymorphStr + attacker.int);&lt;br /&gt;
    } else {&lt;br /&gt;
      attacker.statAttackValue = 2 * (polymorphStr + attacker.str);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function computeHorse(attacker) {&lt;br /&gt;
  attacker.horseAttackValue = 0;&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker) &amp;amp;&amp;amp; isRiding(attacker) &amp;amp;&amp;amp; !isPolymorph(attacker)) {&lt;br /&gt;
    var horseConstant = 30;&lt;br /&gt;
&lt;br /&gt;
    if (attacker.class === &amp;quot;weaponary&amp;quot;) {&lt;br /&gt;
      horseConstant = 60;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    attacker.horseAttackValue = floorMultiplication(&lt;br /&gt;
      2 * attacker.level + attacker.statAttackValue,&lt;br /&gt;
      attacker.horsePoint / horseConstant&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getRankBonus(attacker) {&lt;br /&gt;
  if (!isChecked(attacker.lowRank)) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  switch (attacker.rank) {&lt;br /&gt;
    case &amp;quot;aggressive&amp;quot;:&lt;br /&gt;
      return 1;&lt;br /&gt;
    case &amp;quot;fraudulent&amp;quot;:&lt;br /&gt;
      return 2;&lt;br /&gt;
    case &amp;quot;malicious&amp;quot;:&lt;br /&gt;
      return 3;&lt;br /&gt;
    case &amp;quot;cruel&amp;quot;:&lt;br /&gt;
      return 5;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcElementCoeffPvP(elementBonus, mapping, attacker, victim) {&lt;br /&gt;
  var minElementMalus = 0;&lt;br /&gt;
  var maxDifference = 0;&lt;br /&gt;
  var savedElementDifferences = [];&lt;br /&gt;
  var elementBonusIndex = 0;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; elementBonus.length; index++) {&lt;br /&gt;
    if (!attacker[mapping.elementBonus[index]]) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var elementDifference =&lt;br /&gt;
      attacker[mapping.elementBonus[index]] -&lt;br /&gt;
      victim[mapping.elementResistance[index]];&lt;br /&gt;
&lt;br /&gt;
    if (elementDifference &amp;gt;= 0) {&lt;br /&gt;
      elementBonus[elementBonusIndex] = 10 * elementDifference;&lt;br /&gt;
      minElementMalus -= elementDifference;&lt;br /&gt;
      maxDifference = Math.max(maxDifference, elementDifference);&lt;br /&gt;
      elementBonusIndex++;&lt;br /&gt;
    } else {&lt;br /&gt;
      savedElementDifferences.push(elementDifference);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (!savedElementDifferences.length) {&lt;br /&gt;
    return;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  minElementMalus += maxDifference;&lt;br /&gt;
  savedElementDifferences.sort(compareNumbers);&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; savedElementDifferences.length; index++) {&lt;br /&gt;
    var elementDifference = savedElementDifferences[index];&lt;br /&gt;
&lt;br /&gt;
    elementBonus[elementBonusIndex + index] =&lt;br /&gt;
      10 * Math.max(minElementMalus, elementDifference);&lt;br /&gt;
&lt;br /&gt;
    minElementMalus = Math.min(&lt;br /&gt;
      0,&lt;br /&gt;
      Math.max(minElementMalus, minElementMalus - elementDifference)&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcCriticalHitChance(criticalHitPercentage) {&lt;br /&gt;
  if (criticalHitPercentage &amp;lt;= 9) {&lt;br /&gt;
    return Math.floor((criticalHitPercentage + 5) / 5);&lt;br /&gt;
  }&lt;br /&gt;
  return Math.floor((criticalHitPercentage + 5) / 6);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcCriticalSkillChance(criticalHitPercentage) {&lt;br /&gt;
  if (criticalHitPercentage === 0) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  } else if (criticalHitPercentage &amp;lt;= 9) {&lt;br /&gt;
    return Math.floor((criticalHitPercentage + 7) / 3);&lt;br /&gt;
  }&lt;br /&gt;
  return Math.floor((criticalHitPercentage + 5) / 3);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcPiercingSkillChance(piercingHitPercentage) {&lt;br /&gt;
  if (piercingHitPercentage &amp;lt;= 9) {&lt;br /&gt;
    return Math.floor(piercingHitPercentage / 2);&lt;br /&gt;
  }&lt;br /&gt;
  return 5 + Math.floor((piercingHitPercentage - 10) / 4);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function magicResistanceToCoeff(magicResistance) {&lt;br /&gt;
  if (magicResistance) {&lt;br /&gt;
    return 2000 / (6 * magicResistance + 1000) - 1;&lt;br /&gt;
  }&lt;br /&gt;
  return 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createBattleValues(attacker, victim, battle, skillType) {&lt;br /&gt;
  var {&lt;br /&gt;
    mapping,&lt;br /&gt;
    constants: { polymorphPowerTable, skillPowerTable, marriageTable },&lt;br /&gt;
  } = battle;&lt;br /&gt;
  var calcAttackValues;&lt;br /&gt;
&lt;br /&gt;
  var missPercentage = 0;&lt;br /&gt;
  var attackValueMeleeMagic = 0;&lt;br /&gt;
  var attackValueMarriage = 0;&lt;br /&gt;
  var monsterResistanceMarriage = 0;&lt;br /&gt;
  var monsterResistance = 0;&lt;br /&gt;
  var typeBonus = 0;&lt;br /&gt;
  var raceBonus = 0;&lt;br /&gt;
  var raceResistance = 0;&lt;br /&gt;
  var stoneBonus = 0;&lt;br /&gt;
  var monsterBonus = 0;&lt;br /&gt;
  var elementBonus = [0, 0, 0, 0, 0, 0]; // fire, ice, lightning, earth, darkness, wind, order doesn't matter&lt;br /&gt;
  var defenseMarriage = 0;&lt;br /&gt;
  var damageMultiplier = 1;&lt;br /&gt;
  var useDamage = 1;&lt;br /&gt;
  var defense = victim.defense;&lt;br /&gt;
  var defenseBoost = defense;&lt;br /&gt;
  var magicResistance = 0;&lt;br /&gt;
  var weaponDefense = 0;&lt;br /&gt;
  var tigerStrength = 0;&lt;br /&gt;
  var berserkBonus = 0;&lt;br /&gt;
  var blessingBonus = 0;&lt;br /&gt;
  var fearBonus = 0;&lt;br /&gt;
  var magicAttackValueMeleeMagic = 0;&lt;br /&gt;
  var criticalHitPercentage = attacker.criticalHit;&lt;br /&gt;
  var isPlayerVsPlayer = false;&lt;br /&gt;
  var piercingHitPercentage = attacker.piercingHit;&lt;br /&gt;
  var extraPiercingHitPercentage = Math.max(0, piercingHitPercentage - 100);&lt;br /&gt;
  var averageDamage = 0;&lt;br /&gt;
  var averageDamageResistance = 0;&lt;br /&gt;
  var skillDamage = 0;&lt;br /&gt;
  var skillDamageResistance = 0;&lt;br /&gt;
  var rankBonus = 0;&lt;br /&gt;
  var useDarkProtection = false;&lt;br /&gt;
  var darkProtectionPoint = 0;&lt;br /&gt;
  var defensePercent = 0;&lt;br /&gt;
  var damageBonus = 0;&lt;br /&gt;
  var empireMalus = 0;&lt;br /&gt;
  var sungMaStrBonus = 0;&lt;br /&gt;
  var sungmaStrMalus = 0;&lt;br /&gt;
  var whiteDragonElixir = 0;&lt;br /&gt;
  var steelDragonElixir = 0;&lt;br /&gt;
&lt;br /&gt;
  attacker.statAttackValue = calcStatAttackValue(attacker);&lt;br /&gt;
&lt;br /&gt;
  computePolymorphPoint(attacker, victim, polymorphPowerTable);&lt;br /&gt;
  computeHorse(attacker);&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker)) {&lt;br /&gt;
    if (weaponData.hasOwnProperty(attacker.weapon)) {&lt;br /&gt;
      attacker.weapon = createWeapon(attacker.weapon);&lt;br /&gt;
    } else {&lt;br /&gt;
      attacker.weapon = createWeapon(0);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    attacker.weapon.getValues(attacker.weaponUpgrade);&lt;br /&gt;
&lt;br /&gt;
    attackValueMeleeMagic =&lt;br /&gt;
      attacker.attackValuePercent + Math.min(100, attacker.attackMeleeMagic);&lt;br /&gt;
&lt;br /&gt;
    var weaponType = attacker.weapon.type;&lt;br /&gt;
&lt;br /&gt;
    if (skillType &amp;amp;&amp;amp; attacker.class === &amp;quot;archery&amp;quot;) {&lt;br /&gt;
      if (weaponType !== 2) {&lt;br /&gt;
        useDamage = 0;&lt;br /&gt;
        weaponType = 2;&lt;br /&gt;
      }&lt;br /&gt;
      defense = 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var weaponDefenseName = mapping.defenseWeapon[weaponType];&lt;br /&gt;
    var weaponDefenseBreakName = mapping.breakWeapon[weaponType];&lt;br /&gt;
&lt;br /&gt;
    if (victim.hasOwnProperty(weaponDefenseName)) {&lt;br /&gt;
      weaponDefense = victim[weaponDefenseName];&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isChecked(attacker.whiteDragonElixir)) {&lt;br /&gt;
      whiteDragonElixir = 10;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isPC(victim)) {&lt;br /&gt;
      isPlayerVsPlayer = true;&lt;br /&gt;
&lt;br /&gt;
      if (!skillType) {&lt;br /&gt;
        if (weaponType === 2 &amp;amp;&amp;amp; !isPolymorph(attacker)) {&lt;br /&gt;
          missPercentage = victim.arrowBlock;&lt;br /&gt;
        } else {&lt;br /&gt;
          missPercentage = victim.meleeBlock;&lt;br /&gt;
        }&lt;br /&gt;
        missPercentage +=&lt;br /&gt;
          victim.meleeArrowBlock -&lt;br /&gt;
          (missPercentage * victim.meleeArrowBlock) / 100;&lt;br /&gt;
&lt;br /&gt;
        criticalHitPercentage = calcCriticalHitChance(criticalHitPercentage);&lt;br /&gt;
        berserkBonus = calcBerserkBonus(skillPowerTable, victim);&lt;br /&gt;
        blessingBonus = calcBlessingBonus(skillPowerTable, victim);&lt;br /&gt;
        fearBonus = calcFearBonus(skillPowerTable, victim);&lt;br /&gt;
        averageDamageResistance = victim.averageDamageResistance;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      typeBonus = Math.max(1, attacker.humanBonus - victim.humanResistance);&lt;br /&gt;
      raceBonus = attacker[mapping.raceBonus[victim.race]];&lt;br /&gt;
      raceResistance = victim[mapping.raceResistance[attacker.race]];&lt;br /&gt;
&lt;br /&gt;
      calcElementCoeffPvP(elementBonus, mapping, attacker, victim);&lt;br /&gt;
&lt;br /&gt;
      if (weaponType !== 2 &amp;amp;&amp;amp; attacker.hasOwnProperty(weaponDefenseBreakName)) {&lt;br /&gt;
        weaponDefense -= attacker[weaponDefenseBreakName];&lt;br /&gt;
      }&lt;br /&gt;
    } else {&lt;br /&gt;
      if (isChecked(attacker.isMarried)) {&lt;br /&gt;
        if (isChecked(attacker.loveNecklace)) {&lt;br /&gt;
          attackValueMarriage = getMarriageBonusValue(&lt;br /&gt;
            attacker,&lt;br /&gt;
            marriageTable,&lt;br /&gt;
            &amp;quot;loveNecklace&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isChecked(attacker.loveEarrings)) {&lt;br /&gt;
          criticalHitPercentage += getMarriageBonusValue(&lt;br /&gt;
            attacker,&lt;br /&gt;
            marriageTable,&lt;br /&gt;
            &amp;quot;loveEarrings&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isChecked(attacker.harmonyEarrings)) {&lt;br /&gt;
          piercingHitPercentage += getMarriageBonusValue(&lt;br /&gt;
            attacker,&lt;br /&gt;
            marriageTable,&lt;br /&gt;
            &amp;quot;harmonyEarrings&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (isChecked(attacker.tigerStrength)) {&lt;br /&gt;
        tigerStrength = 40;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      for (var index = 0; index &amp;lt; elementBonus.length; index++) {&lt;br /&gt;
        var elementBonusName = mapping.elementBonus[index];&lt;br /&gt;
        var elementResistanceName = mapping.elementResistance[index];&lt;br /&gt;
&lt;br /&gt;
        if (attacker[elementBonusName] &amp;amp;&amp;amp; victim[elementBonusName]) {&lt;br /&gt;
          elementBonus[index] =&lt;br /&gt;
            50 * (attacker[elementBonusName] - victim[elementResistanceName]);&lt;br /&gt;
        } else {&lt;br /&gt;
          elementBonus[index] = 5 * attacker[elementBonusName];&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      var victimType = victim.type;&lt;br /&gt;
&lt;br /&gt;
      if (victimType !== -1) {&lt;br /&gt;
        typeBonus = attacker[mapping.typeFlag[victimType]];&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      monsterBonus = attacker.monsterBonus;&lt;br /&gt;
&lt;br /&gt;
      if (isStone(victim)) {&lt;br /&gt;
        stoneBonus = attacker.stoneBonus;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (isBoss(victim)) {&lt;br /&gt;
        if (skillType) {&lt;br /&gt;
          skillDamage += attacker.skillBossDamage;&lt;br /&gt;
        } else {&lt;br /&gt;
          averageDamage += attacker.bossDamage;&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (isChecked(attacker.onYohara)) {&lt;br /&gt;
        var sungmaStrDifference = attacker.sungmaStr - attacker.sungmaStrMalus;&lt;br /&gt;
&lt;br /&gt;
        if (sungmaStrDifference &amp;gt;= 0) {&lt;br /&gt;
          sungMaStrBonus = sungmaStrDifference;&lt;br /&gt;
        } else {&lt;br /&gt;
          sungmaStrMalus = 0.5;&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (skillType) {&lt;br /&gt;
      skillDamage += attacker.skillDamage;&lt;br /&gt;
    } else {&lt;br /&gt;
      averageDamage += attacker.averageDamage;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    rankBonus = getRankBonus(attacker);&lt;br /&gt;
    damageBonus = attacker.damageBonus;&lt;br /&gt;
&lt;br /&gt;
    if (isChecked(attacker.empireMalus)) {&lt;br /&gt;
      empireMalus = 1;&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    if (isPC(victim)) {&lt;br /&gt;
      if (isChecked(victim.isMarried)) {&lt;br /&gt;
        if (isChecked(victim.harmonyBracelet)) {&lt;br /&gt;
          monsterResistanceMarriage = getMarriageBonusValue(&lt;br /&gt;
            victim,&lt;br /&gt;
            marriageTable,&lt;br /&gt;
            &amp;quot;harmonyBracelet&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isChecked(victim.harmonyNecklace) &amp;amp;&amp;amp; !skillType) {&lt;br /&gt;
          defenseMarriage = getMarriageBonusValue(&lt;br /&gt;
            victim,&lt;br /&gt;
            marriageTable,&lt;br /&gt;
            &amp;quot;harmonyNecklace&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      monsterResistance = victim.monsterResistance;&lt;br /&gt;
&lt;br /&gt;
      for (var index = 0; index &amp;lt; elementBonus.length; index++) {&lt;br /&gt;
        var elementBonusName = mapping.elementBonus[index];&lt;br /&gt;
        var elementResistanceName = mapping.elementResistance[index];&lt;br /&gt;
&lt;br /&gt;
        if (attacker[elementBonusName]) {&lt;br /&gt;
          elementBonus[index] =&lt;br /&gt;
            80 * (attacker[elementBonusName] - victim[elementResistanceName]);&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (!skillType) {&lt;br /&gt;
        if (isMeleeAttacker(attacker)) {&lt;br /&gt;
          missPercentage = victim.meleeBlock;&lt;br /&gt;
          averageDamageResistance = victim.averageDamageResistance;&lt;br /&gt;
          berserkBonus = calcBerserkBonus(skillPowerTable, victim);&lt;br /&gt;
          blessingBonus = calcBlessingBonus(skillPowerTable, victim);&lt;br /&gt;
          fearBonus = calcFearBonus(skillPowerTable, victim);&lt;br /&gt;
        } else if (isRangeAttacker(attacker)) {&lt;br /&gt;
          missPercentage = victim.arrowBlock;&lt;br /&gt;
          weaponDefense = victim.arrowDefense;&lt;br /&gt;
          averageDamageResistance = victim.averageDamageResistance;&lt;br /&gt;
          berserkBonus = calcBerserkBonus(skillPowerTable, victim);&lt;br /&gt;
          blessingBonus = calcBlessingBonus(skillPowerTable, victim);&lt;br /&gt;
          fearBonus = calcFearBonus(skillPowerTable, victim);&lt;br /&gt;
        } else if (isMagicAttacker(attacker)) {&lt;br /&gt;
          missPercentage = victim.arrowBlock;&lt;br /&gt;
          skillDamageResistance = victim.skillDamageResistance;&lt;br /&gt;
          magicResistance = victim.magicResistance;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        missPercentage +=&lt;br /&gt;
          victim.meleeArrowBlock -&lt;br /&gt;
          (missPercentage * victim.meleeArrowBlock) / 100;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    typeBonus = 1;&lt;br /&gt;
    damageMultiplier = attacker.damageMultiplier;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillType) {&lt;br /&gt;
    criticalHitPercentage = calcCriticalSkillChance(criticalHitPercentage);&lt;br /&gt;
    piercingHitPercentage = calcPiercingSkillChance(piercingHitPercentage);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (isPC(victim)) {&lt;br /&gt;
    if (!skillType &amp;amp;&amp;amp; isChecked(victim.biologist70)) {&lt;br /&gt;
      defenseBoost = Math.floor((defenseBoost * 110) / 100);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    criticalHitPercentage = Math.max(&lt;br /&gt;
      0,&lt;br /&gt;
      criticalHitPercentage - victim.criticalHitResistance&lt;br /&gt;
    );&lt;br /&gt;
    piercingHitPercentage = Math.max(&lt;br /&gt;
      0,&lt;br /&gt;
      piercingHitPercentage - victim.piercingHitResistance&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    if (skillType) {&lt;br /&gt;
      skillDamageResistance = victim.skillDamageResistance;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      victim.useDarkProtection &amp;amp;&amp;amp;&lt;br /&gt;
      victim.class === &amp;quot;black_magic&amp;quot; &amp;amp;&amp;amp;&lt;br /&gt;
      victim.skillDarkProtection&lt;br /&gt;
    ) {&lt;br /&gt;
      useDarkProtection = true;&lt;br /&gt;
      darkProtectionPoint = calcDarkProtectionPoint(skillPowerTable, victim);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isMagicClass(victim)) {&lt;br /&gt;
      defensePercent = (-2 * victim.magicDefense * victim.defensePercent) / 100;&lt;br /&gt;
    } else {&lt;br /&gt;
      defensePercent = (-2 * defenseBoost * victim.defensePercent) / 100;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isChecked(victim.steelDragonElixir)) {&lt;br /&gt;
      steelDragonElixir = 10;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillType === &amp;quot;magic&amp;quot;) {&lt;br /&gt;
    attackValueMeleeMagic = 0;&lt;br /&gt;
    magicAttackValueMeleeMagic =&lt;br /&gt;
      attacker.attackMagic + Math.min(100, attacker.attackMeleeMagic);&lt;br /&gt;
    attackValueMarriage = 0;&lt;br /&gt;
    defense = 0;&lt;br /&gt;
    if (isDispell(attacker, 6)) {&lt;br /&gt;
      typeBonus = 0;&lt;br /&gt;
      raceBonus = 0;&lt;br /&gt;
      raceResistance = 0;&lt;br /&gt;
      stoneBonus = 0;&lt;br /&gt;
      monsterBonus = 0;&lt;br /&gt;
      for (var index = 0; index &amp;lt; elementBonus.length; index++) {&lt;br /&gt;
        elementBonus[index] = 0;&lt;br /&gt;
      }&lt;br /&gt;
    } else {&lt;br /&gt;
      magicResistance = victim.magicResistance;&lt;br /&gt;
    }&lt;br /&gt;
    weaponDefense = 0;&lt;br /&gt;
    calcAttackValues = calcMagicAttackValue;&lt;br /&gt;
  } else {&lt;br /&gt;
    calcAttackValues = calcSecondaryAttackValue;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  missPercentage = Math.min(100, missPercentage);&lt;br /&gt;
  criticalHitPercentage = Math.min(criticalHitPercentage, 100);&lt;br /&gt;
  piercingHitPercentage = Math.min(piercingHitPercentage, 100);&lt;br /&gt;
&lt;br /&gt;
  const bonusValues = {&lt;br /&gt;
    missPercentage: missPercentage,&lt;br /&gt;
    skipCriticalStep: [&lt;br /&gt;
      !Boolean(100 - criticalHitPercentage),&lt;br /&gt;
      !Boolean(criticalHitPercentage),&lt;br /&gt;
    ],&lt;br /&gt;
    skipPiercingStep: [&lt;br /&gt;
      !Boolean(100 - piercingHitPercentage),&lt;br /&gt;
      !Boolean(piercingHitPercentage),&lt;br /&gt;
    ],&lt;br /&gt;
    weaponBonusCoeff: 1,&lt;br /&gt;
    attackValueCoeff: 100 + attackValueMeleeMagic,&lt;br /&gt;
    attackValueMarriage: attackValueMarriage,&lt;br /&gt;
    monsterResistanceMarriageCoeff: 100 - monsterResistanceMarriage,&lt;br /&gt;
    monsterResistanceCoeff: 100 - monsterResistance,&lt;br /&gt;
    typeBonusCoeff: typeBonus,&lt;br /&gt;
    raceBonusCoeff: raceBonus,&lt;br /&gt;
    raceResistanceCoeff: raceResistance,&lt;br /&gt;
    stoneBonusCoeff: stoneBonus,&lt;br /&gt;
    monsterBonusCoeff: monsterBonus,&lt;br /&gt;
    elementBonusCoeff: elementBonus,&lt;br /&gt;
    damageMultiplier: damageMultiplier,&lt;br /&gt;
    useDamage: useDamage,&lt;br /&gt;
    defense: defense,&lt;br /&gt;
    defenseBoost: defenseBoost,&lt;br /&gt;
    defenseMarriage: defenseMarriage,&lt;br /&gt;
    tigerStrengthCoeff: 100 + tigerStrength,&lt;br /&gt;
    magicResistanceCoeff: magicResistanceToCoeff(magicResistance),&lt;br /&gt;
    weaponDefenseCoeff: 100 - weaponDefense,&lt;br /&gt;
    berserkBonusCoeff: 100 + berserkBonus,&lt;br /&gt;
    blessingBonusCoeff: 100 - blessingBonus,&lt;br /&gt;
    fearBonusCoeff: 100 - fearBonus,&lt;br /&gt;
    magicAttackValueCoeff: 100 + magicAttackValueMeleeMagic,&lt;br /&gt;
    extraPiercingHitCoeff: 5 * extraPiercingHitPercentage,&lt;br /&gt;
    averageDamageCoeff: 100 + averageDamage,&lt;br /&gt;
    averageDamageResistanceCoeff: 100 - Math.min(99, averageDamageResistance),&lt;br /&gt;
    skillDamageCoeff: 100 + skillDamage,&lt;br /&gt;
    skillDamageResistanceCoeff: 100 - Math.min(99, skillDamageResistance),&lt;br /&gt;
    useDarkProtection: useDarkProtection,&lt;br /&gt;
    darkProtectionPoint: darkProtectionPoint,&lt;br /&gt;
    darkProtectionSp: victim.darkProtectionSp,&lt;br /&gt;
    rankBonusCoeff: 100 + rankBonus,&lt;br /&gt;
    defensePercent: Math.floor(defensePercent),&lt;br /&gt;
    damageBonusCoeff: Math.min(20, damageBonus),&lt;br /&gt;
    empireMalusCoeff: 10 - empireMalus,&lt;br /&gt;
    sungMaStrBonusCoeff: 10000 + sungMaStrBonus,&lt;br /&gt;
    sungmaStrMalusCoeff: sungmaStrMalus,&lt;br /&gt;
    whiteDragonElixirCoeff: 100 + whiteDragonElixir,&lt;br /&gt;
    steelDragonElixirCoeff: 100 - steelDragonElixir,&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  const damageTypeWeights = [&lt;br /&gt;
    (100 - criticalHitPercentage) *&lt;br /&gt;
      (100 - piercingHitPercentage) *&lt;br /&gt;
      (100 - missPercentage),&lt;br /&gt;
    criticalHitPercentage *&lt;br /&gt;
      (100 - piercingHitPercentage) *&lt;br /&gt;
      (100 - missPercentage),&lt;br /&gt;
    (100 - criticalHitPercentage) *&lt;br /&gt;
      piercingHitPercentage *&lt;br /&gt;
      (100 - missPercentage),&lt;br /&gt;
    criticalHitPercentage * piercingHitPercentage * (100 - missPercentage),&lt;br /&gt;
  ];&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    attacker: attacker,&lt;br /&gt;
    victim: victim,&lt;br /&gt;
    attackFactor: calcAttackFactor(attacker, victim),&lt;br /&gt;
    mainAttackValue: calcMainAttackValue(attacker),&lt;br /&gt;
    attackValues: calcAttackValues(attacker, isPlayerVsPlayer),&lt;br /&gt;
    bonusValues: bonusValues,&lt;br /&gt;
    damageTypeWeights: damageTypeWeights,&lt;br /&gt;
    attackTypeMapping: mapping.attackType,&lt;br /&gt;
    damageWeightedByType: {&lt;br /&gt;
      normalHit: {},&lt;br /&gt;
      criticalHit: {},&lt;br /&gt;
      piercingHit: {},&lt;br /&gt;
      criticalPiercingHit: {},&lt;br /&gt;
    },&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateBattleValues(battleValues, skillFormula, skillInfo) {&lt;br /&gt;
  var weaponBonus = 0;&lt;br /&gt;
  var skillWard = 0;&lt;br /&gt;
  var skillBonus = 0;&lt;br /&gt;
  var skillBonusByBonus = 0;&lt;br /&gt;
  var { attacker: attacker, bonusValues: bonusValues } = battleValues;&lt;br /&gt;
  var {&lt;br /&gt;
    range: [minVariation, maxVariation],&lt;br /&gt;
  } = skillInfo;&lt;br /&gt;
  var variationLength = maxVariation - minVariation + 1;&lt;br /&gt;
&lt;br /&gt;
  if (skillInfo.hasOwnProperty(&amp;quot;weaponBonus&amp;quot;)) {&lt;br /&gt;
    var [weaponType, weaponBonusValue] = skillInfo.weaponBonus;&lt;br /&gt;
&lt;br /&gt;
    if (weaponType === attacker.weapon.type) {&lt;br /&gt;
      weaponBonus = weaponBonusValue;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillInfo.skillBonus) {&lt;br /&gt;
    skillBonus = skillInfo.skillBonus;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillInfo.skillWard) {&lt;br /&gt;
    skillWard = skillInfo.skillWard;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillInfo.skillBonusByBonus) {&lt;br /&gt;
    skillBonusByBonus = skillInfo.skillBonusByBonus;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillInfo.removeWeaponReduction) {&lt;br /&gt;
    bonusValues.weaponDefenseCoeff = 100;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  bonusValues.weaponBonusCoeff = 100 + weaponBonus;&lt;br /&gt;
  bonusValues.skillWardCoeff = 1 - skillWard / 100;&lt;br /&gt;
  bonusValues.skillBonusCoeff = 1 + skillBonus / 100;&lt;br /&gt;
  bonusValues.skillBonusByBonusCoeff = 100 + skillBonusByBonus;&lt;br /&gt;
&lt;br /&gt;
  battleValues.skillFormula = skillFormula;&lt;br /&gt;
  battleValues.skillRange = skillInfo.range;&lt;br /&gt;
  battleValues.attackValues.totalCardinal *= variationLength;&lt;br /&gt;
  battleValues.attackValues.possibleDamageCount *= variationLength;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcWeights(minValue, maxValue, minInterval) {&lt;br /&gt;
  var firstWeightLimit = minValue + minInterval - 1;&lt;br /&gt;
  var lastWeightsLimit = maxValue - minInterval + 1;&lt;br /&gt;
  var weights = [];&lt;br /&gt;
&lt;br /&gt;
  for (var value = minValue; value &amp;lt; firstWeightLimit; value++) {&lt;br /&gt;
    weights.push(value - minValue + 1);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (var value = firstWeightLimit; value &amp;lt;= lastWeightsLimit; value++) {&lt;br /&gt;
    weights.push(minInterval);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (var value = lastWeightsLimit + 1; value &amp;lt;= maxValue; value++) {&lt;br /&gt;
    weights.push(maxValue - value + 1);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return weights;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcBerserkBonus(skillPowerTable, victim) {&lt;br /&gt;
  if (!isChecked(victim.useBerserk) || victim.class !== &amp;quot;body&amp;quot;) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var skillPower = getSkillPower(victim.skillBerserk, skillPowerTable);&lt;br /&gt;
&lt;br /&gt;
  if (!skillPower) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var berserkBonus = Math.floor(skillPower * 25);&lt;br /&gt;
&lt;br /&gt;
  return berserkBonus;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcBlessingBonus(skillPowerTable, victim) {&lt;br /&gt;
  if (!isChecked(victim.isBlessed)) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var int = victim.intBlessing;&lt;br /&gt;
  var dex = victim.dexBlessing;&lt;br /&gt;
  var skillPower = getSkillPower(victim.skillBlessing, skillPowerTable);&lt;br /&gt;
&lt;br /&gt;
  if (!skillPower) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var blessingBonus = floorMultiplication(&lt;br /&gt;
    ((int * 0.3 + 5) * (2 * skillPower + 0.5) + 0.3 * dex) / (skillPower + 2.3),&lt;br /&gt;
    1&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  if (victim.class === &amp;quot;dragon&amp;quot; &amp;amp;&amp;amp; isChecked(victim.blessingOnself)) {&lt;br /&gt;
    blessingBonus = floorMultiplication(blessingBonus, 1.1);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return blessingBonus;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcFearBonus(skillPowerTable, victim) {&lt;br /&gt;
  if (!isChecked(victim.useFear) || victim.class !== &amp;quot;weaponary&amp;quot;) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var skillPower = getSkillPower(victim.skillFear, skillPowerTable);&lt;br /&gt;
&lt;br /&gt;
  if (!skillPower) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var fearBonus = 5 + Math.floor(skillPower * 20);&lt;br /&gt;
&lt;br /&gt;
  return fearBonus;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcDarkProtectionPoint(skillPowerTable, victim) {&lt;br /&gt;
  var skillPower = getSkillPower(victim.skillDarkProtection, skillPowerTable);&lt;br /&gt;
&lt;br /&gt;
  return floorMultiplication(100 - victim.int * 0.84 * skillPower, 1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSkillFormula(battle, skillId, battleValues, removeSkillVariation) {&lt;br /&gt;
  var { attacker, victim, attackFactor } = battleValues;&lt;br /&gt;
  var skillPowerTable = battle.constants.skillPowerTable;&lt;br /&gt;
&lt;br /&gt;
  var skillFormula;&lt;br /&gt;
  var skillInfo = { range: [0, 0] };&lt;br /&gt;
&lt;br /&gt;
  var { class: attackerClass, level: lv, vit, str, int, dex } = attacker;&lt;br /&gt;
&lt;br /&gt;
  if (skillId &amp;lt;= 9) {&lt;br /&gt;
    var skillPower = getSkillPower(&lt;br /&gt;
      attacker[&amp;quot;attackSkill&amp;quot; + skillId],&lt;br /&gt;
      skillPowerTable&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    var improvedBySkillBonus = false;&lt;br /&gt;
    var improvedByBonus = false;&lt;br /&gt;
&lt;br /&gt;
    if (attackerClass === &amp;quot;body&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Triple lacération&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.1 * atk + (0.5 * atk + 1.5 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Moulinet à l'épée&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              3 * atk + (0.8 * atk + 5 * str + 3 * dex + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Accélération&lt;br /&gt;
        case 5:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * atk + (atk + dex * 3 + str * 7 + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Volonté de vivre&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              (3 * atk + (atk + 1.5 * str) * skillPower) * 1.07,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          break;&lt;br /&gt;
        // Tremblement de terre&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              3 * atk +&lt;br /&gt;
                (0.9 * atk + variation + 5 * str + 3 * dex + lv) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;mental&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Attaque de l'esprit&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2.3 * atk + (4 * atk + 4 * str + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Attaque de la paume&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2.3 * atk + (3 * atk + 4 * str + 3 * vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Charge&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * atk + (2 * atk + 2 * dex + 2 * vit + 4 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          break;&lt;br /&gt;
        // Coup d'épée&lt;br /&gt;
        case 5:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * atk + (atk + 3 * dex + 5 * str + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Orbe de l'épée&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              (2 * atk + (2 * atk + 2 * dex + 2 * vit + 4 * str) * skillPower) *&lt;br /&gt;
                1.1,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          break;&lt;br /&gt;
        // Tremblement de terre&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              3 * atk +&lt;br /&gt;
                (0.9 * atk + variation + 5 * str + 3 * dex + lv) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;blade_fight&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Embuscade&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk + (1.2 * atk + variation + 4 * dex + 4 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [1, 50];&lt;br /&gt;
          skillInfo.range = [500, 700];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Attaque rapide&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk + (1.6 * atk + variation + 7 * dex + 7 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [1, 35];&lt;br /&gt;
          skillInfo.range = [200, 300];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Dague filante&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * atk + (0.5 * atk + 9 * dex + 7 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Brume empoisonnée&lt;br /&gt;
        case 5:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * lv + (atk + 3 * str + 18 * dex) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Poison insidieux&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              (2 * lv + (atk + 3 * str + 18 * dex) * skillPower) * 1.1,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          break;&lt;br /&gt;
        // Étoiles brillantes&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk + (1.7 * atk + variation + 6 * dex + 5 * lv) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;archery&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Tir à répétition&lt;br /&gt;
        // case 1:&lt;br /&gt;
        //   skillFormula = function (atk) {&lt;br /&gt;
        //     return floorMultiplication(&lt;br /&gt;
        //       atk + 0.2 * atk * Math.floor(2 + 6 * skillPower) + (0.8 * atk + 8 * dex * attackFactor + 2 * int) * skillPower,&lt;br /&gt;
        //       1&lt;br /&gt;
        //     );&lt;br /&gt;
        //   };&lt;br /&gt;
        //   improvedByBonus = true;&lt;br /&gt;
        //   break;&lt;br /&gt;
        // Pluie de flèches&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk + (1.7 * atk + 5 * dex + str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Flèche de feu&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.5 * atk + (2.6 * atk + 0.9 * int + variation) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [100, 300];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Foulée de plume&lt;br /&gt;
        case 4:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              (3 * dex + 200 + 2 * str + 2 * int) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.removeWeaponReduction = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Flèche empoisonnée&lt;br /&gt;
        case 5:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk +&lt;br /&gt;
                (1.4 * atk + variation + 7 * dex + 4 * str + 4 * int) *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [100, 200];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Coup étincelant&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              (atk +&lt;br /&gt;
                (1.2 * atk + variation + 6 * dex + 3 * str + 3 * int) *&lt;br /&gt;
                  skillPower) *&lt;br /&gt;
                1.2,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [100, 200];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Tir tempête&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.9 * atk + (2.6 * atk + variation) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;weaponary&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Toucher brûlant&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk +&lt;br /&gt;
                2 * lv +&lt;br /&gt;
                2 * int +&lt;br /&gt;
                (2 * atk + 4 * str + 14 * int) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Tourbillon du dragon&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.1 * atk +&lt;br /&gt;
                2 * lv +&lt;br /&gt;
                2 * int +&lt;br /&gt;
                (1.5 * atk + str + 12 * int) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Contre-sort&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              40 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                2 * int +&lt;br /&gt;
                (10 * int + 7 * mav + variation) * attackFactor * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [50, 100];&lt;br /&gt;
          break;&lt;br /&gt;
        // Coup démoniaque&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.9 * atk + (2.6 * atk + variation) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;black_magic&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Attaque des ténèbres&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              40 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                2 * int +&lt;br /&gt;
                (13 * int + 6 * mav + variation) * attackFactor * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [50, 100];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Attaque de flammes&lt;br /&gt;
        // case 2:&lt;br /&gt;
        //   skillFormula = function (mav, variation) {&lt;br /&gt;
        //     return floorMultiplication(&lt;br /&gt;
        //       5 * lv + 2 * int + (7 * int + 8 * mav + 4 * str + 2 * vit + variation) * skillPower,&lt;br /&gt;
        //       1&lt;br /&gt;
        //     );&lt;br /&gt;
        //   };&lt;br /&gt;
        //   skillInfo.range = [180, 100];&lt;br /&gt;
        //   improvedByBonus = true;&lt;br /&gt;
        //   break;&lt;br /&gt;
        // Esprit de flammes&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              30 +&lt;br /&gt;
                2 * lv +&lt;br /&gt;
                2 * int +&lt;br /&gt;
                (7 * int + 6 * mav + variation) * attackFactor * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [200, 500];&lt;br /&gt;
          break;&lt;br /&gt;
        // Frappe de l'esprit&lt;br /&gt;
        // case 5:&lt;br /&gt;
        //   skillFormula = function (mav, variation) {&lt;br /&gt;
        //     return floorMultiplication(&lt;br /&gt;
        //       40 + 2 * lv + 2 * int + (2 * vit + 2 * dex + 13 * int + 6 * mav + variation) * attackFactor * skillPower,&lt;br /&gt;
        //       1&lt;br /&gt;
        //     );&lt;br /&gt;
        //   };&lt;br /&gt;
        //   skillInfo.range = [180, 200];&lt;br /&gt;
        //   break;&lt;br /&gt;
        // Orbe des ténèbres&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (mav) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              120 +&lt;br /&gt;
                6 * lv +&lt;br /&gt;
                (5 * vit + 5 * dex + 29 * int + 9 * mav) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Vague mortelle&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              120 +&lt;br /&gt;
                6 * lv +&lt;br /&gt;
                (5 * vit + 5 * dex + 30 * int + variation + 9 * mav) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;dragon&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Talisman volant&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (mav) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              70 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                (18 * int + 7 * str + 5 * mav + 50) * attackFactor * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [4, 10];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Dragon chassant&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (mav) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              60 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                (16 * int + 6 * dex + 6 * mav + 120) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [4, 10];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Rugissement du dragon&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (mav) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              70 +&lt;br /&gt;
                3 * lv +&lt;br /&gt;
                (20 * int + 3 * str + 10 * mav + 100) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [4, 10];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Météore&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              120 +&lt;br /&gt;
                6 * lv +&lt;br /&gt;
                (5 * vit + 5 * dex + 30 * int + variation + 9 * mav) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;heal&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Jet de foudre&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              60 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                (8 * int + 2 * dex + 8 * mav + variation) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [6, 10];&lt;br /&gt;
          skillInfo.range = [5 * int, 15 * int];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Invocation de foudre&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              40 +&lt;br /&gt;
                4 * lv +&lt;br /&gt;
                (13 * int + 2 * str + 10 * mav + variation) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [6, 10];&lt;br /&gt;
          skillInfo.range = [5 * int, 16 * int];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Griffe de foudre&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              50 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                (8 * int + 2 * str + 8 * mav + variation) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 800];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;lycan&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Déchiqueter&lt;br /&gt;
        // case 1:&lt;br /&gt;
        //   skillFormula = function (atk) {&lt;br /&gt;
        //     return floorMultiplication(&lt;br /&gt;
        //       1.1 * atk + (0.3 * atk + 1.5 * str) * skillPower,&lt;br /&gt;
        //       1&lt;br /&gt;
        //     );&lt;br /&gt;
        //   };&lt;br /&gt;
        //   skillInfo.weaponBonus = [5, 54];&lt;br /&gt;
        //   improvedByBonus = true;&lt;br /&gt;
        //   break;&lt;br /&gt;
        // Souffle de loup&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * atk + (atk + 3 * dex + 5 * str + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [5, 35];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Bond de loup&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk + (1.6 * atk + 200 + 7 * dex + 7 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [5, 35];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Griffe de loup&lt;br /&gt;
        case 4:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              3 * atk + (0.8 * atk + 6 * str + 2 * dex + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Tempête cinglante&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.8 * atk +&lt;br /&gt;
                (atk + 6 * dex + variation + 3 * str + lv) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
    if (improvedBySkillBonus) {&lt;br /&gt;
      skillInfo.skillBonus =&lt;br /&gt;
        16 * getSkillPower(attacker.skillBonus, skillPowerTable);&lt;br /&gt;
&lt;br /&gt;
      var skillWardChoice = victim.skillWardChoice;&lt;br /&gt;
&lt;br /&gt;
      if (skillWardChoice &amp;amp;&amp;amp; skillWardChoice === attackerClass) {&lt;br /&gt;
        skillInfo.skillWard =&lt;br /&gt;
          24 * getSkillPower(victim.skillWard, skillPowerTable);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (improvedByBonus) {&lt;br /&gt;
      skillInfo.skillBonusByBonus = attacker[&amp;quot;skillBonus&amp;quot; + skillId];&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (removeSkillVariation) {&lt;br /&gt;
      var averageVariation = (skillInfo.range[0] + skillInfo.range[0]) / 2;&lt;br /&gt;
      skillInfo.range = [averageVariation, averageVariation];&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    var skillPower = getSkillPower(&lt;br /&gt;
      attacker[&amp;quot;horseSkill&amp;quot; + skillId],&lt;br /&gt;
      skillPowerTable&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    switch (skillId) {&lt;br /&gt;
      // Combat équestre&lt;br /&gt;
      case 137:&lt;br /&gt;
        skillFormula = function (atk) {&lt;br /&gt;
          return floorMultiplication(atk + 2 * atk * skillPower, 1);&lt;br /&gt;
        };&lt;br /&gt;
        break;&lt;br /&gt;
      // Charge à cheval&lt;br /&gt;
      case 138:&lt;br /&gt;
        skillFormula = function (atk) {&lt;br /&gt;
          return floorMultiplication(&lt;br /&gt;
            2.4 * (200 + 1.5 * lv) + 600 * skillPower,&lt;br /&gt;
            1&lt;br /&gt;
          );&lt;br /&gt;
        };&lt;br /&gt;
        break;&lt;br /&gt;
      // Vague de Pouvoir&lt;br /&gt;
      case 139:&lt;br /&gt;
        skillFormula = function (atk) {&lt;br /&gt;
          return floorMultiplication(&lt;br /&gt;
            2 * (200 + 1.5 * lv) + 600 * skillPower,&lt;br /&gt;
            1&lt;br /&gt;
          );&lt;br /&gt;
        };&lt;br /&gt;
        break;&lt;br /&gt;
      // Grêle de flèches&lt;br /&gt;
      case 140:&lt;br /&gt;
        skillFormula = function (atk) {&lt;br /&gt;
          return floorMultiplication(atk + 2 * atk * skillPower, 1);&lt;br /&gt;
        };&lt;br /&gt;
        break;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  updateBattleValues(battleValues, skillFormula, skillInfo);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcMagicAttackValueAugmentation(&lt;br /&gt;
  magicAttackValueWeapon,&lt;br /&gt;
  magicAttackValueBonus&lt;br /&gt;
) {&lt;br /&gt;
  if (magicAttackValueBonus) {&lt;br /&gt;
    return Math.max(&lt;br /&gt;
      1,&lt;br /&gt;
      0.0025056 *&lt;br /&gt;
        magicAttackValueBonus ** 0.602338 *&lt;br /&gt;
        magicAttackValueWeapon ** 1.20476&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
  return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getMagicAttackValueAugmentation(&lt;br /&gt;
  minMagicAttackValue,&lt;br /&gt;
  maxMagicAttackValue,&lt;br /&gt;
  magicAttackValueBonus&lt;br /&gt;
) {&lt;br /&gt;
  var magicAttackValueAugmentation = [];&lt;br /&gt;
&lt;br /&gt;
  for (&lt;br /&gt;
    var magicAttackValue = minMagicAttackValue;&lt;br /&gt;
    magicAttackValue &amp;lt;= maxMagicAttackValue;&lt;br /&gt;
    magicAttackValue++&lt;br /&gt;
  ) {&lt;br /&gt;
    magicAttackValueAugmentation.push(&lt;br /&gt;
      calcMagicAttackValueAugmentation(magicAttackValue, magicAttackValueBonus)&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return magicAttackValueAugmentation;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcPhysicalDamage(battleValues) {&lt;br /&gt;
  const {&lt;br /&gt;
    attackFactor,&lt;br /&gt;
    mainAttackValue,&lt;br /&gt;
    attackValues: {&lt;br /&gt;
      minAttackValue,&lt;br /&gt;
      maxAttackValue,&lt;br /&gt;
      attackValueOther,&lt;br /&gt;
      weights,&lt;br /&gt;
      criticalAttackRange,&lt;br /&gt;
    },&lt;br /&gt;
    bonusValues,&lt;br /&gt;
    damageWeightedByType,&lt;br /&gt;
  } = battleValues;&lt;br /&gt;
&lt;br /&gt;
  const savedDamage = {};&lt;br /&gt;
&lt;br /&gt;
  if (bonusValues.missPercentage) {&lt;br /&gt;
    damageWeightedByType.miss = bonusValues.missPercentage / 100;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (&lt;br /&gt;
    let attackValue = minAttackValue;&lt;br /&gt;
    attackValue &amp;lt;= maxAttackValue;&lt;br /&gt;
    attackValue++&lt;br /&gt;
  ) {&lt;br /&gt;
    const weight = weights[attackValue - minAttackValue];&lt;br /&gt;
    const damageByType = [[], [], [], []];&lt;br /&gt;
    const currentDamageInfo = [weight, damageByType];&lt;br /&gt;
&lt;br /&gt;
    const secondaryAttackValue = 2 * attackValue + attackValueOther;&lt;br /&gt;
    const rawDamage =&lt;br /&gt;
      mainAttackValue + floorMultiplication(attackFactor, secondaryAttackValue);&lt;br /&gt;
&lt;br /&gt;
    const damageWithPrimaryBonuses = calcDamageWithPrimaryBonuses(&lt;br /&gt;
      rawDamage,&lt;br /&gt;
      bonusValues&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    const minPiercingDamage =&lt;br /&gt;
      damageWithPrimaryBonuses -&lt;br /&gt;
      bonusValues.defenseBoost -&lt;br /&gt;
      bonusValues.defenseMarriage;&lt;br /&gt;
&lt;br /&gt;
    const damageValues =&lt;br /&gt;
      minPiercingDamage &amp;lt;= 2 ? [1, 2, 3, 4, 5] : [damageWithPrimaryBonuses];&lt;br /&gt;
&lt;br /&gt;
    for (const damage of damageValues) {&lt;br /&gt;
      saveFinalDamage(&lt;br /&gt;
        damage,&lt;br /&gt;
        minPiercingDamage,&lt;br /&gt;
        damageWithPrimaryBonuses,&lt;br /&gt;
        bonusValues,&lt;br /&gt;
        criticalAttackRange,&lt;br /&gt;
        damageByType&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    savedDamage[attackValue] = currentDamageInfo;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  processSavedDamage(savedDamage, damageWeightedByType, battleValues);&lt;br /&gt;
&lt;br /&gt;
  return damageWeightedByType;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcPhysicalSkillDamage(battleValues) {&lt;br /&gt;
  const {&lt;br /&gt;
    attackFactor,&lt;br /&gt;
    mainAttackValue,&lt;br /&gt;
    attackValues: {&lt;br /&gt;
      minAttackValue,&lt;br /&gt;
      maxAttackValue,&lt;br /&gt;
      attackValueOther,&lt;br /&gt;
      weights,&lt;br /&gt;
      criticalAttackRange,&lt;br /&gt;
    },&lt;br /&gt;
    bonusValues,&lt;br /&gt;
    damageWeightedByType,&lt;br /&gt;
    skillFormula,&lt;br /&gt;
    skillRange: [minVariation, maxVariation],&lt;br /&gt;
  } = battleValues;&lt;br /&gt;
&lt;br /&gt;
  const savedDamage = {};&lt;br /&gt;
&lt;br /&gt;
  for (&lt;br /&gt;
    let attackValue = minAttackValue;&lt;br /&gt;
    attackValue &amp;lt;= maxAttackValue;&lt;br /&gt;
    attackValue++&lt;br /&gt;
  ) {&lt;br /&gt;
    const weight = weights[attackValue - minAttackValue];&lt;br /&gt;
&lt;br /&gt;
    const secondaryAttackValue = 2 * attackValue + attackValueOther;&lt;br /&gt;
    const rawDamage =&lt;br /&gt;
      mainAttackValue + floorMultiplication(attackFactor, secondaryAttackValue);&lt;br /&gt;
&lt;br /&gt;
    const damageWithPrimaryBonuses = calcDamageWithPrimaryBonuses(&lt;br /&gt;
      rawDamage,&lt;br /&gt;
      bonusValues&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    const damageValues =&lt;br /&gt;
      damageWithPrimaryBonuses &amp;lt;= 2&lt;br /&gt;
        ? [1, 2, 3, 4, 5]&lt;br /&gt;
        : [damageWithPrimaryBonuses];&lt;br /&gt;
&lt;br /&gt;
    for (let variation = minVariation; variation &amp;lt;= maxVariation; variation++) {&lt;br /&gt;
      for (const damage of damageValues) {&lt;br /&gt;
        const damageWithFormula = skillFormula(&lt;br /&gt;
          damage * bonusValues.useDamage,&lt;br /&gt;
          variation&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        let damageKey = damageWithFormula;&lt;br /&gt;
&lt;br /&gt;
        if (damageWithPrimaryBonuses &amp;lt; 0) {&lt;br /&gt;
          damageKey = `${damageWithFormula}_${Math.abs(&lt;br /&gt;
            damageWithPrimaryBonuses&lt;br /&gt;
          )}`;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        const entry = savedDamage[damageKey];&lt;br /&gt;
&lt;br /&gt;
        if (entry) {&lt;br /&gt;
          entry[0] += weight;&lt;br /&gt;
          continue;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        const damageByType = [[], [], [], []];&lt;br /&gt;
        const currentDamageInfo = [weight, damageByType];&lt;br /&gt;
&lt;br /&gt;
        const finalDamage = Math.floor(&lt;br /&gt;
          (damageWithFormula * bonusValues.weaponBonusCoeff) / 100&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        saveFinalSkillDamage(&lt;br /&gt;
          finalDamage,&lt;br /&gt;
          damageWithPrimaryBonuses,&lt;br /&gt;
          bonusValues,&lt;br /&gt;
          criticalAttackRange,&lt;br /&gt;
          damageByType&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        savedDamage[damageKey] = currentDamageInfo;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  processSavedDamage(savedDamage, damageWeightedByType, battleValues);&lt;br /&gt;
&lt;br /&gt;
  return damageWeightedByType;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcMagicSkillDamage(battleValues) {&lt;br /&gt;
  const {&lt;br /&gt;
    attackValues: {&lt;br /&gt;
      minMagicAttackValue,&lt;br /&gt;
      maxMagicAttackValue,&lt;br /&gt;
      magicAttackValueAugmentation,&lt;br /&gt;
      weights,&lt;br /&gt;
      criticalAttackRange,&lt;br /&gt;
    },&lt;br /&gt;
    bonusValues,&lt;br /&gt;
    damageWeightedByType,&lt;br /&gt;
    skillFormula,&lt;br /&gt;
    skillRange: [minVariation, maxVariation],&lt;br /&gt;
  } = battleValues;&lt;br /&gt;
&lt;br /&gt;
  const savedDamage = {};&lt;br /&gt;
&lt;br /&gt;
  for (&lt;br /&gt;
    let magicAttackValue = minMagicAttackValue;&lt;br /&gt;
    magicAttackValue &amp;lt;= maxMagicAttackValue;&lt;br /&gt;
    magicAttackValue++&lt;br /&gt;
  ) {&lt;br /&gt;
    const index = magicAttackValue - minMagicAttackValue;&lt;br /&gt;
    const weight = weights[index];&lt;br /&gt;
&lt;br /&gt;
    for (let variation = minVariation; variation &amp;lt;= maxVariation; variation++) {&lt;br /&gt;
      const rawDamage = skillFormula(&lt;br /&gt;
        magicAttackValue + magicAttackValueAugmentation[index],&lt;br /&gt;
        variation&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      const entry = savedDamage[rawDamage];&lt;br /&gt;
&lt;br /&gt;
      if (entry) {&lt;br /&gt;
        entry[0] += weight;&lt;br /&gt;
        continue;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      const damageByType = [[], [], [], []];&lt;br /&gt;
      const currentDamageInfo = [weight, damageByType];&lt;br /&gt;
&lt;br /&gt;
      let damageWithPrimaryBonuses = Math.floor(&lt;br /&gt;
        (rawDamage * bonusValues.weaponBonusCoeff) / 100&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      damageWithPrimaryBonuses = calcDamageWithPrimaryBonuses(&lt;br /&gt;
        damageWithPrimaryBonuses,&lt;br /&gt;
        bonusValues&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      const damageValues =&lt;br /&gt;
        damageWithPrimaryBonuses &amp;lt;= 2&lt;br /&gt;
          ? [1, 2, 3, 4, 5]&lt;br /&gt;
          : [damageWithPrimaryBonuses];&lt;br /&gt;
&lt;br /&gt;
      for (const damage of damageValues) {&lt;br /&gt;
        saveFinalSkillDamage(&lt;br /&gt;
          damage,&lt;br /&gt;
          damageWithPrimaryBonuses,&lt;br /&gt;
          bonusValues,&lt;br /&gt;
          criticalAttackRange,&lt;br /&gt;
          damageByType&lt;br /&gt;
        );&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      savedDamage[rawDamage] = currentDamageInfo;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  processSavedDamage(savedDamage, damageWeightedByType, battleValues);&lt;br /&gt;
&lt;br /&gt;
  return damageWeightedByType;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcDamage(&lt;br /&gt;
  attacker,&lt;br /&gt;
  victim,&lt;br /&gt;
  attackType,&lt;br /&gt;
  battle,&lt;br /&gt;
  removeSkillVariation&lt;br /&gt;
) {&lt;br /&gt;
  var damageCalculator, skillId, skillType;&lt;br /&gt;
&lt;br /&gt;
  if (attackType === &amp;quot;physical&amp;quot;) {&lt;br /&gt;
    damageCalculator = calcPhysicalDamage;&lt;br /&gt;
  } else if (attackType.startsWith(&amp;quot;attackSkill&amp;quot;)) {&lt;br /&gt;
    skillId = Number(attackType.split(&amp;quot;attackSkill&amp;quot;)[1]);&lt;br /&gt;
&lt;br /&gt;
    if (isMagicClass(attacker) || isDispell(attacker, skillId)) {&lt;br /&gt;
      skillType = &amp;quot;magic&amp;quot;;&lt;br /&gt;
      damageCalculator = calcMagicSkillDamage;&lt;br /&gt;
    } else {&lt;br /&gt;
      skillType = &amp;quot;physical&amp;quot;;&lt;br /&gt;
      damageCalculator = calcPhysicalSkillDamage;&lt;br /&gt;
    }&lt;br /&gt;
  } else if (attackType.startsWith(&amp;quot;horseSkill&amp;quot;)) {&lt;br /&gt;
    skillType = &amp;quot;physical&amp;quot;;&lt;br /&gt;
    skillId = Number(attackType.split(&amp;quot;horseSkill&amp;quot;)[1]);&lt;br /&gt;
    damageCalculator = calcPhysicalSkillDamage;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var battleValues = createBattleValues(attacker, victim, battle, skillType);&lt;br /&gt;
&lt;br /&gt;
  if (skillId) {&lt;br /&gt;
    getSkillFormula(battle, skillId, battleValues, removeSkillVariation);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    damageWeightedByType: damageCalculator(battleValues),&lt;br /&gt;
    attackValues: battleValues.attackValues,&lt;br /&gt;
    skillType: skillType,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function damageWithoutVariation(&lt;br /&gt;
  attacker,&lt;br /&gt;
  victim,&lt;br /&gt;
  attackType,&lt;br /&gt;
  battle,&lt;br /&gt;
  characters&lt;br /&gt;
) {&lt;br /&gt;
  var startDamageTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
  var { damageWeightedByType, attackValues, skillType } = calcDamage(&lt;br /&gt;
    attacker,&lt;br /&gt;
    victim,&lt;br /&gt;
    attackType,&lt;br /&gt;
    battle&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  var endDamageTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
  displayResults(&lt;br /&gt;
    attackValues,&lt;br /&gt;
    damageWeightedByType,&lt;br /&gt;
    battle,&lt;br /&gt;
    attacker.name,&lt;br /&gt;
    victim.name&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  var endDisplayTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
  displayFightInfo(&lt;br /&gt;
    attackValues.possibleDamageCount,&lt;br /&gt;
    endDamageTime - startDamageTime,&lt;br /&gt;
    endDisplayTime - endDamageTime,&lt;br /&gt;
    battle&lt;br /&gt;
  );&lt;br /&gt;
  addPotentialErrorInformation(&lt;br /&gt;
    battle.errorInformation,&lt;br /&gt;
    attacker,&lt;br /&gt;
    victim,&lt;br /&gt;
    skillType,&lt;br /&gt;
    characters&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  hideElement(battle.bonusVariationResultContainer);&lt;br /&gt;
  showElement(battle.fightResultTitle);&lt;br /&gt;
  showElement(battle.fightResultContainer);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function damageWithVariation(&lt;br /&gt;
  attacker,&lt;br /&gt;
  victim,&lt;br /&gt;
  attackType,&lt;br /&gt;
  battle,&lt;br /&gt;
  entity,&lt;br /&gt;
  entityVariation&lt;br /&gt;
) {&lt;br /&gt;
  var startTime = performance.now();&lt;br /&gt;
  var damageByBonus = [];&lt;br /&gt;
  var augmentationByBonus = [];&lt;br /&gt;
  var {&lt;br /&gt;
    bonusVariationMinValue: minVariation,&lt;br /&gt;
    bonusVariationMaxValue: maxVariation,&lt;br /&gt;
  } = entity;&lt;br /&gt;
  var step = Math.ceil((maxVariation - minVariation + 1) / 500);&lt;br /&gt;
  var simulationCount = 0;&lt;br /&gt;
  var simulationTime;&lt;br /&gt;
  var firstDamage = 1;&lt;br /&gt;
&lt;br /&gt;
  for (&lt;br /&gt;
    var bonusValue = minVariation;&lt;br /&gt;
    bonusValue &amp;lt;= maxVariation;&lt;br /&gt;
    bonusValue += step&lt;br /&gt;
  ) {&lt;br /&gt;
    entity[entityVariation] = bonusValue;&lt;br /&gt;
&lt;br /&gt;
    var {&lt;br /&gt;
      damageWeightedByType,&lt;br /&gt;
      attackValues: { totalCardinal },&lt;br /&gt;
    } = calcDamage(&lt;br /&gt;
      copyObject(attacker),&lt;br /&gt;
      copyObject(victim),&lt;br /&gt;
      attackType,&lt;br /&gt;
      battle,&lt;br /&gt;
      true&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    var meanDamage = calcMeanDamage(damageWeightedByType, totalCardinal);&lt;br /&gt;
&lt;br /&gt;
    if (bonusValue === minVariation) {&lt;br /&gt;
      firstDamage = Math.max(meanDamage, 1e-3);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    damageByBonus.push({ x: bonusValue, y: meanDamage });&lt;br /&gt;
    augmentationByBonus.push({&lt;br /&gt;
      x: bonusValue,&lt;br /&gt;
      y: meanDamage / firstDamage - 1,&lt;br /&gt;
    });&lt;br /&gt;
    simulationCount++;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var endTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
  battle.damageByBonus = damageByBonus.concat(entityVariation);&lt;br /&gt;
&lt;br /&gt;
  addToBonusVariationChart(&lt;br /&gt;
    damageByBonus,&lt;br /&gt;
    augmentationByBonus,&lt;br /&gt;
    entity.bonusVariationName,&lt;br /&gt;
    battle.bonusVariationChart&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  simulationCount = battle.numberFormats.default.format(simulationCount);&lt;br /&gt;
  simulationTime = battle.numberFormats.second.format(&lt;br /&gt;
    (endTime - startTime) / 1000&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  battle.simulationCounter.textContent = simulationCount;&lt;br /&gt;
  battle.simulationTime.textContent = simulationTime;&lt;br /&gt;
&lt;br /&gt;
  hideElement(battle.fightResultContainer);&lt;br /&gt;
  showElement(battle.fightResultTitle);&lt;br /&gt;
  showElement(battle.bonusVariationResultContainer);&lt;br /&gt;
&lt;br /&gt;
  if (&lt;br /&gt;
    isChecked(attacker.useBonusVariation) &amp;amp;&amp;amp;&lt;br /&gt;
    isChecked(victim.useBonusVariation)&lt;br /&gt;
  ) {&lt;br /&gt;
    showElement(battle.errorInformation[&amp;quot;attacker-victim-variation&amp;quot;]);&lt;br /&gt;
  } else {&lt;br /&gt;
    hideElement(battle.errorInformation[&amp;quot;attacker-victim-variation&amp;quot;]);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function changeMonsterValues(monster, instance, attacker) {&lt;br /&gt;
  switch (instance) {&lt;br /&gt;
    case &amp;quot;SungMahiTower&amp;quot;:&lt;br /&gt;
      var sungMahiFloor = 1;&lt;br /&gt;
      var sungMahiStep = 1;&lt;br /&gt;
      var rawDefense = 120;&lt;br /&gt;
&lt;br /&gt;
      if (isPC(attacker)) {&lt;br /&gt;
        sungMahiFloor = attacker.sungMahiFloor;&lt;br /&gt;
        sungMahiStep = attacker.sungMahiStep;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (monster.rank === 5) {&lt;br /&gt;
        monster.level = 121;&lt;br /&gt;
        monster.dex = 75;&lt;br /&gt;
        rawDefense += 1;&lt;br /&gt;
      } else if (monster.rank === 6) {&lt;br /&gt;
        monster.level = 123;&lt;br /&gt;
        monster.dex = 75;&lt;br /&gt;
        rawDefense += 1;&lt;br /&gt;
      } else {&lt;br /&gt;
        monster.level = 120;&lt;br /&gt;
        monster.dex = 68;&lt;br /&gt;
      }&lt;br /&gt;
      monster.vit = 100;&lt;br /&gt;
      monster.rawDefense = rawDefense + (sungMahiStep - 1) * 6;&lt;br /&gt;
      monster.fistDefense = 0;&lt;br /&gt;
      monster.swordDefense = 0;&lt;br /&gt;
      monster.twoHandedSwordDefense = 0;&lt;br /&gt;
      monster.daggerDefense = 0;&lt;br /&gt;
      monster.bellDefense = 0;&lt;br /&gt;
      monster.fanDefense = 0;&lt;br /&gt;
      monster.arrowDefense = 0;&lt;br /&gt;
      monster.clawDefense = 0;&lt;br /&gt;
      monster.magicResistance = 0;&lt;br /&gt;
      monster.fireResistance = -20;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  // Alastor&lt;br /&gt;
  if (monster.vnum === 6790) {&lt;br /&gt;
    monster.iceResistance = 0;&lt;br /&gt;
    monster.iceBonus = 0;&lt;br /&gt;
    monster.lightningResistance = -10;&lt;br /&gt;
    monster.lightningBonus = 65;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createWeapon(vnum) {&lt;br /&gt;
  var weapon = copyObject(weaponData[vnum]);&lt;br /&gt;
  var serpentVnums = [360, 380, 1210, 2230, 3250, 5200, 6150, 7330];&lt;br /&gt;
  var weaponValues = weapon[1];&lt;br /&gt;
  var isSerpent = isValueInArray(Number(vnum), serpentVnums);&lt;br /&gt;
  var isSpecial = Array.isArray(weaponValues[0]);&lt;br /&gt;
  var isMagic;&lt;br /&gt;
&lt;br /&gt;
  if (isSpecial) {&lt;br /&gt;
    isMagic = weaponValues[0][1] &amp;gt; 0;&lt;br /&gt;
  } else {&lt;br /&gt;
    isMagic = weaponValues[1] &amp;gt; 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    type: weapon[0],&lt;br /&gt;
    maxUpgrade: weapon[2].length - 1,&lt;br /&gt;
    isSerpent: isSerpent,&lt;br /&gt;
    isMagic: isMagic,&lt;br /&gt;
    getValues: function (upgrade) {&lt;br /&gt;
      var currentWeaponValues = weaponValues;&lt;br /&gt;
&lt;br /&gt;
      if (upgrade === undefined) {&lt;br /&gt;
        // rare bug when weaponUpgrade is deleted&lt;br /&gt;
        console.warn(&amp;quot;WeaponUpgrade is missing.&amp;quot;);&lt;br /&gt;
        upgrade = this.maxUpgrade;&lt;br /&gt;
      }&lt;br /&gt;
      upgrade = Math.min(upgrade, this.maxUpgrade);&lt;br /&gt;
&lt;br /&gt;
      if (isSpecial) {&lt;br /&gt;
        currentWeaponValues = weaponValues[upgrade];&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      this.minAttackValue = currentWeaponValues[2];&lt;br /&gt;
      this.maxAttackValue = currentWeaponValues[3];&lt;br /&gt;
      this.minMagicAttackValue = currentWeaponValues[0];&lt;br /&gt;
      this.maxMagicAttackValue = currentWeaponValues[1];&lt;br /&gt;
      this.growth = weapon[2][upgrade];&lt;br /&gt;
    },&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createMonster(monsterVnum, attacker, polymorphMonster) {&lt;br /&gt;
  var monsterAttributes = monsterData[monsterVnum];&lt;br /&gt;
&lt;br /&gt;
  var monster = {&lt;br /&gt;
    vnum: Number(monsterVnum),&lt;br /&gt;
    name: monsterAttributes[36],&lt;br /&gt;
    rank: monsterAttributes[0],&lt;br /&gt;
    race: monsterAttributes[1],&lt;br /&gt;
    attack: monsterAttributes[2],&lt;br /&gt;
    level: monsterAttributes[3],&lt;br /&gt;
    type: monsterAttributes[4],&lt;br /&gt;
    str: monsterAttributes[5],&lt;br /&gt;
    dex: monsterAttributes[6],&lt;br /&gt;
    vit: monsterAttributes[7],&lt;br /&gt;
    int: monsterAttributes[8],&lt;br /&gt;
    minAttackValue: monsterAttributes[9],&lt;br /&gt;
    maxAttackValue: monsterAttributes[10],&lt;br /&gt;
    rawDefense: monsterAttributes[11],&lt;br /&gt;
    criticalHit: monsterAttributes[12],&lt;br /&gt;
    piercingHit: monsterAttributes[13],&lt;br /&gt;
    fistDefense: monsterAttributes[14],&lt;br /&gt;
    swordDefense: monsterAttributes[15],&lt;br /&gt;
    twoHandedSwordDefense: monsterAttributes[16],&lt;br /&gt;
    daggerDefense: monsterAttributes[17],&lt;br /&gt;
    bellDefense: monsterAttributes[18],&lt;br /&gt;
    fanDefense: monsterAttributes[19],&lt;br /&gt;
    arrowDefense: monsterAttributes[20],&lt;br /&gt;
    clawDefense: monsterAttributes[21],&lt;br /&gt;
    fireResistance: monsterAttributes[22],&lt;br /&gt;
    lightningResistance: monsterAttributes[23],&lt;br /&gt;
    magicResistance: monsterAttributes[24],&lt;br /&gt;
    windResistance: monsterAttributes[25],&lt;br /&gt;
    lightningBonus: monsterAttributes[26],&lt;br /&gt;
    fireBonus: monsterAttributes[27],&lt;br /&gt;
    iceBonus: monsterAttributes[28],&lt;br /&gt;
    windBonus: monsterAttributes[29],&lt;br /&gt;
    earthBonus: monsterAttributes[30],&lt;br /&gt;
    darknessBonus: monsterAttributes[31],&lt;br /&gt;
    darknessResistance: monsterAttributes[32],&lt;br /&gt;
    iceResistance: monsterAttributes[33],&lt;br /&gt;
    earthResistance: monsterAttributes[34],&lt;br /&gt;
    damageMultiplier: monsterAttributes[35],&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  // monster.instance = 0;&lt;br /&gt;
&lt;br /&gt;
  // if (attacker &amp;amp;&amp;amp; monster.instance === 0) {&lt;br /&gt;
  //   changeMonsterValues(monster, &amp;quot;SungMahiTower&amp;quot;, attacker);&lt;br /&gt;
  // }&lt;br /&gt;
  if (!polymorphMonster) {&lt;br /&gt;
    changeMonsterValues(monster);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  monster.defense = monster.rawDefense + monster.level + monster.vit;&lt;br /&gt;
&lt;br /&gt;
  return monster;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addPotentialErrorInformation(&lt;br /&gt;
  errorInformation,&lt;br /&gt;
  attacker,&lt;br /&gt;
  victim,&lt;br /&gt;
  skillType,&lt;br /&gt;
  characters&lt;br /&gt;
) {&lt;br /&gt;
  for (var error of Object.values(errorInformation)) {&lt;br /&gt;
    hideElement(error);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker)) {&lt;br /&gt;
    if (isRiding(attacker)) {&lt;br /&gt;
      if (attacker.horsePoint === 0) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;horse-level&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
      showElement(errorInformation[&amp;quot;horse-stat&amp;quot;]);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isPolymorph(attacker)) {&lt;br /&gt;
      if (attacker.polymorphPoint === 0) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;polymorph-level&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (&lt;br /&gt;
        (attacker.polymorphPoint &amp;lt;= 39 &amp;amp;&amp;amp; attacker.attackValuePercent &amp;lt;= 199) ||&lt;br /&gt;
        (attacker.polymorphPoint === 40 &amp;amp;&amp;amp; attacker.attackValuePercent &amp;lt;= 299)&lt;br /&gt;
      ) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;polymorph-bonus&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
    if (skillType === &amp;quot;magic&amp;quot;) {&lt;br /&gt;
      if (attacker.magicAttackValue) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;magic-attack-value-bonus&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
      if (victim.magicResistance) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;magic-resistance&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    showElement(errorInformation[&amp;quot;monster-attacker&amp;quot;]);&lt;br /&gt;
    if (isMagicAttacker(attacker) &amp;amp;&amp;amp; victim.magicResistance) {&lt;br /&gt;
      showElement(errorInformation[&amp;quot;magic-resistance&amp;quot;]);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (isPC(victim)) {&lt;br /&gt;
    if (isRiding(victim)) {&lt;br /&gt;
      showElement(errorInformation[&amp;quot;horse-stat&amp;quot;]);&lt;br /&gt;
    }&lt;br /&gt;
    if (isPolymorph(victim)) {&lt;br /&gt;
      if (attacker.polymorphPoint === 0) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;polymorph-level&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
      showElement(errorInformation[&amp;quot;polymorph-defense&amp;quot;]);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (characters.unsavedChanges) {&lt;br /&gt;
    showElement(errorInformation[&amp;quot;save&amp;quot;]);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function reduceChartPointsListener(battle) {&lt;br /&gt;
  var {&lt;br /&gt;
    reduceChartPointsContainer,&lt;br /&gt;
    reduceChartPoints,&lt;br /&gt;
    numberFormats: { second: numberFormat },&lt;br /&gt;
    displayTime,&lt;br /&gt;
  } = battle;&lt;br /&gt;
&lt;br /&gt;
  reduceChartPoints.addEventListener(&amp;quot;change&amp;quot;, function () {&lt;br /&gt;
    reduceChartPoints.disabled = true;&lt;br /&gt;
&lt;br /&gt;
    var startDisplayTime = performance.now();&lt;br /&gt;
    var scatterDataByType = battle.scatterDataByType;&lt;br /&gt;
    var {&lt;br /&gt;
      chart,&lt;br /&gt;
      maxPoints,&lt;br /&gt;
      chart: {&lt;br /&gt;
        data: { datasets },&lt;br /&gt;
      },&lt;br /&gt;
    } = battle.damageChart;&lt;br /&gt;
    var addAnimations = false;&lt;br /&gt;
&lt;br /&gt;
    for (var index = 0; index &amp;lt; datasets.length; index++) {&lt;br /&gt;
      var dataset = datasets[index];&lt;br /&gt;
      var scatterData = scatterDataByType[dataset.name];&lt;br /&gt;
&lt;br /&gt;
      if (dataset.canBeReduced &amp;amp;&amp;amp; reduceChartPoints.checked) {&lt;br /&gt;
        dataset.data = aggregateDamage(scatterData, maxPoints);&lt;br /&gt;
        addAnimations = true;&lt;br /&gt;
      } else {&lt;br /&gt;
        dataset.data = scatterData;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    handleChartAnimations(chart, addAnimations);&lt;br /&gt;
    chart.update();&lt;br /&gt;
&lt;br /&gt;
    displayTime.textContent = numberFormat.format(&lt;br /&gt;
      (performance.now() - startDisplayTime) / 1000&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    setTimeout(function () {&lt;br /&gt;
      reduceChartPoints.disabled = false;&lt;br /&gt;
    }, 1000);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  reduceChartPointsContainer.addEventListener(&amp;quot;pointerup&amp;quot;, function (event) {&lt;br /&gt;
    if (event.pointerType === &amp;quot;mouse&amp;quot;) {&lt;br /&gt;
      if (event.target.closest(&amp;quot;label&amp;quot;)) {&lt;br /&gt;
        return;&lt;br /&gt;
      }&lt;br /&gt;
      reduceChartPoints.click();&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function downloadRawDataListener(battle) {&lt;br /&gt;
  var { downLoadRawData, downLoadRawDataVariation } = battle;&lt;br /&gt;
  var fileType = &amp;quot;text/csv;charset=utf-8;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  downLoadRawData.addEventListener(&amp;quot;click&amp;quot;, function () {&lt;br /&gt;
    var damageWeightedByType = battle.damageWeightedByType;&lt;br /&gt;
    var filename = &amp;quot;raw_damage.csv&amp;quot;;&lt;br /&gt;
    var csvContent = &amp;quot;damage,probabilities,damageType\n&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    for (var damageType in damageWeightedByType) {&lt;br /&gt;
      var damageWeighted = damageWeightedByType[damageType];&lt;br /&gt;
&lt;br /&gt;
      for (var damage in damageWeighted) {&lt;br /&gt;
        csvContent +=&lt;br /&gt;
          damage + &amp;quot;,&amp;quot; + damageWeighted[damage] + &amp;quot;,&amp;quot; + damageType + &amp;quot;\n&amp;quot;;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    downloadData(csvContent, fileType, filename);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  downLoadRawDataVariation.addEventListener(&amp;quot;click&amp;quot;, function () {&lt;br /&gt;
    var damageByBonus = battle.damageByBonus;&lt;br /&gt;
    var damageByBonusLength = damageByBonus.length;&lt;br /&gt;
    var filename = &amp;quot;damage_variation.csv&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    if (!damageByBonusLength) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var csvContent =&lt;br /&gt;
      damageByBonus[damageByBonusLength - 1] + &amp;quot;,averageDamage\n&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    for (var index = 0; index &amp;lt; damageByBonusLength - 1; index++) {&lt;br /&gt;
      var row = damageByBonus[index];&lt;br /&gt;
&lt;br /&gt;
      csvContent += row.x + &amp;quot;,&amp;quot; + row.y + &amp;quot;\n&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    downloadData(csvContent, fileType, filename);&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function displayResults(&lt;br /&gt;
  attackValues,&lt;br /&gt;
  damageWeightedByType,&lt;br /&gt;
  battle,&lt;br /&gt;
  attackerName,&lt;br /&gt;
  victimName&lt;br /&gt;
) {&lt;br /&gt;
  var [meanDamage, minDamage, maxDamage, scatterDataByType, uniqueDamageCount] =&lt;br /&gt;
    prepareDamageData(damageWeightedByType, attackValues);&lt;br /&gt;
&lt;br /&gt;
  addToDamageChart(&lt;br /&gt;
    scatterDataByType,&lt;br /&gt;
    battle.damageChart,&lt;br /&gt;
    battle.reduceChartPoints.checked&lt;br /&gt;
  );&lt;br /&gt;
  updateDamageChartDescription(&lt;br /&gt;
    battle.uniqueDamageCounters,&lt;br /&gt;
    uniqueDamageCount,&lt;br /&gt;
    battle.numberFormats.default&lt;br /&gt;
  );&lt;br /&gt;
  displayFightResults(&lt;br /&gt;
    battle,&lt;br /&gt;
    attackerName,&lt;br /&gt;
    victimName,&lt;br /&gt;
    meanDamage,&lt;br /&gt;
    minDamage,&lt;br /&gt;
    maxDamage&lt;br /&gt;
  );&lt;br /&gt;
  battle.damageWeightedByType = damageWeightedByType;&lt;br /&gt;
  battle.scatterDataByType = scatterDataByType;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function displayFightResults(&lt;br /&gt;
  battle,&lt;br /&gt;
  attackerName,&lt;br /&gt;
  victimName,&lt;br /&gt;
  meanDamage,&lt;br /&gt;
  minDamage,&lt;br /&gt;
  maxDamage&lt;br /&gt;
) {&lt;br /&gt;
  var {&lt;br /&gt;
    tableResultFight,&lt;br /&gt;
    tableResultHistory,&lt;br /&gt;
    savedFights,&lt;br /&gt;
    numberFormats: { default: numberFormat },&lt;br /&gt;
    deleteFightTemplate,&lt;br /&gt;
  } = battle;&lt;br /&gt;
&lt;br /&gt;
  hideElement(tableResultHistory.rows[1]);&lt;br /&gt;
&lt;br /&gt;
  var valuesToDisplay = [&lt;br /&gt;
    attackerName,&lt;br /&gt;
    victimName,&lt;br /&gt;
    battle.battleChoice.attackType.selectedText,&lt;br /&gt;
    meanDamage,&lt;br /&gt;
    minDamage,&lt;br /&gt;
    maxDamage,&lt;br /&gt;
  ];&lt;br /&gt;
&lt;br /&gt;
  savedFights.push(valuesToDisplay);&lt;br /&gt;
  updateSavedFights(savedFights);&lt;br /&gt;
&lt;br /&gt;
  editTableResultRow(tableResultFight.rows[1], valuesToDisplay, numberFormat);&lt;br /&gt;
  addRowToTableResultHistory(&lt;br /&gt;
    tableResultHistory,&lt;br /&gt;
    valuesToDisplay,&lt;br /&gt;
    deleteFightTemplate,&lt;br /&gt;
    numberFormat&lt;br /&gt;
  );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function displayFightInfo(&lt;br /&gt;
  possibleDamageCount,&lt;br /&gt;
  damageTimeDuration,&lt;br /&gt;
  displayTimeDuration,&lt;br /&gt;
  battle&lt;br /&gt;
) {&lt;br /&gt;
  var container = battle.possibleDamageCounter.parentElement;&lt;br /&gt;
&lt;br /&gt;
  if (possibleDamageCount &amp;lt;= 1) {&lt;br /&gt;
    hideElement(container);&lt;br /&gt;
    return;&lt;br /&gt;
  } else {&lt;br /&gt;
    showElement(container);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var { numberFormats, possibleDamageCounter, damageTime, displayTime } =&lt;br /&gt;
    battle;&lt;br /&gt;
&lt;br /&gt;
  possibleDamageCount = numberFormats.default.format(possibleDamageCount);&lt;br /&gt;
  damageTimeDuration = numberFormats.second.format(damageTimeDuration / 1000);&lt;br /&gt;
  displayTimeDuration = numberFormats.second.format(displayTimeDuration / 1000);&lt;br /&gt;
&lt;br /&gt;
  possibleDamageCounter.textContent = possibleDamageCount;&lt;br /&gt;
  damageTime.textContent = damageTimeDuration;&lt;br /&gt;
  displayTime.textContent = displayTimeDuration;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function parseTypeAndName(data) {&lt;br /&gt;
  var [type, nameOrVnum] = splitFirst(data, &amp;quot;-&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    type: type,&lt;br /&gt;
    nameOrVnum: nameOrVnum,&lt;br /&gt;
    isCharacter: type === &amp;quot;character&amp;quot;,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isCharacterSelected(characterName, selected) {&lt;br /&gt;
  if (!selected) {&lt;br /&gt;
    return false;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var { nameOrVnum, isCharacter } = parseTypeAndName(selected);&lt;br /&gt;
&lt;br /&gt;
  return nameOrVnum === characterName &amp;amp;&amp;amp; isCharacter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function useBonusVariationMode(character, variation) {&lt;br /&gt;
  return (&lt;br /&gt;
    isChecked(character.useBonusVariation) &amp;amp;&amp;amp;&lt;br /&gt;
    character.hasOwnProperty(variation) &amp;amp;&amp;amp;&lt;br /&gt;
    character.bonusVariationMinValue &amp;lt; character.bonusVariationMaxValue&lt;br /&gt;
  );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createBattle(characters, battle) {&lt;br /&gt;
  var battleChoice = battle.battleChoice;&lt;br /&gt;
  var battleForm = battleChoice.form;&lt;br /&gt;
  var lastInvalidTime = 0;&lt;br /&gt;
&lt;br /&gt;
  battleForm.addEventListener(&amp;quot;change&amp;quot;, handleBattleFormChange);&lt;br /&gt;
  battleForm.addEventListener(&amp;quot;invalid&amp;quot;, handleBattleFormInvalid, true);&lt;br /&gt;
  battleForm.addEventListener(&amp;quot;submit&amp;quot;, handleBattleFormSubmit);&lt;br /&gt;
&lt;br /&gt;
  function handleBattleFormChange(event) {&lt;br /&gt;
    var target = event.target;&lt;br /&gt;
    var { name: targetName, value: targetValue, type: targetType } = target;&lt;br /&gt;
&lt;br /&gt;
    if (targetType !== &amp;quot;radio&amp;quot;) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (targetName === &amp;quot;attackType&amp;quot;) {&lt;br /&gt;
      battleChoice.attackType.selectedText =&lt;br /&gt;
        target.previousElementSibling.dataset.o;&lt;br /&gt;
    } else {&lt;br /&gt;
      updateBattleChoiceButton(battleChoice, targetName, targetValue);&lt;br /&gt;
&lt;br /&gt;
      if (targetName === &amp;quot;attacker&amp;quot;) {&lt;br /&gt;
        filterAttackTypeSelection(characters, battleChoice, targetValue);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function handleBattleFormInvalid(event) {&lt;br /&gt;
    var currentTime = Date.now();&lt;br /&gt;
&lt;br /&gt;
    if (currentTime - lastInvalidTime &amp;lt; 100) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    lastInvalidTime = currentTime;&lt;br /&gt;
&lt;br /&gt;
    var target = event.target;&lt;br /&gt;
    var modal = target.closest(&amp;quot;.modal&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (!modal) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var dataModal = modal.dataset.modal;&lt;br /&gt;
&lt;br /&gt;
    if (!dataModal) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var category = dataModal.split(&amp;quot;-&amp;quot;)[0];&lt;br /&gt;
&lt;br /&gt;
    if (isValueInArray(category, battleChoice.categories)) {&lt;br /&gt;
      battleChoice[category].button.click();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function handleBattleFormSubmit(event) {&lt;br /&gt;
    event.preventDefault();&lt;br /&gt;
&lt;br /&gt;
    // auto save&lt;br /&gt;
    if (characters.unsavedChanges) {&lt;br /&gt;
      characters.saveButton.click();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var battleInfo = new FormData(event.target);&lt;br /&gt;
    var attackerData = battleInfo.get(&amp;quot;attacker&amp;quot;);&lt;br /&gt;
    var attackType = battleInfo.get(&amp;quot;attackType&amp;quot;);&lt;br /&gt;
    var victimData = battleInfo.get(&amp;quot;victim&amp;quot;);&lt;br /&gt;
    var attackerVariation;&lt;br /&gt;
    var victimVariation;&lt;br /&gt;
&lt;br /&gt;
    if (!attackerData &amp;amp;&amp;amp; !attackType &amp;amp;&amp;amp; !victimData) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var { nameOrVnum: attackerNameOrVnum, isCharacter: attackerIsPlayer } =&lt;br /&gt;
      parseTypeAndName(attackerData);&lt;br /&gt;
    var { nameOrVnum: victimNameOrVnum, isCharacter: victimIsPlayer } =&lt;br /&gt;
      parseTypeAndName(victimData);&lt;br /&gt;
&lt;br /&gt;
    if (attackerIsPlayer) {&lt;br /&gt;
      var attacker = copyObject(characters.savedCharacters[attackerNameOrVnum]);&lt;br /&gt;
      attackerVariation = attacker.bonusVariation;&lt;br /&gt;
    } else {&lt;br /&gt;
      var attacker = createMonster(attackerNameOrVnum);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (victimIsPlayer) {&lt;br /&gt;
      var victim = copyObject(characters.savedCharacters[victimNameOrVnum]);&lt;br /&gt;
      victimVariation = victim.bonusVariation;&lt;br /&gt;
    } else {&lt;br /&gt;
      var victim = createMonster(victimNameOrVnum, attacker);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (useBonusVariationMode(attacker, attackerVariation)) {&lt;br /&gt;
      damageWithVariation(&lt;br /&gt;
        attacker,&lt;br /&gt;
        victim,&lt;br /&gt;
        attackType,&lt;br /&gt;
        battle,&lt;br /&gt;
        attacker,&lt;br /&gt;
        attackerVariation&lt;br /&gt;
      );&lt;br /&gt;
    } else if (useBonusVariationMode(victim, victimVariation)) {&lt;br /&gt;
      damageWithVariation(&lt;br /&gt;
        attacker,&lt;br /&gt;
        victim,&lt;br /&gt;
        attackType,&lt;br /&gt;
        battle,&lt;br /&gt;
        victim,&lt;br /&gt;
        victimVariation&lt;br /&gt;
      );&lt;br /&gt;
    } else {&lt;br /&gt;
      damageWithoutVariation(attacker, victim, attackType, battle, characters);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createMapping() {&lt;br /&gt;
  return {&lt;br /&gt;
    typeFlag: [&lt;br /&gt;
      &amp;quot;animalBonus&amp;quot;, // 0&lt;br /&gt;
      &amp;quot;humanBonus&amp;quot;, // 1&lt;br /&gt;
      &amp;quot;orcBonus&amp;quot;, // 2&lt;br /&gt;
      &amp;quot;mysticBonus&amp;quot;, // 3&lt;br /&gt;
      &amp;quot;undeadBonus&amp;quot;, // 4&lt;br /&gt;
      &amp;quot;insectBonus&amp;quot;, // 5&lt;br /&gt;
      &amp;quot;desertBonus&amp;quot;, // 6&lt;br /&gt;
      &amp;quot;devilBonus&amp;quot;, // 7&lt;br /&gt;
    ],&lt;br /&gt;
    raceBonus: {&lt;br /&gt;
      warrior: &amp;quot;warriorBonus&amp;quot;,&lt;br /&gt;
      sura: &amp;quot;suraBonus&amp;quot;,&lt;br /&gt;
      ninja: &amp;quot;ninjaBonus&amp;quot;,&lt;br /&gt;
      shaman: &amp;quot;shamanBonus&amp;quot;,&lt;br /&gt;
      lycan: &amp;quot;lycanBonus&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    raceResistance: {&lt;br /&gt;
      warrior: &amp;quot;warriorResistance&amp;quot;,&lt;br /&gt;
      sura: &amp;quot;suraResistance&amp;quot;,&lt;br /&gt;
      ninja: &amp;quot;ninjaResistance&amp;quot;,&lt;br /&gt;
      shaman: &amp;quot;shamanResistance&amp;quot;,&lt;br /&gt;
      lycan: &amp;quot;lycanResistance&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    defenseWeapon: [&lt;br /&gt;
      &amp;quot;swordDefense&amp;quot;, // 0&lt;br /&gt;
      &amp;quot;daggerDefense&amp;quot;, // 1&lt;br /&gt;
      &amp;quot;arrowDefense&amp;quot;, // 2&lt;br /&gt;
      &amp;quot;twoHandedSwordDefense&amp;quot;, // 3&lt;br /&gt;
      &amp;quot;bellDefense&amp;quot;, // 4&lt;br /&gt;
      &amp;quot;clawDefense&amp;quot;, // 5&lt;br /&gt;
      &amp;quot;fanDefense&amp;quot;, // 6&lt;br /&gt;
      &amp;quot;swordDefense&amp;quot;, // 7&lt;br /&gt;
      &amp;quot;fistDefense&amp;quot;, // 8&lt;br /&gt;
    ],&lt;br /&gt;
    breakWeapon: [&lt;br /&gt;
      &amp;quot;breakSwordDefense&amp;quot;, // 0&lt;br /&gt;
      &amp;quot;breakDaggerDefense&amp;quot;, // 1&lt;br /&gt;
      &amp;quot;breakArrowDefense&amp;quot;, // 2&lt;br /&gt;
      &amp;quot;breakTwoHandedSwordDefense&amp;quot;, // 3&lt;br /&gt;
      &amp;quot;breakBellDefense&amp;quot;, // 4&lt;br /&gt;
      &amp;quot;breakClawDefense&amp;quot;, // 5&lt;br /&gt;
      &amp;quot;breakFanDefense&amp;quot;, // 6&lt;br /&gt;
      &amp;quot;breakSwordDefense&amp;quot;, // 7&lt;br /&gt;
    ],&lt;br /&gt;
    elementBonus: [&lt;br /&gt;
      &amp;quot;fireBonus&amp;quot;, // 0&lt;br /&gt;
      &amp;quot;iceBonus&amp;quot;, // 1&lt;br /&gt;
      &amp;quot;windBonus&amp;quot;, // 2&lt;br /&gt;
      &amp;quot;lightningBonus&amp;quot;, // 3&lt;br /&gt;
      &amp;quot;earthBonus&amp;quot;, // 4&lt;br /&gt;
      &amp;quot;darknessBonus&amp;quot;, // 5&lt;br /&gt;
    ],&lt;br /&gt;
    elementResistance: [&lt;br /&gt;
      &amp;quot;fireResistance&amp;quot;, // 0&lt;br /&gt;
      &amp;quot;iceResistance&amp;quot;, // 1&lt;br /&gt;
      &amp;quot;windResistance&amp;quot;, // 2&lt;br /&gt;
      &amp;quot;lightningResistance&amp;quot;, // 3&lt;br /&gt;
      &amp;quot;earthResistance&amp;quot;, // 4&lt;br /&gt;
      &amp;quot;darknessResistance&amp;quot;, // 5&lt;br /&gt;
    ],&lt;br /&gt;
    attackType: [&lt;br /&gt;
      &amp;quot;normalHit&amp;quot;,&lt;br /&gt;
      &amp;quot;criticalHit&amp;quot;,&lt;br /&gt;
      &amp;quot;piercingHit&amp;quot;,&lt;br /&gt;
      &amp;quot;criticalPiercingHit&amp;quot;,&lt;br /&gt;
    ],&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createConstants() {&lt;br /&gt;
  var constants = {&lt;br /&gt;
    polymorphPowerTable: [&lt;br /&gt;
      10, 11, 11, 12, 13, 13, 14, 15, 16, 17, 18, 19, 20, 22, 23, 24, 26, 27,&lt;br /&gt;
      29, 31, 33, 35, 37, 39, 41, 44, 46, 49, 52, 55, 59, 62, 66, 70, 74, 79,&lt;br /&gt;
      84, 89, 94, 100, 0,&lt;br /&gt;
    ],&lt;br /&gt;
    skillPowerTable: [&lt;br /&gt;
      0, 0.05, 0.06, 0.08, 0.1, 0.12, 0.14, 0.16, 0.18, 0.2, 0.22, 0.24, 0.26,&lt;br /&gt;
      0.28, 0.3, 0.32, 0.34, 0.36, 0.38, 0.4, 0.5, 0.52, 0.54, 0.56, 0.58, 0.6,&lt;br /&gt;
      0.63, 0.66, 0.69, 0.72, 0.82, 0.85, 0.88, 0.91, 0.94, 0.98, 1.02, 1.06,&lt;br /&gt;
      1.1, 1.15, 1.25,&lt;br /&gt;
    ],&lt;br /&gt;
    marriageTable: {&lt;br /&gt;
      harmonyEarrings: [4, 5, 6, 8],&lt;br /&gt;
      loveEarrings: [4, 5, 6, 8],&lt;br /&gt;
      harmonyBracelet: [4, 5, 6, 8],&lt;br /&gt;
      loveNecklace: [20, 25, 30, 40],&lt;br /&gt;
      harmonyNecklace: [12, 16, 20, 30],&lt;br /&gt;
    },&lt;br /&gt;
    allowedWeaponsPerRace: {&lt;br /&gt;
      warrior: [0, 3, 8],&lt;br /&gt;
      ninja: [0, 1, 2, 8],&lt;br /&gt;
      sura: [0, 7, 8],&lt;br /&gt;
      shaman: [4, 6, 8],&lt;br /&gt;
      lycan: [5, 8],&lt;br /&gt;
    },&lt;br /&gt;
    translation: {&lt;br /&gt;
      fr: {&lt;br /&gt;
        damage: &amp;quot;Dégâts&amp;quot;,&lt;br /&gt;
        percentage: &amp;quot;Pourcentage&amp;quot;,&lt;br /&gt;
        miss: &amp;quot;Miss&amp;quot;,&lt;br /&gt;
        normalHit: &amp;quot;Coup classique&amp;quot;,&lt;br /&gt;
        criticalHit: &amp;quot;Coup critique&amp;quot;,&lt;br /&gt;
        piercingHit: &amp;quot;Coup perçant&amp;quot;,&lt;br /&gt;
        criticalPiercingHit: &amp;quot;Coup critique perçant&amp;quot;,&lt;br /&gt;
        damageRepartition: &amp;quot;Distribution des dégâts&amp;quot;,&lt;br /&gt;
        averageDamage: &amp;quot;Dégâts moyens&amp;quot;,&lt;br /&gt;
        damageAugmentation: &amp;quot;Augmentation des dégâts&amp;quot;,&lt;br /&gt;
        bonusVariationTitle: [&lt;br /&gt;
          &amp;quot;Évolution des dégâts moyens&amp;quot;,&lt;br /&gt;
          &amp;quot;par rapport à la valeur d'un bonus&amp;quot;,&lt;br /&gt;
        ],&lt;br /&gt;
      },&lt;br /&gt;
      en: {&lt;br /&gt;
        damage: &amp;quot;Damage&amp;quot;,&lt;br /&gt;
        percentage: &amp;quot;Percentage&amp;quot;,&lt;br /&gt;
        miss: &amp;quot;Miss&amp;quot;,&lt;br /&gt;
        normalHit: &amp;quot;Normal Hit&amp;quot;,&lt;br /&gt;
        criticalHit: &amp;quot;Critical Hit&amp;quot;,&lt;br /&gt;
        piercingHit: &amp;quot;Piercing Hit&amp;quot;,&lt;br /&gt;
        criticalPiercingHit: &amp;quot;Critical Piercing Hit&amp;quot;,&lt;br /&gt;
        damageRepartition: &amp;quot;Damage Repartition&amp;quot;,&lt;br /&gt;
        averageDamage: &amp;quot;Average Damage&amp;quot;,&lt;br /&gt;
        damageAugmentation: &amp;quot;Damage Augmentation&amp;quot;,&lt;br /&gt;
        bonusVariationTitle: [&lt;br /&gt;
          &amp;quot;Evolution of Average Damage&amp;quot;,&lt;br /&gt;
          &amp;quot;Relative to a Bonus Value&amp;quot;,&lt;br /&gt;
        ],&lt;br /&gt;
      },&lt;br /&gt;
      tr: {&lt;br /&gt;
        damage: &amp;quot;Hasar&amp;quot;,&lt;br /&gt;
        percentage: &amp;quot;Yüzde&amp;quot;,&lt;br /&gt;
        miss: &amp;quot;Miss Vuruş&amp;quot;,&lt;br /&gt;
        normalHit: &amp;quot;Düz Vuruş&amp;quot;,&lt;br /&gt;
        criticalHit: &amp;quot;Kritik Vuruş&amp;quot;,&lt;br /&gt;
        piercingHit: &amp;quot;Delici Vuruş&amp;quot;,&lt;br /&gt;
        criticalPiercingHit: &amp;quot;Kritikli Delici Vuruş&amp;quot;,&lt;br /&gt;
        damageRepartition: &amp;quot;Hasar Dağılımı&amp;quot;,&lt;br /&gt;
        averageDamage: &amp;quot;Ortalama Hasar&amp;quot;,&lt;br /&gt;
        damageAugmentation: &amp;quot;Ortalama Hasar Artışı&amp;quot;,&lt;br /&gt;
        bonusVariationTitle: [&lt;br /&gt;
          &amp;quot;Bir bonusun değerine kıyasla&amp;quot;,&lt;br /&gt;
          &amp;quot;Ortalama Hasar Çizelgesi&amp;quot;,&lt;br /&gt;
        ],&lt;br /&gt;
      },&lt;br /&gt;
      ro: {&lt;br /&gt;
        damage: &amp;quot;Daune&amp;quot;,&lt;br /&gt;
        percentage: &amp;quot;Procent&amp;quot;,&lt;br /&gt;
        miss: &amp;quot;Miss&amp;quot;,&lt;br /&gt;
        normalHit: &amp;quot;Lovitura normala&amp;quot;,&lt;br /&gt;
        criticalHit: &amp;quot;Lovitura critica&amp;quot;,&lt;br /&gt;
        piercingHit: &amp;quot;Lovitura patrunzatoare&amp;quot;,&lt;br /&gt;
        criticalPiercingHit: &amp;quot;Lovitura critica si patrunzatoare&amp;quot;,&lt;br /&gt;
        damageRepartition: &amp;quot;Distribuția daunelor&amp;quot;,&lt;br /&gt;
        averageDamage: &amp;quot;Media damageului&amp;quot;,&lt;br /&gt;
        damageAugmentation: &amp;quot;Damage imbunatatit&amp;quot;,&lt;br /&gt;
        bonusVariationTitle: [&lt;br /&gt;
          &amp;quot;Evolutia mediei damageului&amp;quot;,&lt;br /&gt;
          &amp;quot;relativ la o valoare bonus&amp;quot;,&lt;br /&gt;
        ],&lt;br /&gt;
      },&lt;br /&gt;
      de: {&lt;br /&gt;
        damage: &amp;quot;Schäden&amp;quot;,&lt;br /&gt;
        percentage: &amp;quot;Prozentsatz&amp;quot;,&lt;br /&gt;
        miss: &amp;quot;Verfehlen&amp;quot;,&lt;br /&gt;
        normalHit: &amp;quot;Normaler Treffer&amp;quot;,&lt;br /&gt;
        criticalHit: &amp;quot;Kritischer Treffer&amp;quot;,&lt;br /&gt;
        piercingHit: &amp;quot;Durchdringender Treffer&amp;quot;,&lt;br /&gt;
        criticalPiercingHit: &amp;quot;Kritischer durchdringender Treffer&amp;quot;,&lt;br /&gt;
        damageRepartition: &amp;quot;Schadensverteilung&amp;quot;,&lt;br /&gt;
        averageDamage: &amp;quot;Durchschnittlicher Schaden&amp;quot;,&lt;br /&gt;
        damageAugmentation: &amp;quot;Schadenserhöhung&amp;quot;,&lt;br /&gt;
        bonusVariationTitle: [&lt;br /&gt;
          &amp;quot;Entwicklung des durchschnittlichen Schadens&amp;quot;,&lt;br /&gt;
          &amp;quot;im Verhältnis zu einem Bonus&amp;quot;,&lt;br /&gt;
        ],&lt;br /&gt;
      },&lt;br /&gt;
      pt: {&lt;br /&gt;
        damage: &amp;quot;Dano&amp;quot;,&lt;br /&gt;
        percentage: &amp;quot;Percentagem&amp;quot;,&lt;br /&gt;
        miss: &amp;quot;Miss&amp;quot;,&lt;br /&gt;
        normalHit: &amp;quot;Dano normal&amp;quot;,&lt;br /&gt;
        criticalHit: &amp;quot;Dano crítico&amp;quot;,&lt;br /&gt;
        piercingHit: &amp;quot;Dano perfurante&amp;quot;,&lt;br /&gt;
        criticalPiercingHit: &amp;quot;Dano crítico perfurante&amp;quot;,&lt;br /&gt;
        damageRepartition: &amp;quot;Repartição de dano&amp;quot;,&lt;br /&gt;
        averageDamage: &amp;quot;Dano médio&amp;quot;,&lt;br /&gt;
        damageAugmentation: &amp;quot;Aumento de dano&amp;quot;,&lt;br /&gt;
        bonusVariationTitle: [&amp;quot;Evolução do dano médio&amp;quot;, &amp;quot;relativo a um bónus&amp;quot;],&lt;br /&gt;
      },&lt;br /&gt;
      // es: {&lt;br /&gt;
      //   damage: &amp;quot;Daño&amp;quot;,&lt;br /&gt;
      //   percentage: &amp;quot;Porcentaje&amp;quot;,&lt;br /&gt;
      //   miss: &amp;quot;Miss&amp;quot;,&lt;br /&gt;
      //   normalHit: &amp;quot;Daño normal&amp;quot;,&lt;br /&gt;
      //   criticalHit: &amp;quot;Daño crítico&amp;quot;,&lt;br /&gt;
      //   piercingHit: &amp;quot;Daño perforante&amp;quot;,&lt;br /&gt;
      //   criticalPiercingHit: &amp;quot;Daño crítico perforante&amp;quot;,&lt;br /&gt;
      //   damageRepartition: &amp;quot;Repartición de daños&amp;quot;,&lt;br /&gt;
      //   averageDamage: &amp;quot;Daño medio&amp;quot;,&lt;br /&gt;
      //   damageAugmentation: &amp;quot;Aumento de daño&amp;quot;,&lt;br /&gt;
      //   bonusVariationTitle: [&amp;quot;Evolución del daño medio&amp;quot;, &amp;quot;Relativo a una bonificación&amp;quot;]&lt;br /&gt;
      // },&lt;br /&gt;
    },&lt;br /&gt;
  };&lt;br /&gt;
  return constants;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initResultTableHistory(battle) {&lt;br /&gt;
  var {&lt;br /&gt;
    tableResultHistory,&lt;br /&gt;
    savedFights,&lt;br /&gt;
    deleteFightTemplate,&lt;br /&gt;
    numberFormats: { default: numberFormat },&lt;br /&gt;
  } = battle;&lt;br /&gt;
  var startIndex = 3;&lt;br /&gt;
&lt;br /&gt;
  if (savedFights.length) {&lt;br /&gt;
    hideElement(tableResultHistory.rows[1]);&lt;br /&gt;
&lt;br /&gt;
    for (var savedFight of savedFights) {&lt;br /&gt;
      addRowToTableResultHistory(&lt;br /&gt;
        tableResultHistory,&lt;br /&gt;
        savedFight,&lt;br /&gt;
        deleteFightTemplate,&lt;br /&gt;
        numberFormat&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  tableResultHistory.addEventListener(&amp;quot;click&amp;quot;, function (event) {&lt;br /&gt;
    var deleteButton = event.target.closest(&amp;quot;.svg-icon-delete&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (deleteButton) {&lt;br /&gt;
      var row = deleteButton.closest(&amp;quot;tr&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
      if (row) {&lt;br /&gt;
        savedFights.splice(row.rowIndex - startIndex, 1);&lt;br /&gt;
        updateSavedFights(savedFights);&lt;br /&gt;
&lt;br /&gt;
        row.remove();&lt;br /&gt;
&lt;br /&gt;
        if (tableResultHistory.rows.length === startIndex) {&lt;br /&gt;
          showElement(tableResultHistory.rows[1]);&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initDamageChart(battle) {&lt;br /&gt;
  var { translation, reduceChartPointsContainer, reduceChartPoints } = battle;&lt;br /&gt;
  var percentFormat = battle.numberFormats.percent;&lt;br /&gt;
  var customPlugins = {&lt;br /&gt;
    id: &amp;quot;customPlugins&amp;quot;,&lt;br /&gt;
    afterDraw(chart) {&lt;br /&gt;
      var missPercentage = chart.data.missPercentage;&lt;br /&gt;
&lt;br /&gt;
      if (!missPercentage) {&lt;br /&gt;
        return;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      var {&lt;br /&gt;
        ctx,&lt;br /&gt;
        chartArea: { top, right },&lt;br /&gt;
      } = chart;&lt;br /&gt;
      ctx.save();&lt;br /&gt;
      var text =&lt;br /&gt;
        translation.miss + &amp;quot; : &amp;quot; + percentFormat.format(missPercentage);&lt;br /&gt;
      var padding = 4;&lt;br /&gt;
      var fontSize = 14;&lt;br /&gt;
&lt;br /&gt;
      ctx.font = fontSize + &amp;quot;px Helvetica Neue&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
      var textWidth = ctx.measureText(text).width;&lt;br /&gt;
      var xPosition = right - textWidth - 5;&lt;br /&gt;
      var yPosition = top + 5;&lt;br /&gt;
&lt;br /&gt;
      ctx.fillStyle = &amp;quot;rgba(255, 0, 0, 0.2)&amp;quot;;&lt;br /&gt;
      ctx.fillRect(&lt;br /&gt;
        xPosition - padding,&lt;br /&gt;
        yPosition - padding,&lt;br /&gt;
        textWidth + 2 * padding,&lt;br /&gt;
        fontSize + 2 * padding&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      ctx.strokeStyle = &amp;quot;red&amp;quot;;&lt;br /&gt;
      ctx.strokeRect(&lt;br /&gt;
        xPosition - padding,&lt;br /&gt;
        yPosition - padding,&lt;br /&gt;
        textWidth + 2 * padding,&lt;br /&gt;
        fontSize + 2 * padding&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      ctx.fillStyle = &amp;quot;#666&amp;quot;;&lt;br /&gt;
      ctx.textBaseline = &amp;quot;top&amp;quot;;&lt;br /&gt;
      ctx.fillText(text, xPosition, yPosition + 1);&lt;br /&gt;
&lt;br /&gt;
      ctx.restore();&lt;br /&gt;
    },&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  Chart.register(customPlugins);&lt;br /&gt;
&lt;br /&gt;
  var ctx = battle.plotDamage.getContext(&amp;quot;2d&amp;quot;);&lt;br /&gt;
  var maxLabelsInTooltip = 10;&lt;br /&gt;
  var nullLabelText = &amp;quot; ...&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  var chart = new Chart(ctx, {&lt;br /&gt;
    type: &amp;quot;scatter&amp;quot;,&lt;br /&gt;
    data: {&lt;br /&gt;
      missPercentage: 0,&lt;br /&gt;
      datasets: [],&lt;br /&gt;
    },&lt;br /&gt;
    options: {&lt;br /&gt;
      responsive: true,&lt;br /&gt;
      maintainAspectRatio: false,&lt;br /&gt;
      plugins: {&lt;br /&gt;
        legend: {&lt;br /&gt;
          display: true,&lt;br /&gt;
          onHover: function (e) {&lt;br /&gt;
            e.native.target.style.cursor = &amp;quot;pointer&amp;quot;;&lt;br /&gt;
          },&lt;br /&gt;
          onLeave: function (e) {&lt;br /&gt;
            e.native.target.style.cursor = &amp;quot;default&amp;quot;;&lt;br /&gt;
          },&lt;br /&gt;
          onClick: function (e, legendItem, legend) {&lt;br /&gt;
            var currentIndex = legendItem.datasetIndex;&lt;br /&gt;
            var ci = legend.chart;&lt;br /&gt;
            var isCurrentDatasetVisible = ci.isDatasetVisible(currentIndex);&lt;br /&gt;
            var datasets = ci.data.datasets;&lt;br /&gt;
            var hideReducePoints = true;&lt;br /&gt;
            var isReducePointsChecked = reduceChartPoints.checked;&lt;br /&gt;
&lt;br /&gt;
            datasets[currentIndex].hidden = isCurrentDatasetVisible;&lt;br /&gt;
            legendItem.hidden = isCurrentDatasetVisible;&lt;br /&gt;
&lt;br /&gt;
            for (var index in datasets) {&lt;br /&gt;
              if (ci.isDatasetVisible(index) &amp;amp;&amp;amp; datasets[index].canBeReduced) {&lt;br /&gt;
                showElement(reduceChartPointsContainer);&lt;br /&gt;
                hideReducePoints = false;&lt;br /&gt;
                break;&lt;br /&gt;
              }&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            if (hideReducePoints) {&lt;br /&gt;
              hideElement(reduceChartPointsContainer);&lt;br /&gt;
              handleChartAnimations(ci, true);&lt;br /&gt;
            } else {&lt;br /&gt;
              handleChartAnimations(ci, isReducePointsChecked);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            ci.update();&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        title: {&lt;br /&gt;
          display: true,&lt;br /&gt;
          text: translation.damageRepartition,&lt;br /&gt;
          font: {&lt;br /&gt;
            size: 20,&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        tooltip: {&lt;br /&gt;
          callbacks: {&lt;br /&gt;
            label: function (context) {&lt;br /&gt;
              if (context.label === null) {&lt;br /&gt;
                return nullLabelText;&lt;br /&gt;
              }&lt;br /&gt;
&lt;br /&gt;
              var xValue = battle.numberFormats.default.format(&lt;br /&gt;
                context.parsed.x&lt;br /&gt;
              );&lt;br /&gt;
              var yValue = battle.numberFormats.percent.format(&lt;br /&gt;
                context.parsed.y&lt;br /&gt;
              );&lt;br /&gt;
              var label =&lt;br /&gt;
                &amp;quot; &amp;quot; +&lt;br /&gt;
                context.dataset.label +&lt;br /&gt;
                &amp;quot; : (&amp;quot; +&lt;br /&gt;
                xValue +&lt;br /&gt;
                &amp;quot;, &amp;quot; +&lt;br /&gt;
                yValue +&lt;br /&gt;
                &amp;quot;)&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
              return label;&lt;br /&gt;
            },&lt;br /&gt;
            beforeBody: function (tooltipItems) {&lt;br /&gt;
              if (tooltipItems.length &amp;gt; maxLabelsInTooltip + 1) {&lt;br /&gt;
                tooltipItems.splice(maxLabelsInTooltip + 1);&lt;br /&gt;
                tooltipItems[maxLabelsInTooltip].label = null;&lt;br /&gt;
              }&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          caretPadding: 10,&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
      scales: {&lt;br /&gt;
        x: {&lt;br /&gt;
          type: &amp;quot;linear&amp;quot;,&lt;br /&gt;
          position: &amp;quot;bottom&amp;quot;,&lt;br /&gt;
          title: {&lt;br /&gt;
            display: true,&lt;br /&gt;
            text: translation.damage,&lt;br /&gt;
            font: {&lt;br /&gt;
              size: 16,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          ticks: {&lt;br /&gt;
            callback: function (value) {&lt;br /&gt;
              return Number.isInteger(value) ? value : &amp;quot;&amp;quot;;&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        y: {&lt;br /&gt;
          title: {&lt;br /&gt;
            display: true,&lt;br /&gt;
            text: translation.percentage,&lt;br /&gt;
            font: {&lt;br /&gt;
              size: 16,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          ticks: {&lt;br /&gt;
            format: {&lt;br /&gt;
              style: &amp;quot;percent&amp;quot;,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
      elements: {&lt;br /&gt;
        point: {&lt;br /&gt;
          borderWidth: 1,&lt;br /&gt;
          radius: 3,&lt;br /&gt;
          hitRadius: 3,&lt;br /&gt;
          hoverRadius: 6,&lt;br /&gt;
          hoverBorderWidth: 2,&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
    },&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  var datasetsStyle = [&lt;br /&gt;
    {&lt;br /&gt;
      name: &amp;quot;normalHit&amp;quot;,&lt;br /&gt;
      canBeReduced: false,&lt;br /&gt;
      label: translation.normalHit,&lt;br /&gt;
      backgroundColor: &amp;quot;rgba(75, 192, 192, 0.2)&amp;quot;,&lt;br /&gt;
      borderColor: &amp;quot;rgba(75, 192, 192, 1)&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      name: &amp;quot;piercingHit&amp;quot;,&lt;br /&gt;
      canBeReduced: false,&lt;br /&gt;
      label: translation.piercingHit,&lt;br /&gt;
      backgroundColor: &amp;quot;rgba(192, 192, 75, 0.2)&amp;quot;,&lt;br /&gt;
      borderColor: &amp;quot;rgba(192, 192, 75, 1)&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      name: &amp;quot;criticalHit&amp;quot;,&lt;br /&gt;
      canBeReduced: false,&lt;br /&gt;
      label: translation.criticalHit,&lt;br /&gt;
      backgroundColor: &amp;quot;rgba(192, 75, 192, 0.2)&amp;quot;,&lt;br /&gt;
      borderColor: &amp;quot;rgba(192, 75, 192, 1)&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      name: &amp;quot;criticalPiercingHit&amp;quot;,&lt;br /&gt;
      canBeReduced: false,&lt;br /&gt;
      label: translation.criticalPiercingHit,&lt;br /&gt;
      backgroundColor: &amp;quot;rgba(75, 75, 192, 0.2)&amp;quot;,&lt;br /&gt;
      borderColor: &amp;quot;rgba(75, 75, 192, 1)&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
  ];&lt;br /&gt;
  battle.damageChart = {&lt;br /&gt;
    chart: chart,&lt;br /&gt;
    datasetsStyle: datasetsStyle,&lt;br /&gt;
    maxPoints: 500,&lt;br /&gt;
    reduceChartPointsContainer: reduceChartPointsContainer,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initBonusVariationChart(battle) {&lt;br /&gt;
  var translation = battle.translation;&lt;br /&gt;
&lt;br /&gt;
  var ctx = battle.plotBonusVariation.getContext(&amp;quot;2d&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  var chart = new Chart(ctx, {&lt;br /&gt;
    type: &amp;quot;line&amp;quot;,&lt;br /&gt;
    data: {&lt;br /&gt;
      datasets: [&lt;br /&gt;
        {&lt;br /&gt;
          label: translation.averageDamage,&lt;br /&gt;
          backgroundColor: &amp;quot;rgba(75, 192, 192, 0.2)&amp;quot;,&lt;br /&gt;
          borderColor: &amp;quot;rgba(75, 192, 192, 1)&amp;quot;,&lt;br /&gt;
          fill: true,&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          label: translation.damageAugmentation,&lt;br /&gt;
          backgroundColor: &amp;quot;rgba(192, 192, 75, 0.2)&amp;quot;,&lt;br /&gt;
          borderColor: &amp;quot;rgba(192, 192, 75, 1)&amp;quot;,&lt;br /&gt;
          hidden: true,&lt;br /&gt;
          yTicksFormat: { style: &amp;quot;percent&amp;quot; },&lt;br /&gt;
          fill: true,&lt;br /&gt;
        },&lt;br /&gt;
      ],&lt;br /&gt;
    },&lt;br /&gt;
    options: {&lt;br /&gt;
      responsive: true,&lt;br /&gt;
      maintainAspectRatio: false,&lt;br /&gt;
      plugins: {&lt;br /&gt;
        legend: {&lt;br /&gt;
          display: true,&lt;br /&gt;
          onHover: function (e) {&lt;br /&gt;
            e.native.target.style.cursor = &amp;quot;pointer&amp;quot;;&lt;br /&gt;
          },&lt;br /&gt;
          onLeave: function (e) {&lt;br /&gt;
            e.native.target.style.cursor = &amp;quot;default&amp;quot;;&lt;br /&gt;
          },&lt;br /&gt;
          onClick: function (e, legendItem, legend) {&lt;br /&gt;
            var currentIndex = legendItem.datasetIndex;&lt;br /&gt;
            var ci = legend.chart;&lt;br /&gt;
            var datasets = ci.data.datasets;&lt;br /&gt;
            var isCurrentDatasetVisible = ci.isDatasetVisible(currentIndex);&lt;br /&gt;
            var yAxis = ci.options.scales.y;&lt;br /&gt;
&lt;br /&gt;
            var otherIndex = currentIndex === 0 ? 1 : 0;&lt;br /&gt;
            var visibleDataset = isCurrentDatasetVisible&lt;br /&gt;
              ? datasets[otherIndex]&lt;br /&gt;
              : datasets[currentIndex];&lt;br /&gt;
&lt;br /&gt;
            datasets[currentIndex].hidden = isCurrentDatasetVisible;&lt;br /&gt;
            datasets[otherIndex].hidden = !isCurrentDatasetVisible;&lt;br /&gt;
&lt;br /&gt;
            yAxis.title.text = visibleDataset.label;&lt;br /&gt;
            yAxis.ticks.format = visibleDataset.yTicksFormat;&lt;br /&gt;
&lt;br /&gt;
            ci.update();&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        title: {&lt;br /&gt;
          display: true,&lt;br /&gt;
          text: translation.bonusVariationTitle,&lt;br /&gt;
          font: {&lt;br /&gt;
            size: 18,&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        tooltip: {&lt;br /&gt;
          caretPadding: 10,&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
      scales: {&lt;br /&gt;
        x: {&lt;br /&gt;
          type: &amp;quot;linear&amp;quot;,&lt;br /&gt;
          position: &amp;quot;bottom&amp;quot;,&lt;br /&gt;
          title: {&lt;br /&gt;
            display: true,&lt;br /&gt;
            text: &amp;quot;Bonus&amp;quot;,&lt;br /&gt;
            font: {&lt;br /&gt;
              size: 16,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          ticks: {&lt;br /&gt;
            callback: function (value) {&lt;br /&gt;
              if (Number.isInteger(value)) {&lt;br /&gt;
                return Number(value);&lt;br /&gt;
              }&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        y: {&lt;br /&gt;
          title: {&lt;br /&gt;
            display: true,&lt;br /&gt;
            text: translation.averageDamage,&lt;br /&gt;
            font: {&lt;br /&gt;
              size: 16,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
      elements: {&lt;br /&gt;
        point: {&lt;br /&gt;
          borderWidth: 1,&lt;br /&gt;
          radius: 3,&lt;br /&gt;
          hitRadius: 3,&lt;br /&gt;
          hoverRadius: 6,&lt;br /&gt;
          hoverBorderWidth: 2,&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
    },&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  battle.bonusVariationChart = chart;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterAttackTypeSelection(characters, battleChoice, targetValue) {&lt;br /&gt;
  var { nameOrVnum: attackerNameOrVnum, isCharacter: isAttackerPlayer } =&lt;br /&gt;
    parseTypeAndName(targetValue);&lt;br /&gt;
&lt;br /&gt;
  if (isAttackerPlayer) {&lt;br /&gt;
    var attacker = characters.savedCharacters[attackerNameOrVnum];&lt;br /&gt;
    filterAttackTypeSelectionCharacter(attacker, battleChoice.attackType);&lt;br /&gt;
  } else {&lt;br /&gt;
    filterAttackTypeSelectionMonster(battleChoice.attackType);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getTranslation(translation) {&lt;br /&gt;
  var userLanguage = navigator.language;&lt;br /&gt;
  var langToUse = &amp;quot;en&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  for (var lang in translation) {&lt;br /&gt;
    if (userLanguage.startsWith(lang)) {&lt;br /&gt;
      langToUse = lang;&lt;br /&gt;
      break;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return translation[langToUse];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addBattleData(battle) {&lt;br /&gt;
  var errorElements = document.querySelectorAll(&amp;quot;[data-error]&amp;quot;);&lt;br /&gt;
  var { elements: attackTypeElements, container: attackTypeContainer } =&lt;br /&gt;
    battle.battleChoice.attackType;&lt;br /&gt;
  var attackTypeChilds = attackTypeContainer.children;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; errorElements.length; index++) {&lt;br /&gt;
    var errorElement = errorElements[index];&lt;br /&gt;
    battle.errorInformation[errorElement.dataset.error] = errorElement;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (var index = 1; index &amp;lt; attackTypeChilds.length - 1; index++) {&lt;br /&gt;
    var attackTypeChild = attackTypeChilds[index];&lt;br /&gt;
    var input = attackTypeChild.querySelector(&amp;quot;input&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    attackTypeElements.push({&lt;br /&gt;
      container: attackTypeChild,&lt;br /&gt;
      input: input,&lt;br /&gt;
      inputClass: input.dataset.class,&lt;br /&gt;
      inputValue: input.value,&lt;br /&gt;
    });&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createDamageCalculatorInformation(chartSource) {&lt;br /&gt;
  var characters = {&lt;br /&gt;
    unsavedChanges: false,&lt;br /&gt;
    savedCharacters: {},&lt;br /&gt;
    currentCharacter: null,&lt;br /&gt;
    savedMonsters: getSavedMonsters(),&lt;br /&gt;
    monsterElements: {},&lt;br /&gt;
    characterCreation: document.getElementById(&amp;quot;character-creation&amp;quot;),&lt;br /&gt;
    addNewCharacterButton: document.getElementById(&amp;quot;add-new-character&amp;quot;),&lt;br /&gt;
    dropZone: document.getElementById(&amp;quot;character-drop-zone&amp;quot;),&lt;br /&gt;
    characterInput: document.getElementById(&amp;quot;character-input&amp;quot;),&lt;br /&gt;
    newCharacterTemplate: document.getElementById(&amp;quot;new-character-template&amp;quot;)&lt;br /&gt;
      .children[0],&lt;br /&gt;
    charactersContainer: document.getElementById(&amp;quot;characters-container&amp;quot;),&lt;br /&gt;
    monsterButtonTemplates: document.getElementById(&amp;quot;monster-button-templates&amp;quot;),&lt;br /&gt;
    monsterTemplate: document.getElementById(&amp;quot;new-monster-template&amp;quot;)&lt;br /&gt;
      .children[0],&lt;br /&gt;
    monstersContainer: document.getElementById(&amp;quot;monsters-container&amp;quot;),&lt;br /&gt;
    monsteriFrame: document.getElementById(&amp;quot;monster-iframe&amp;quot;),&lt;br /&gt;
    stoneiFrame: document.getElementById(&amp;quot;stone-iframe&amp;quot;),&lt;br /&gt;
    saveButton: document.getElementById(&amp;quot;save-character&amp;quot;),&lt;br /&gt;
    weaponCategory: document.getElementById(&amp;quot;weapon-category&amp;quot;),&lt;br /&gt;
    weaponDisplay: document.getElementById(&amp;quot;weapon-display&amp;quot;),&lt;br /&gt;
    randomAttackValue: document.getElementById(&amp;quot;random-attack-value&amp;quot;),&lt;br /&gt;
    randomMagicAttackValue: document.getElementById(&lt;br /&gt;
      &amp;quot;random-magic-attack-value&amp;quot;&lt;br /&gt;
    ),&lt;br /&gt;
    toggleSiblings: {},&lt;br /&gt;
    polymorphDisplay: document.getElementById(&amp;quot;polymorph-display&amp;quot;),&lt;br /&gt;
    bonusVariation: {&lt;br /&gt;
      tabButton: document.getElementById(&amp;quot;Variation&amp;quot;),&lt;br /&gt;
      checkbox: document.getElementById(&amp;quot;use-bonus-variation&amp;quot;),&lt;br /&gt;
      input: document.getElementById(&amp;quot;bonus-variation&amp;quot;),&lt;br /&gt;
      inputName: document.getElementById(&amp;quot;bonus-variation-name&amp;quot;),&lt;br /&gt;
      container: document.getElementById(&amp;quot;bonus-variation-creation&amp;quot;),&lt;br /&gt;
      minValue: document.getElementById(&amp;quot;bonus-variation-min-value&amp;quot;),&lt;br /&gt;
      maxValue: document.getElementById(&amp;quot;bonus-variation-max-value&amp;quot;),&lt;br /&gt;
      disabledText: document.getElementById(&amp;quot;bonus-variation-disabled&amp;quot;),&lt;br /&gt;
      selectedText: document.getElementById(&amp;quot;bonus-variation-selected&amp;quot;),&lt;br /&gt;
      displaySpan: document.getElementById(&amp;quot;bonus-variation-display&amp;quot;),&lt;br /&gt;
    },&lt;br /&gt;
    skillElementsToFilter: document.querySelectorAll(&lt;br /&gt;
      &amp;quot;#skill-container [data-class]&amp;quot;&lt;br /&gt;
    ),&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  for (var [pseudo, character] of Object.entries(getSavedCharacters())) {&lt;br /&gt;
    characters.savedCharacters[pseudo] = character;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  document.querySelectorAll(&amp;quot;.toggle-sibling&amp;quot;).forEach(function (element) {&lt;br /&gt;
    var target = element.dataset.target;&lt;br /&gt;
    var sibling = document.getElementById(target);&lt;br /&gt;
    characters.toggleSiblings[element.name] = sibling;&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  var constants = createConstants();&lt;br /&gt;
&lt;br /&gt;
  var battle = {&lt;br /&gt;
    savedFights: getSavedFights(),&lt;br /&gt;
    battleChoice: {&lt;br /&gt;
      resetAttackType: false,&lt;br /&gt;
      form: document.getElementById(&amp;quot;create-battle&amp;quot;),&lt;br /&gt;
      template: document.getElementById(&amp;quot;battle-selection-template&amp;quot;)&lt;br /&gt;
        .children[0],&lt;br /&gt;
      raceToImage: {&lt;br /&gt;
        warrior: &amp;quot;/images/0/0f/Bandeaurougehomme.png&amp;quot;,&lt;br /&gt;
        ninja: &amp;quot;/images/0/0e/Queuedechevalclair.png&amp;quot;,&lt;br /&gt;
        sura: &amp;quot;/images/3/37/Couperespectablerouge.png&amp;quot;,&lt;br /&gt;
        shaman: &amp;quot;/images/6/6a/Coupeeleganteclairfemme.png&amp;quot;,&lt;br /&gt;
        lycan: &amp;quot;/images/4/4e/Protectionfrontalerouge.png&amp;quot;,&lt;br /&gt;
      },&lt;br /&gt;
      categories: [&amp;quot;attacker&amp;quot;, &amp;quot;victim&amp;quot;],&lt;br /&gt;
      attacker: {&lt;br /&gt;
        character: {&lt;br /&gt;
          count: 0,&lt;br /&gt;
          container: document.getElementById(&amp;quot;attacker-selection-characters&amp;quot;),&lt;br /&gt;
          elements: {},&lt;br /&gt;
        },&lt;br /&gt;
        monster: {&lt;br /&gt;
          count: 0,&lt;br /&gt;
          container: document.getElementById(&amp;quot;attacker-selection-monsters&amp;quot;),&lt;br /&gt;
          elements: {},&lt;br /&gt;
        },&lt;br /&gt;
        button: document.getElementById(&amp;quot;attacker-trigger&amp;quot;),&lt;br /&gt;
        defaultButtonContent: document.getElementById(&lt;br /&gt;
          &amp;quot;attacker-default-button-content&amp;quot;&lt;br /&gt;
        ),&lt;br /&gt;
        buttonContent: document.getElementById(&amp;quot;attacker-button-content&amp;quot;),&lt;br /&gt;
        container: document.getElementById(&amp;quot;attacker-selection&amp;quot;),&lt;br /&gt;
        selected: null,&lt;br /&gt;
      },&lt;br /&gt;
      victim: {&lt;br /&gt;
        character: {&lt;br /&gt;
          count: 0,&lt;br /&gt;
          container: document.getElementById(&amp;quot;victim-selection-characters&amp;quot;),&lt;br /&gt;
          elements: {},&lt;br /&gt;
        },&lt;br /&gt;
        monster: {&lt;br /&gt;
          count: 0,&lt;br /&gt;
          container: document.getElementById(&amp;quot;victim-selection-monsters&amp;quot;),&lt;br /&gt;
          elements: {},&lt;br /&gt;
        },&lt;br /&gt;
        stone: {&lt;br /&gt;
          count: 0,&lt;br /&gt;
          container: document.getElementById(&amp;quot;victim-selection-stones&amp;quot;),&lt;br /&gt;
          elements: {},&lt;br /&gt;
        },&lt;br /&gt;
        button: document.getElementById(&amp;quot;victim-trigger&amp;quot;),&lt;br /&gt;
        defaultButtonContent: document.getElementById(&lt;br /&gt;
          &amp;quot;victim-default-button-content&amp;quot;&lt;br /&gt;
        ),&lt;br /&gt;
        buttonContent: document.getElementById(&amp;quot;victim-button-content&amp;quot;),&lt;br /&gt;
        selected: null,&lt;br /&gt;
      },&lt;br /&gt;
      attackType: {&lt;br /&gt;
        container: document.getElementById(&amp;quot;attack-type-selection&amp;quot;),&lt;br /&gt;
        elements: [],&lt;br /&gt;
        defaultInput: document.getElementById(&amp;quot;physical-attack&amp;quot;),&lt;br /&gt;
        selectedText: &amp;quot;&amp;quot;,&lt;br /&gt;
      },&lt;br /&gt;
    },&lt;br /&gt;
    damageWeightedByType: {},&lt;br /&gt;
    scatterDataByType: {},&lt;br /&gt;
    damageByBonus: [],&lt;br /&gt;
    tableResultFight: document.getElementById(&amp;quot;result-table-fight&amp;quot;),&lt;br /&gt;
    tableResultHistory: document.getElementById(&amp;quot;result-table-history&amp;quot;),&lt;br /&gt;
    deleteFightTemplate: document.getElementById(&amp;quot;delete-fight-template&amp;quot;)&lt;br /&gt;
      .children[0],&lt;br /&gt;
    errorInformation: {},&lt;br /&gt;
    fightResultTitle: document.getElementById(&amp;quot;fight-result-title&amp;quot;),&lt;br /&gt;
    fightResultContainer: document.getElementById(&amp;quot;fight-result-container&amp;quot;),&lt;br /&gt;
    downLoadRawData: document.getElementById(&amp;quot;download-raw-data&amp;quot;),&lt;br /&gt;
    downLoadRawDataVariation: document.getElementById(&lt;br /&gt;
      &amp;quot;download-raw-data-variation&amp;quot;&lt;br /&gt;
    ),&lt;br /&gt;
    bonusVariationResultContainer: document.getElementById(&lt;br /&gt;
      &amp;quot;bonus-variation-result-container&amp;quot;&lt;br /&gt;
    ),&lt;br /&gt;
    reduceChartPointsContainer: document.getElementById(&lt;br /&gt;
      &amp;quot;reduce-chart-points-container&amp;quot;&lt;br /&gt;
    ),&lt;br /&gt;
    reduceChartPoints: document.getElementById(&amp;quot;reduce-chart-points&amp;quot;),&lt;br /&gt;
    plotDamage: document.getElementById(&amp;quot;plot-damage&amp;quot;),&lt;br /&gt;
    plotBonusVariation: document.getElementById(&amp;quot;plot-bonus-variation&amp;quot;),&lt;br /&gt;
    uniqueDamageCounters: document.querySelectorAll(&amp;quot;.unique-damage-counter&amp;quot;),&lt;br /&gt;
    possibleDamageCounter: document.getElementById(&amp;quot;possible-damage-counter&amp;quot;),&lt;br /&gt;
    damageTime: document.getElementById(&amp;quot;damage-time&amp;quot;),&lt;br /&gt;
    displayTime: document.getElementById(&amp;quot;display-time&amp;quot;),&lt;br /&gt;
    simulationCounter: document.getElementById(&amp;quot;simulation-counter&amp;quot;),&lt;br /&gt;
    simulationTime: document.getElementById(&amp;quot;simulation-time&amp;quot;),&lt;br /&gt;
    numberFormats: {&lt;br /&gt;
      default: new Intl.NumberFormat(undefined, {&lt;br /&gt;
        minimumFractionDigits: 0,&lt;br /&gt;
        maximumFractionDigits: 1,&lt;br /&gt;
      }),&lt;br /&gt;
      percent: new Intl.NumberFormat(undefined, {&lt;br /&gt;
        style: &amp;quot;percent&amp;quot;,&lt;br /&gt;
        maximumFractionDigits: 3,&lt;br /&gt;
      }),&lt;br /&gt;
      second: new Intl.NumberFormat(undefined, {&lt;br /&gt;
        style: &amp;quot;unit&amp;quot;,&lt;br /&gt;
        unit: &amp;quot;second&amp;quot;,&lt;br /&gt;
        unitDisplay: &amp;quot;long&amp;quot;,&lt;br /&gt;
        maximumFractionDigits: 3,&lt;br /&gt;
      }),&lt;br /&gt;
    },&lt;br /&gt;
    mapping: createMapping(),&lt;br /&gt;
    constants: constants,&lt;br /&gt;
    translation: getTranslation(constants.translation),&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  addBattleData(battle);&lt;br /&gt;
  initResultTableHistory(battle);&lt;br /&gt;
  addScript(chartSource, function () {&lt;br /&gt;
    initDamageChart(battle);&lt;br /&gt;
    initBonusVariationChart(battle);&lt;br /&gt;
  });&lt;br /&gt;
  reduceChartPointsListener(battle);&lt;br /&gt;
  downloadRawDataListener(battle);&lt;br /&gt;
&lt;br /&gt;
  return [characters, battle];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadStyle(src) {&lt;br /&gt;
  var link = document.createElement(&amp;quot;link&amp;quot;);&lt;br /&gt;
  link.href = src;&lt;br /&gt;
  link.rel = &amp;quot;stylesheet&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  document.head.appendChild(link);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
(function () {&lt;br /&gt;
  var javascriptSource =&lt;br /&gt;
    &amp;quot;/index.php?title=Utilisateur:Ankhseram/Calculator.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&amp;quot;;&lt;br /&gt;
  var cssSource =&lt;br /&gt;
    &amp;quot;/index.php?title=Utilisateur:Ankhseram/Style.css&amp;amp;action=raw&amp;amp;ctype=text/css&amp;quot;;&lt;br /&gt;
  var chartSource = &amp;quot;https://cdn.jsdelivr.net/npm/chart.js&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  loadStyle(cssSource);&lt;br /&gt;
&lt;br /&gt;
  function main() {&lt;br /&gt;
    var [characters, battle] = createDamageCalculatorInformation(chartSource);&lt;br /&gt;
&lt;br /&gt;
    characterManagement(characters, battle);&lt;br /&gt;
    monsterManagement(characters, battle);&lt;br /&gt;
&lt;br /&gt;
    updateBattleChoice(characters, battle.battleChoice);&lt;br /&gt;
    createBattle(characters, battle);&lt;br /&gt;
  }&lt;br /&gt;
  addScript(javascriptSource, main);&lt;br /&gt;
})();&lt;/div&gt;</summary>
		<author><name>Dexter</name></author>
		
	</entry>
	<entry>
		<id>https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Script/Calculator.js&amp;diff=106399</id>
		<title>MediaWiki:Script/Calculator.js</title>
		<link rel="alternate" type="text/html" href="https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Script/Calculator.js&amp;diff=106399"/>
		<updated>2025-02-17T05:17:19Z</updated>

		<summary type="html">&lt;p&gt;Dexter : v0.19&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;function removeAccent(str) {&lt;br /&gt;
  return str.normalize(&amp;quot;NFD&amp;quot;).replace(/[\u0300-\u036f]/g, &amp;quot;&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function pseudoFormat(str) {&lt;br /&gt;
  return removeAccent(str).replace(/[^A-Za-z0-9 \(\)\+_-]+/g, &amp;quot;&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isValueInArray(value, array) {&lt;br /&gt;
  return array.indexOf(value) !== -1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function splitFirst(value, delimiter) {&lt;br /&gt;
  var parts = value.split(delimiter);&lt;br /&gt;
  var first = parts[0];&lt;br /&gt;
  var rest = parts.slice(1).join(delimiter);&lt;br /&gt;
  return [first, rest];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function copyObject(object) {&lt;br /&gt;
  var copy = {};&lt;br /&gt;
  for (var key in object) {&lt;br /&gt;
    copy[key] = object[key];&lt;br /&gt;
  }&lt;br /&gt;
  return copy;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function compareNumbers(a, b) {&lt;br /&gt;
  return b - a;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isChecked(attribute) {&lt;br /&gt;
  return attribute === &amp;quot;on&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function floorMultiplication(firstFactor, secondFactor) {&lt;br /&gt;
  return Math.floor((firstFactor * secondFactor).toFixed(8));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function truncateNumber(number, precision) {&lt;br /&gt;
  return Math.floor(number * 10 ** precision) / 10 ** precision;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function newChangeEvent() {&lt;br /&gt;
  return new Event(&amp;quot;change&amp;quot;, { bubbles: true });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addKeyValue(object, key, value) {&lt;br /&gt;
  if (object.hasOwnProperty(key)) {&lt;br /&gt;
    object[key] += value;&lt;br /&gt;
  } else {&lt;br /&gt;
    object[key] = value;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function openTargetTab(target) {&lt;br /&gt;
  var tabberContainer = target.closest(&amp;quot;.tabber-container&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (!tabberContainer) {&lt;br /&gt;
    return;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var [buttonsContainer, tabsContainer] = tabberContainer.children;&lt;br /&gt;
  var buttons = buttonsContainer.children;&lt;br /&gt;
  var tabs = tabsContainer.children;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; tabs.length; index++) {&lt;br /&gt;
    var tab = tabs[index];&lt;br /&gt;
    if (tab.contains(target) &amp;amp;&amp;amp; !tab.checkVisibility()) {&lt;br /&gt;
      buttons[index].click();&lt;br /&gt;
      break;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function openTargetCollapsible(target) {&lt;br /&gt;
  var collapsible = target.closest(&amp;quot;.improved-collapsible&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (!collapsible) {&lt;br /&gt;
    return;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var span = collapsible.firstElementChild;&lt;br /&gt;
&lt;br /&gt;
  if (!span.classList.contains(&amp;quot;mw-collapsible-toggle-expanded&amp;quot;)) {&lt;br /&gt;
    span.click();&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function editTableResultRow(row, valuesToDisplay, numberFormat) {&lt;br /&gt;
  row.innerHTML = &amp;quot;&amp;quot;;&lt;br /&gt;
  for (var index = 0; index &amp;lt; valuesToDisplay.length; index++) {&lt;br /&gt;
    var cell = row.insertCell();&lt;br /&gt;
    var textContent;&lt;br /&gt;
&lt;br /&gt;
    if (index &amp;gt;= 3) {&lt;br /&gt;
      textContent = numberFormat.format(valuesToDisplay[index]);&lt;br /&gt;
    } else {&lt;br /&gt;
      textContent = valuesToDisplay[index];&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    cell.textContent = textContent;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return row;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addRowToTableResultHistory(&lt;br /&gt;
  tableResultHistory,&lt;br /&gt;
  valuesToDisplay,&lt;br /&gt;
  deleteFightTemplate,&lt;br /&gt;
  numberFormat&lt;br /&gt;
) {&lt;br /&gt;
  var row = tableResultHistory.insertRow();&lt;br /&gt;
  editTableResultRow(row, valuesToDisplay, numberFormat);&lt;br /&gt;
  var cell = row.insertCell();&lt;br /&gt;
  cell.appendChild(deleteFightTemplate.cloneNode(true));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcMeanDamage(damageWeightedByType, totalCardinal) {&lt;br /&gt;
  var sumDamage = 0;&lt;br /&gt;
&lt;br /&gt;
  for (var damageTypeName in damageWeightedByType) {&lt;br /&gt;
    if (damageTypeName === &amp;quot;miss&amp;quot;) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var damageWeighted = damageWeightedByType[damageTypeName];&lt;br /&gt;
&lt;br /&gt;
    for (var damage in damageWeighted) {&lt;br /&gt;
      sumDamage += damage * damageWeighted[damage];&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return sumDamage / totalCardinal;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function prepareDamageData(damageWeightedByType, attackValues) {&lt;br /&gt;
  var totalCardinal = attackValues.totalCardinal;&lt;br /&gt;
  var minDamage = Infinity;&lt;br /&gt;
  var maxDamage = 0;&lt;br /&gt;
  var scatterDataByType = {};&lt;br /&gt;
  var sumDamage = 0;&lt;br /&gt;
  var possibleDamageCount = 0;&lt;br /&gt;
  var possibleDamageCountTemp = 0;&lt;br /&gt;
  var uniqueDamageCount = 0;&lt;br /&gt;
&lt;br /&gt;
  for (var damageTypeName in damageWeightedByType) {&lt;br /&gt;
    if (damageTypeName === &amp;quot;miss&amp;quot;) {&lt;br /&gt;
      scatterDataByType.miss = damageWeightedByType.miss;&lt;br /&gt;
      possibleDamageCount++;&lt;br /&gt;
      uniqueDamageCount++;&lt;br /&gt;
      continue;&lt;br /&gt;
    } else if (&lt;br /&gt;
      (damageTypeName === &amp;quot;criticalHit&amp;quot; ||&lt;br /&gt;
        damageTypeName === &amp;quot;criticalPiercingHit&amp;quot;) &amp;amp;&amp;amp;&lt;br /&gt;
      attackValues.isPlayerVsPlayer&lt;br /&gt;
    ) {&lt;br /&gt;
      possibleDamageCountTemp =&lt;br /&gt;
        attackValues.possibleDamageCount * attackValues.weapon.interval;&lt;br /&gt;
    } else {&lt;br /&gt;
      possibleDamageCountTemp = attackValues.possibleDamageCount;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var firstIteration = true;&lt;br /&gt;
    var damageWeighted = damageWeightedByType[damageTypeName];&lt;br /&gt;
    var scatterData = [];&lt;br /&gt;
    scatterDataByType[damageTypeName] = scatterData;&lt;br /&gt;
&lt;br /&gt;
    for (var damage in damageWeighted) {&lt;br /&gt;
      damage = +damage;&lt;br /&gt;
&lt;br /&gt;
      if (firstIteration) {&lt;br /&gt;
        if (damage &amp;lt; minDamage) {&lt;br /&gt;
          minDamage = damage;&lt;br /&gt;
        }&lt;br /&gt;
        firstIteration = false;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      var weight = damageWeighted[damage];&lt;br /&gt;
      var probability = weight / totalCardinal;&lt;br /&gt;
&lt;br /&gt;
      sumDamage += damage * weight;&lt;br /&gt;
      damageWeighted[damage] = probability;&lt;br /&gt;
      scatterData.push({ x: damage, y: probability });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var scatterDataLength = scatterData.length;&lt;br /&gt;
&lt;br /&gt;
    possibleDamageCount += possibleDamageCountTemp;&lt;br /&gt;
    uniqueDamageCount += scatterDataLength;&lt;br /&gt;
&lt;br /&gt;
    if (damage &amp;gt; maxDamage) {&lt;br /&gt;
      maxDamage = damage;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (minDamage === Infinity) {&lt;br /&gt;
    minDamage = 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  attackValues.possibleDamageCount = possibleDamageCount;&lt;br /&gt;
&lt;br /&gt;
  return [&lt;br /&gt;
    sumDamage / totalCardinal,&lt;br /&gt;
    minDamage,&lt;br /&gt;
    maxDamage,&lt;br /&gt;
    scatterDataByType,&lt;br /&gt;
    uniqueDamageCount,&lt;br /&gt;
  ];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function aggregateDamage(scatterData, maxPoints) {&lt;br /&gt;
  var dataLength = scatterData.length;&lt;br /&gt;
  var remainingData = dataLength;&lt;br /&gt;
  var aggregateScatterData = [];&lt;br /&gt;
&lt;br /&gt;
  for (var groupIndex = 0; groupIndex &amp;lt; maxPoints; groupIndex++) {&lt;br /&gt;
    var groupLength = Math.floor(remainingData / (maxPoints - groupIndex));&lt;br /&gt;
    var startIndex = dataLength - remainingData;&lt;br /&gt;
    var aggregateDamage = 0;&lt;br /&gt;
    var aggregateProbability = 0;&lt;br /&gt;
&lt;br /&gt;
    for (var index = startIndex; index &amp;lt; startIndex + groupLength; index++) {&lt;br /&gt;
      var { x: damage, y: probability } = scatterData[index];&lt;br /&gt;
      aggregateDamage += damage * probability;&lt;br /&gt;
      aggregateProbability += probability;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    aggregateScatterData.push({&lt;br /&gt;
      x: aggregateDamage / aggregateProbability,&lt;br /&gt;
      y: aggregateProbability,&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    remainingData -= groupLength;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return aggregateScatterData;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addToDamageChart(&lt;br /&gt;
  scatterDataByType,&lt;br /&gt;
  damageChart,&lt;br /&gt;
  isReducePointsChecked&lt;br /&gt;
) {&lt;br /&gt;
  var { chart, datasetsStyle, maxPoints, reduceChartPointsContainer } =&lt;br /&gt;
    damageChart;&lt;br /&gt;
  var isFirstDataset = true;&lt;br /&gt;
  var datasets = chart.data.datasets;&lt;br /&gt;
&lt;br /&gt;
  datasets.length = 0;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; datasetsStyle.length; index++) {&lt;br /&gt;
    var dataset = copyObject(datasetsStyle[index]);&lt;br /&gt;
&lt;br /&gt;
    if (!scatterDataByType.hasOwnProperty(dataset.name)) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var scatterData = scatterDataByType[dataset.name];&lt;br /&gt;
    var canBeReduced = scatterData.length &amp;gt; 2 * maxPoints;&lt;br /&gt;
&lt;br /&gt;
    dataset.hidden = !isFirstDataset;&lt;br /&gt;
    dataset.canBeReduced = canBeReduced;&lt;br /&gt;
&lt;br /&gt;
    if (canBeReduced &amp;amp;&amp;amp; isReducePointsChecked) {&lt;br /&gt;
      dataset.data = aggregateDamage(scatterData, maxPoints);&lt;br /&gt;
    } else {&lt;br /&gt;
      dataset.data = scatterData;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isFirstDataset) {&lt;br /&gt;
      isFirstDataset = false;&lt;br /&gt;
&lt;br /&gt;
      if (canBeReduced) {&lt;br /&gt;
        showElement(reduceChartPointsContainer);&lt;br /&gt;
&lt;br /&gt;
        if (!isReducePointsChecked) {&lt;br /&gt;
          handleChartAnimations(chart, false);&lt;br /&gt;
        }&lt;br /&gt;
      } else {&lt;br /&gt;
        hideElement(reduceChartPointsContainer);&lt;br /&gt;
        handleChartAnimations(chart, true);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    datasets.push(dataset);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  chart.data.missPercentage = scatterDataByType.miss;&lt;br /&gt;
  chart.update();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addToBonusVariationChart(&lt;br /&gt;
  damageByBonus,&lt;br /&gt;
  augmentationByBonus,&lt;br /&gt;
  xLabel,&lt;br /&gt;
  chart&lt;br /&gt;
) {&lt;br /&gt;
  chart.data.datasets[0].data = damageByBonus;&lt;br /&gt;
  chart.data.datasets[1].data = augmentationByBonus;&lt;br /&gt;
  chart.options.scales.x.title.text = xLabel;&lt;br /&gt;
  chart.update();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleChartAnimations(chart, addAnimations) {&lt;br /&gt;
  chart.options.animation = addAnimations;&lt;br /&gt;
  chart.options.animations.colors = addAnimations;&lt;br /&gt;
  chart.options.animations.x = addAnimations;&lt;br /&gt;
  chart.options.transitions.active.animation.duration = addAnimations * 1000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateDamageChartDescription(&lt;br /&gt;
  uniqueDamageCounters,&lt;br /&gt;
  uniqueDamageCount,&lt;br /&gt;
  formatNumber&lt;br /&gt;
) {&lt;br /&gt;
  uniqueDamageCounters.forEach(function (element) {&lt;br /&gt;
    if (uniqueDamageCount &amp;lt;= 1) {&lt;br /&gt;
      hideElement(element.parentElement);&lt;br /&gt;
    } else {&lt;br /&gt;
      showElement(element.parentElement);&lt;br /&gt;
      element.textContent = formatNumber.format(uniqueDamageCount);&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getMonsterName(monsterVnum) {&lt;br /&gt;
  var monsterAttributes = monsterData[monsterVnum];&lt;br /&gt;
  return monsterAttributes[monsterAttributes.length - 1];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterClass(selectedRace, classChoice, selectValueIsChanged = false) {&lt;br /&gt;
  for (var radioNode of classChoice) {&lt;br /&gt;
    var radioGrandParent = radioNode.parentElement.parentElement;&lt;br /&gt;
&lt;br /&gt;
    if (radioNode.getAttribute(&amp;quot;data-race&amp;quot;) === selectedRace) {&lt;br /&gt;
      if (!selectValueIsChanged) {&lt;br /&gt;
        radioNode.checked = true;&lt;br /&gt;
        selectValueIsChanged = true;&lt;br /&gt;
      }&lt;br /&gt;
      showElement(radioGrandParent);&lt;br /&gt;
    } else {&lt;br /&gt;
      hideElement(radioGrandParent);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterWeapon(&lt;br /&gt;
  selectedRace,&lt;br /&gt;
  weaponElement,&lt;br /&gt;
  weaponCategory,&lt;br /&gt;
  allowedWeaponsPerRace,&lt;br /&gt;
  selectValueIsChanged = false&lt;br /&gt;
) {&lt;br /&gt;
  var allowedWeapons = allowedWeaponsPerRace[selectedRace];&lt;br /&gt;
&lt;br /&gt;
  if (!selectValueIsChanged) {&lt;br /&gt;
    var weaponType = createWeapon(weaponElement.value).type;&lt;br /&gt;
&lt;br /&gt;
    if (!isValueInArray(weaponType, allowedWeapons)) {&lt;br /&gt;
      weaponElement.value = 0;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var children = weaponCategory.children;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; children.length; index++) {&lt;br /&gt;
    var child = children[index];&lt;br /&gt;
&lt;br /&gt;
    if (isValueInArray(index, allowedWeapons)) {&lt;br /&gt;
      showElement(child);&lt;br /&gt;
    } else {&lt;br /&gt;
      hideElement(child);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function changePolymorphValues(characterCreation, monsterVnum, monsterImage) {&lt;br /&gt;
  var { polymorphMonster, polymorphMonsterImage } = characterCreation;&lt;br /&gt;
&lt;br /&gt;
  polymorphMonster.value = monsterVnum;&lt;br /&gt;
  polymorphMonsterImage.value = monsterImage;&lt;br /&gt;
&lt;br /&gt;
  polymorphMonster.dispatchEvent(newChangeEvent());&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function resetImageFromWiki(image) {&lt;br /&gt;
  image.removeAttribute(&amp;quot;srcset&amp;quot;);&lt;br /&gt;
  image.removeAttribute(&amp;quot;data-file-width&amp;quot;);&lt;br /&gt;
  image.removeAttribute(&amp;quot;data-file-height&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleImageFromWiki(image, newSrc) {&lt;br /&gt;
  image.src = newSrc;&lt;br /&gt;
  image.alt = newSrc.split(&amp;quot;/&amp;quot;).pop();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handlePolymorphDisplay(polymorphDisplay, monsterVnum, monsterSrc) {&lt;br /&gt;
  var oldImage = polymorphDisplay.firstChild;&lt;br /&gt;
  var oldLink = oldImage.nextElementSibling;&lt;br /&gt;
  var monsterName = getMonsterName(monsterVnum);&lt;br /&gt;
  var newLink = createWikiLink(monsterName);&lt;br /&gt;
&lt;br /&gt;
  resetImageFromWiki(oldImage);&lt;br /&gt;
  handleImageFromWiki(oldImage, monsterSrc);&lt;br /&gt;
&lt;br /&gt;
  polymorphDisplay.replaceChild(newLink, oldLink);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createWikiLink(pageName) {&lt;br /&gt;
  var wikiLink = document.createElement(&amp;quot;a&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  wikiLink.href = mw.util.getUrl(pageName);&lt;br /&gt;
  wikiLink.title = pageName;&lt;br /&gt;
  wikiLink.textContent = pageName;&lt;br /&gt;
&lt;br /&gt;
  return wikiLink;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSelectedWeapon(weaponCategory) {&lt;br /&gt;
  return weaponCategory.querySelector(&amp;quot;input[type='radio']:checked&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleWeaponDisplay(&lt;br /&gt;
  weaponCategory,&lt;br /&gt;
  weaponDisplay,&lt;br /&gt;
  weaponVnum,&lt;br /&gt;
  newWeapon&lt;br /&gt;
) {&lt;br /&gt;
  var newWeapon = newWeapon || getSelectedWeapon(weaponCategory);&lt;br /&gt;
&lt;br /&gt;
  var newImage = newWeapon.nextElementSibling;&lt;br /&gt;
  var newText = document.createElement(&amp;quot;span&amp;quot;);&lt;br /&gt;
  var oldImage = weaponDisplay.firstChild;&lt;br /&gt;
  var oldText = oldImage.nextElementSibling;&lt;br /&gt;
  var weaponName = newImage.nextElementSibling.dataset.o;&lt;br /&gt;
&lt;br /&gt;
  if (weaponVnum == 0) {&lt;br /&gt;
    newText.textContent = weaponName;&lt;br /&gt;
  } else {&lt;br /&gt;
    var weaponLink = createWikiLink(weaponName);&lt;br /&gt;
    newText.appendChild(weaponLink);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  weaponDisplay.replaceChild(newImage.cloneNode(), oldImage);&lt;br /&gt;
  weaponDisplay.replaceChild(newText, oldText);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterUpgrade(&lt;br /&gt;
  weaponUpgrade,&lt;br /&gt;
  weaponVnum,&lt;br /&gt;
  randomAttackValue,&lt;br /&gt;
  randomMagicAttackValue&lt;br /&gt;
) {&lt;br /&gt;
  var weapon = createWeapon(weaponVnum);&lt;br /&gt;
  var currentUpgrade = Number(weaponUpgrade.value);&lt;br /&gt;
  var weaponUpgradeChildren = weaponUpgrade.children;&lt;br /&gt;
&lt;br /&gt;
  if (weapon.isSerpent) {&lt;br /&gt;
    showElement(randomAttackValue);&lt;br /&gt;
&lt;br /&gt;
    if (weapon.isMagic) {&lt;br /&gt;
      showElement(randomMagicAttackValue);&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    hideElement(randomAttackValue);&lt;br /&gt;
    hideElement(randomMagicAttackValue);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (weapon.maxUpgrade &amp;lt; 1) {&lt;br /&gt;
    hideElement(weaponUpgrade.parentElement);&lt;br /&gt;
  } else {&lt;br /&gt;
    showElement(weaponUpgrade.parentElement);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (var upgrade = 0; upgrade &amp;lt;= weapon.maxUpgrade; upgrade++) {&lt;br /&gt;
    showElement(weaponUpgradeChildren[upgrade]);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (&lt;br /&gt;
    var upgrade = weapon.maxUpgrade + 1;&lt;br /&gt;
    upgrade &amp;lt; weaponUpgradeChildren.length;&lt;br /&gt;
    upgrade++&lt;br /&gt;
  ) {&lt;br /&gt;
    hideElement(weaponUpgradeChildren[upgrade]);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (currentUpgrade &amp;gt; weapon.maxUpgrade) {&lt;br /&gt;
    weaponUpgrade.value = weapon.maxUpgrade;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterCheckbox(checkbox, element) {&lt;br /&gt;
  if (checkbox.checked) {&lt;br /&gt;
    showElement(element);&lt;br /&gt;
  } else {&lt;br /&gt;
    hideElement(element);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterSkills(selectedClass, skillElementsToFilter) {&lt;br /&gt;
  for (var element of skillElementsToFilter) {&lt;br /&gt;
    if (isValueInArray(selectedClass, element.dataset.class)) {&lt;br /&gt;
      showElement(element);&lt;br /&gt;
    } else {&lt;br /&gt;
      hideElement(element);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterForm(characters, battle) {&lt;br /&gt;
  var { saveButton, characterCreation, toggleSiblings } = characters;&lt;br /&gt;
  var allowedWeaponsPerRace = battle.constants.allowedWeaponsPerRace;&lt;br /&gt;
  var battleChoice = battle.battleChoice;&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;change&amp;quot;, function (event) {&lt;br /&gt;
    var target = event.target;&lt;br /&gt;
    var targetName = target.name;&lt;br /&gt;
&lt;br /&gt;
    saveButtonOrange(saveButton);&lt;br /&gt;
    characters.unsavedChanges = true;&lt;br /&gt;
&lt;br /&gt;
    switch (targetName) {&lt;br /&gt;
      case &amp;quot;race&amp;quot;:&lt;br /&gt;
        var selectedRace = target.value;&lt;br /&gt;
        var classChoice = characterCreation.class;&lt;br /&gt;
        var weaponElement = characterCreation.weapon;&lt;br /&gt;
&lt;br /&gt;
        filterClass(selectedRace, classChoice);&lt;br /&gt;
        filterWeapon(&lt;br /&gt;
          selectedRace,&lt;br /&gt;
          weaponElement,&lt;br /&gt;
          characters.weaponCategory,&lt;br /&gt;
          allowedWeaponsPerRace&lt;br /&gt;
        );&lt;br /&gt;
        handleWeaponDisplay(&lt;br /&gt;
          characters.weaponCategory,&lt;br /&gt;
          characters.weaponDisplay,&lt;br /&gt;
          weaponElement.value&lt;br /&gt;
        );&lt;br /&gt;
        filterUpgrade(&lt;br /&gt;
          characterCreation.weaponUpgrade,&lt;br /&gt;
          weaponElement.value,&lt;br /&gt;
          characters.randomAttackValue,&lt;br /&gt;
          characters.randomMagicAttackValue&lt;br /&gt;
        );&lt;br /&gt;
        filterSkills(classChoice.value, characters.skillElementsToFilter);&lt;br /&gt;
        handleBonusVariationUpdate(&lt;br /&gt;
          characterCreation,&lt;br /&gt;
          characters.bonusVariation,&lt;br /&gt;
          true&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        battleChoice.resetAttackType = true;&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;class&amp;quot;:&lt;br /&gt;
        filterSkills(target.value, characters.skillElementsToFilter);&lt;br /&gt;
        handleBonusVariationUpdate(&lt;br /&gt;
          characterCreation,&lt;br /&gt;
          characters.bonusVariation,&lt;br /&gt;
          true&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        battleChoice.resetAttackType = true;&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;weapon&amp;quot;:&lt;br /&gt;
        var weaponElement = characterCreation.weapon;&lt;br /&gt;
&lt;br /&gt;
        handleWeaponDisplay(&lt;br /&gt;
          characters.weaponCategory,&lt;br /&gt;
          characters.weaponDisplay,&lt;br /&gt;
          weaponElement.value,&lt;br /&gt;
          target&lt;br /&gt;
        );&lt;br /&gt;
        filterUpgrade(&lt;br /&gt;
          characterCreation.weaponUpgrade,&lt;br /&gt;
          target.value,&lt;br /&gt;
          characters.randomAttackValue,&lt;br /&gt;
          characters.randomMagicAttackValue&lt;br /&gt;
        );&lt;br /&gt;
        handleBonusVariationUpdate(&lt;br /&gt;
          characterCreation,&lt;br /&gt;
          characters.bonusVariation&lt;br /&gt;
        );&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;isRiding&amp;quot;:&lt;br /&gt;
        battleChoice.resetAttackType = true;&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;isPolymorph&amp;quot;:&lt;br /&gt;
        battleChoice.resetAttackType = true;&lt;br /&gt;
        break;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (toggleSiblings.hasOwnProperty(targetName)) {&lt;br /&gt;
      filterCheckbox(target, toggleSiblings[targetName]);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      targetName.startsWith(&amp;quot;attackSkill&amp;quot;) ||&lt;br /&gt;
      targetName.startsWith(&amp;quot;horseSkill&amp;quot;)&lt;br /&gt;
    ) {&lt;br /&gt;
      battleChoice.resetAttackType = true;&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addUniquePseudo(characterDataObject, savedCharactersPseudo) {&lt;br /&gt;
  var characterPseudo = String(characterDataObject.name);&lt;br /&gt;
  var originalPseudo = characterPseudo;&lt;br /&gt;
  var count = 0;&lt;br /&gt;
&lt;br /&gt;
  var regex = /(.*)(\d)$/;&lt;br /&gt;
  var match = characterPseudo.match(regex);&lt;br /&gt;
&lt;br /&gt;
  if (match) {&lt;br /&gt;
    originalPseudo = match[1];&lt;br /&gt;
    count = match[2];&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  while (isValueInArray(characterPseudo, savedCharactersPseudo)) {&lt;br /&gt;
    characterPseudo = originalPseudo + count;&lt;br /&gt;
    count++;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  characterDataObject.name = characterPseudo;&lt;br /&gt;
  return [characterDataObject, characterPseudo];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function convertToNumber(value) {&lt;br /&gt;
  var valueNumber = Number(value);&lt;br /&gt;
  return isNaN(valueNumber) ? value : valueNumber;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getLocalStorageValue(key, defaultValue) {&lt;br /&gt;
  var storedValue = localStorage.getItem(key);&lt;br /&gt;
&lt;br /&gt;
  if (storedValue) {&lt;br /&gt;
    return JSON.parse(storedValue);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return defaultValue;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSavedCharacters() {&lt;br /&gt;
  return getLocalStorageValue(&amp;quot;savedCharactersCalculator&amp;quot;, {});&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSavedMonsters() {&lt;br /&gt;
  var savedMonsters = getLocalStorageValue(&amp;quot;savedMonstersCalculator&amp;quot;, {});&lt;br /&gt;
&lt;br /&gt;
  if (Array.isArray(savedMonsters)) {&lt;br /&gt;
    return {};&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var filteredMonsters = {};&lt;br /&gt;
&lt;br /&gt;
  for (var vnum in savedMonsters) {&lt;br /&gt;
    if (&lt;br /&gt;
      String(Number(vnum)) === vnum &amp;amp;&amp;amp;&lt;br /&gt;
      savedMonsters[vnum].hasOwnProperty(&amp;quot;category&amp;quot;)&lt;br /&gt;
    ) {&lt;br /&gt;
      filteredMonsters[vnum] = savedMonsters[vnum];&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  updateSavedMonsters(filteredMonsters);&lt;br /&gt;
&lt;br /&gt;
  return filteredMonsters;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSavedFights() {&lt;br /&gt;
  return getLocalStorageValue(&amp;quot;savedFightsCalculator&amp;quot;, []);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveToLocalStorage(key, value) {&lt;br /&gt;
  localStorage.setItem(key, JSON.stringify(value));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateSavedCharacters(savedCharacters) {&lt;br /&gt;
  saveToLocalStorage(&amp;quot;savedCharactersCalculator&amp;quot;, savedCharacters);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateSavedMonsters(savedMonsters) {&lt;br /&gt;
  saveToLocalStorage(&amp;quot;savedMonstersCalculator&amp;quot;, savedMonsters);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateSavedFights(savedFights) {&lt;br /&gt;
  saveToLocalStorage(&amp;quot;savedFightsCalculator&amp;quot;, savedFights);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveCharacter(&lt;br /&gt;
  savedCharacters,&lt;br /&gt;
  characterCreation,&lt;br /&gt;
  battle,&lt;br /&gt;
  newCharacter,&lt;br /&gt;
  characterDataObject&lt;br /&gt;
) {&lt;br /&gt;
  if (!characterDataObject) {&lt;br /&gt;
    var characterData = new FormData(characterCreation);&lt;br /&gt;
    var characterDataObject = {};&lt;br /&gt;
&lt;br /&gt;
    characterData.forEach(function (value, key) {&lt;br /&gt;
      characterDataObject[key] = convertToNumber(value);&lt;br /&gt;
    });&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var characterPseudo = characterDataObject.name;&lt;br /&gt;
  var { battleChoice } = battle;&lt;br /&gt;
&lt;br /&gt;
  savedCharacters[characterPseudo] = characterDataObject;&lt;br /&gt;
  updateSavedCharacters(savedCharacters);&lt;br /&gt;
&lt;br /&gt;
  if (newCharacter) {&lt;br /&gt;
    addBattleChoice(battleChoice, characterPseudo, characterDataObject);&lt;br /&gt;
  } else {&lt;br /&gt;
    updateBattleChoiceImage(&lt;br /&gt;
      battleChoice,&lt;br /&gt;
      characterPseudo,&lt;br /&gt;
      characterDataObject.race&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (battleChoice.resetAttackType) {&lt;br /&gt;
    if (isCharacterSelected(characterPseudo, battleChoice.attacker.selected)) {&lt;br /&gt;
      filterAttackTypeSelectionCharacter(&lt;br /&gt;
        characterDataObject,&lt;br /&gt;
        battleChoice.attackType&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
    battleChoice.resetAttackType = false;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveButtonGreen(saveButton) {&lt;br /&gt;
  saveButton.classList.remove(&amp;quot;unsaved-character&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveButtonOrange(saveButton) {&lt;br /&gt;
  saveButton.classList.add(&amp;quot;unsaved-character&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function characterCreationListener(characters, battle) {&lt;br /&gt;
  var { characterCreation, saveButton, weaponCategory } = characters;&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;submit&amp;quot;, handleSubmitForm);&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;invalid&amp;quot;, handleInvalidInput, true);&lt;br /&gt;
  document.addEventListener(&amp;quot;keydown&amp;quot;, handleSaveShortcut);&lt;br /&gt;
  weaponCategory.addEventListener(&amp;quot;mouseover&amp;quot;, handleTooltipOverflow);&lt;br /&gt;
&lt;br /&gt;
  function handleSubmitForm(event) {&lt;br /&gt;
    event.preventDefault();&lt;br /&gt;
&lt;br /&gt;
    if (characters.unsavedChanges) {&lt;br /&gt;
      saveCharacter(characters.savedCharacters, characterCreation, battle);&lt;br /&gt;
      saveButtonGreen(saveButton);&lt;br /&gt;
      characters.unsavedChanges = false;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function handleInvalidInput(event) {&lt;br /&gt;
    var target = event.target;&lt;br /&gt;
&lt;br /&gt;
    if (target.checkVisibility()) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var autoCorrectInput = target.closest(&amp;quot;.auto-correct-input&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      autoCorrectInput &amp;amp;&amp;amp;&lt;br /&gt;
      autoCorrectInput.classList.contains(&amp;quot;tabber-noactive&amp;quot;)&lt;br /&gt;
    ) {&lt;br /&gt;
      target.value = target.defaultValue;&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    openTargetTab(target);&lt;br /&gt;
    openTargetCollapsible(target);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function handleSaveShortcut(event) {&lt;br /&gt;
    if (event.ctrlKey &amp;amp;&amp;amp; event.key === &amp;quot;s&amp;quot;) {&lt;br /&gt;
      event.preventDefault();&lt;br /&gt;
      saveButton.click();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function handleTooltipOverflow(event) {&lt;br /&gt;
    var label = event.target.closest(&amp;quot;label&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (label) {&lt;br /&gt;
      var tooltip = label.lastChild;&lt;br /&gt;
&lt;br /&gt;
      if (tooltip.classList.contains(&amp;quot;popContenu&amp;quot;)) {&lt;br /&gt;
        var tooltipRect = tooltip.getBoundingClientRect();&lt;br /&gt;
        var modalRect = weaponCategory.getBoundingClientRect();&lt;br /&gt;
&lt;br /&gt;
        if (tooltipRect.right &amp;gt; modalRect.right) {&lt;br /&gt;
          tooltip.style.left = &amp;quot;-100%&amp;quot;;&lt;br /&gt;
        } else if (tooltipRect.left &amp;lt; modalRect.left) {&lt;br /&gt;
          tooltip.style.left = &amp;quot;200%&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function downloadData(content, type, filename) {&lt;br /&gt;
  var link = document.createElement(&amp;quot;a&amp;quot;);&lt;br /&gt;
  var blob = new Blob([content], { type: type });&lt;br /&gt;
  var blobURL = URL.createObjectURL(blob);&lt;br /&gt;
&lt;br /&gt;
  link.href = blobURL;&lt;br /&gt;
  link.download = filename;&lt;br /&gt;
  document.body.appendChild(link);&lt;br /&gt;
&lt;br /&gt;
  link.click();&lt;br /&gt;
  document.body.removeChild(link);&lt;br /&gt;
  URL.revokeObjectURL(blobURL);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function uploadCharacter(&lt;br /&gt;
  selectedFiles,&lt;br /&gt;
  characters,&lt;br /&gt;
  characterTemplate,&lt;br /&gt;
  charactersContainer,&lt;br /&gt;
  battle&lt;br /&gt;
) {&lt;br /&gt;
  var selectFilesLength = selectedFiles.length;&lt;br /&gt;
&lt;br /&gt;
  for (var fileIndex = 0; fileIndex &amp;lt; selectFilesLength; fileIndex++) {&lt;br /&gt;
    var selectedFile = selectedFiles[fileIndex];&lt;br /&gt;
&lt;br /&gt;
    if (selectedFile.type === &amp;quot;text/plain&amp;quot;) {&lt;br /&gt;
      var reader = new FileReader();&lt;br /&gt;
      reader.onload = function (e) {&lt;br /&gt;
        var fileContent = e.target.result;&lt;br /&gt;
        try {&lt;br /&gt;
          var characterDataObject = JSON.parse(fileContent);&lt;br /&gt;
&lt;br /&gt;
          if (characterDataObject.hasOwnProperty(&amp;quot;name&amp;quot;)) {&lt;br /&gt;
            var characterPseudo = String(characterDataObject.name);&lt;br /&gt;
&lt;br /&gt;
            hideElement(characters.characterCreation);&lt;br /&gt;
            characterPseudo = validPseudo(characterPseudo);&lt;br /&gt;
&lt;br /&gt;
            [characterDataObject, characterPseudo] = addUniquePseudo(&lt;br /&gt;
              characterDataObject,&lt;br /&gt;
              Object.keys(characters.savedCharacters)&lt;br /&gt;
            );&lt;br /&gt;
            var selectedCharacter = handleNewCharacter(&lt;br /&gt;
              characters,&lt;br /&gt;
              characterTemplate,&lt;br /&gt;
              charactersContainer,&lt;br /&gt;
              battle,&lt;br /&gt;
              characterPseudo&lt;br /&gt;
            )[0];&lt;br /&gt;
&lt;br /&gt;
            if (selectFilesLength === 1) {&lt;br /&gt;
              updateForm(&lt;br /&gt;
                characterDataObject,&lt;br /&gt;
                characters.characterCreation,&lt;br /&gt;
                characters,&lt;br /&gt;
                selectedCharacter,&lt;br /&gt;
                battle&lt;br /&gt;
              );&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            saveCharacter(&lt;br /&gt;
              characters.savedCharacters,&lt;br /&gt;
              characters.characterCreation,&lt;br /&gt;
              battle,&lt;br /&gt;
              true,&lt;br /&gt;
              characterDataObject&lt;br /&gt;
            );&lt;br /&gt;
          }&lt;br /&gt;
        } catch (error) {&lt;br /&gt;
          console.log(error);&lt;br /&gt;
          if (error.name === &amp;quot;TypeError&amp;quot;) {&lt;br /&gt;
            // delete the character&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
      };&lt;br /&gt;
      reader.readAsText(selectedFile);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleUploadCharacter(&lt;br /&gt;
  characters,&lt;br /&gt;
  characterTemplate,&lt;br /&gt;
  charactersContainer,&lt;br /&gt;
  battle&lt;br /&gt;
) {&lt;br /&gt;
  var characterInput = characters.characterInput;&lt;br /&gt;
  var dropZone = characters.dropZone;&lt;br /&gt;
&lt;br /&gt;
  characterInput.accept = &amp;quot;.txt&amp;quot;;&lt;br /&gt;
  characterInput.multiple = true;&lt;br /&gt;
  dropZone.setAttribute(&amp;quot;tabindex&amp;quot;, &amp;quot;0&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  dropZone.addEventListener(&amp;quot;click&amp;quot;, function () {&lt;br /&gt;
    characterInput.click();&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  dropZone.addEventListener(&amp;quot;dragover&amp;quot;, function (event) {&lt;br /&gt;
    event.preventDefault();&lt;br /&gt;
    dropZone.classList.add(&amp;quot;drop-zone--dragover&amp;quot;);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  [&amp;quot;dragleave&amp;quot;, &amp;quot;dragend&amp;quot;].forEach(function (type) {&lt;br /&gt;
    dropZone.addEventListener(type, function () {&lt;br /&gt;
      dropZone.classList.remove(&amp;quot;drop-zone--dragover&amp;quot;);&lt;br /&gt;
    });&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  dropZone.addEventListener(&amp;quot;drop&amp;quot;, function (event) {&lt;br /&gt;
    event.preventDefault();&lt;br /&gt;
    uploadCharacter(&lt;br /&gt;
      event.dataTransfer.files,&lt;br /&gt;
      characters,&lt;br /&gt;
      characterTemplate,&lt;br /&gt;
      charactersContainer,&lt;br /&gt;
      battle&lt;br /&gt;
    );&lt;br /&gt;
    dropZone.classList.remove(&amp;quot;drop-zone--dragover&amp;quot;);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  characterInput.addEventListener(&amp;quot;change&amp;quot;, function (event) {&lt;br /&gt;
    uploadCharacter(&lt;br /&gt;
      event.target.files,&lt;br /&gt;
      characters,&lt;br /&gt;
      characterTemplate,&lt;br /&gt;
      charactersContainer,&lt;br /&gt;
      battle&lt;br /&gt;
    );&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function deleteCharacter(characters, pseudo, element, battle) {&lt;br /&gt;
  delete characters.savedCharacters[pseudo];&lt;br /&gt;
  element.remove();&lt;br /&gt;
&lt;br /&gt;
  updateSavedCharacters(characters.savedCharacters);&lt;br /&gt;
  removeBattleChoice(battle.battleChoice, pseudo, &amp;quot;character&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (&lt;br /&gt;
    !Object.keys(characters.savedCharacters).length ||&lt;br /&gt;
    characters.characterCreation.name.value === pseudo&lt;br /&gt;
  ) {&lt;br /&gt;
    saveButtonGreen(characters.saveButton);&lt;br /&gt;
    characters.unsavedChanges = false;&lt;br /&gt;
    hideElement(characters.characterCreation);&lt;br /&gt;
    showElement(characters.characterCreation.previousElementSibling);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function deleteMonster(characters, battle, monsterVnum) {&lt;br /&gt;
  var monsterElements = characters.monsterElements;&lt;br /&gt;
  var monsterType = characters.savedMonsters[monsterVnum].category;&lt;br /&gt;
&lt;br /&gt;
  if (monsterElements.hasOwnProperty(monsterVnum)) {&lt;br /&gt;
    monsterElements[monsterVnum].remove();&lt;br /&gt;
    delete monsterElements[monsterVnum];&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  delete characters.savedMonsters[monsterVnum];&lt;br /&gt;
&lt;br /&gt;
  updateSavedMonsters(characters.savedMonsters);&lt;br /&gt;
  removeBattleChoice(battle.battleChoice, monsterVnum, monsterType);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleStyle(characters, selectedElement) {&lt;br /&gt;
  var currentCharacter = characters.currentCharacter;&lt;br /&gt;
&lt;br /&gt;
  if (currentCharacter) {&lt;br /&gt;
    currentCharacter.classList.remove(&amp;quot;selected-character&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  selectedElement.classList.add(&amp;quot;selected-character&amp;quot;);&lt;br /&gt;
  characters.currentCharacter = selectedElement;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateForm(&lt;br /&gt;
  formData,&lt;br /&gt;
  characterCreation,&lt;br /&gt;
  characters,&lt;br /&gt;
  selectedElement,&lt;br /&gt;
  battle&lt;br /&gt;
) {&lt;br /&gt;
  saveButtonGreen(characters.saveButton);&lt;br /&gt;
  hideElement(characterCreation.previousElementSibling);&lt;br /&gt;
  showElement(characterCreation);&lt;br /&gt;
  handleStyle(characters, selectedElement);&lt;br /&gt;
&lt;br /&gt;
  characterCreation.reset();&lt;br /&gt;
&lt;br /&gt;
  for (var [name, value] of Object.entries(formData)) {&lt;br /&gt;
    var formElement = characterCreation[name];&lt;br /&gt;
&lt;br /&gt;
    if (!formElement) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (formElement.type === &amp;quot;checkbox&amp;quot;) {&lt;br /&gt;
      if (isChecked(value)) {&lt;br /&gt;
        formElement.checked = true;&lt;br /&gt;
      }&lt;br /&gt;
    } else {&lt;br /&gt;
      formElement.value = value;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  var selectedRace = characterCreation.race.value;&lt;br /&gt;
  var classChoice = characterCreation.class;&lt;br /&gt;
  var weaponElement = characterCreation.weapon;&lt;br /&gt;
&lt;br /&gt;
  filterClass(selectedRace, classChoice, true);&lt;br /&gt;
  filterWeapon(&lt;br /&gt;
    selectedRace,&lt;br /&gt;
    weaponElement,&lt;br /&gt;
    characters.weaponCategory,&lt;br /&gt;
    battle.constants.allowedWeaponsPerRace,&lt;br /&gt;
    true&lt;br /&gt;
  );&lt;br /&gt;
  handlePolymorphDisplay(&lt;br /&gt;
    characters.polymorphDisplay,&lt;br /&gt;
    characterCreation.polymorphMonster.value,&lt;br /&gt;
    characterCreation.polymorphMonsterImage.value&lt;br /&gt;
  );&lt;br /&gt;
  handleWeaponDisplay(&lt;br /&gt;
    characters.weaponCategory,&lt;br /&gt;
    characters.weaponDisplay,&lt;br /&gt;
    weaponElement.value&lt;br /&gt;
  );&lt;br /&gt;
  filterUpgrade(&lt;br /&gt;
    characterCreation.weaponUpgrade,&lt;br /&gt;
    weaponElement.value,&lt;br /&gt;
    characters.randomAttackValue,&lt;br /&gt;
    characters.randomMagicAttackValue&lt;br /&gt;
  );&lt;br /&gt;
  for (var [targetName, sibling] of Object.entries(characters.toggleSiblings)) {&lt;br /&gt;
    filterCheckbox(characterCreation[targetName], sibling);&lt;br /&gt;
  }&lt;br /&gt;
  filterSkills(classChoice.value, characters.skillElementsToFilter);&lt;br /&gt;
  handleBonusVariationUpdate(characterCreation, characters.bonusVariation);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleClickOnCharacter(&lt;br /&gt;
  spanInput,&lt;br /&gt;
  target,&lt;br /&gt;
  characters,&lt;br /&gt;
  characterElement,&lt;br /&gt;
  battle,&lt;br /&gt;
  edition&lt;br /&gt;
) {&lt;br /&gt;
  var displayedPseudo = characters.characterCreation.name.value;&lt;br /&gt;
  var pseudo = spanInput.dataset.name;&lt;br /&gt;
&lt;br /&gt;
  if (edition) {&lt;br /&gt;
    if (!characters.unsavedChanges) {&lt;br /&gt;
      updateForm(&lt;br /&gt;
        characters.savedCharacters[pseudo],&lt;br /&gt;
        characters.characterCreation,&lt;br /&gt;
        characters,&lt;br /&gt;
        characterElement,&lt;br /&gt;
        battle&lt;br /&gt;
      );&lt;br /&gt;
    } else if (displayedPseudo === pseudo) {&lt;br /&gt;
      // pass&lt;br /&gt;
    } else {&lt;br /&gt;
      var result = confirm(&lt;br /&gt;
        &amp;quot;Voulez-vous continuer ? Les dernières modifications ne seront pas sauvegardées.&amp;quot;&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      if (result) {&lt;br /&gt;
        updateForm(&lt;br /&gt;
          characters.savedCharacters[pseudo],&lt;br /&gt;
          characters.characterCreation,&lt;br /&gt;
          characters,&lt;br /&gt;
          characterElement,&lt;br /&gt;
          battle&lt;br /&gt;
        );&lt;br /&gt;
        characters.unsavedChanges = false;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    if (target.tagName === &amp;quot;path&amp;quot;) {&lt;br /&gt;
      target = target.parentElement;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    switch (target.dataset.icon) {&lt;br /&gt;
      case &amp;quot;duplicate&amp;quot;:&lt;br /&gt;
        if (!characters.unsavedChanges) {&lt;br /&gt;
          addNewCharacter(&lt;br /&gt;
            characters,&lt;br /&gt;
            characters.newCharacterTemplate,&lt;br /&gt;
            characters.charactersContainer,&lt;br /&gt;
            battle,&lt;br /&gt;
            pseudo&lt;br /&gt;
          );&lt;br /&gt;
        } else {&lt;br /&gt;
          var result = confirm(&lt;br /&gt;
            &amp;quot;Voulez-vous continuer ? Les dernières modifications ne seront pas sauvegardées.&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
&lt;br /&gt;
          if (result) {&lt;br /&gt;
            addNewCharacter(&lt;br /&gt;
              characters,&lt;br /&gt;
              characters.newCharacterTemplate,&lt;br /&gt;
              characters.charactersContainer,&lt;br /&gt;
              battle,&lt;br /&gt;
              pseudo&lt;br /&gt;
            );&lt;br /&gt;
            saveButtonGreen(characters.saveButton);&lt;br /&gt;
            characters.unsavedChanges = false;&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
        break;&lt;br /&gt;
&lt;br /&gt;
      case &amp;quot;download&amp;quot;:&lt;br /&gt;
        var character = characters.savedCharacters[pseudo];&lt;br /&gt;
        downloadData(&lt;br /&gt;
          JSON.stringify(character),&lt;br /&gt;
          &amp;quot;text/plain&amp;quot;,&lt;br /&gt;
          character.name + &amp;quot;.txt&amp;quot;&lt;br /&gt;
        );&lt;br /&gt;
        break;&lt;br /&gt;
&lt;br /&gt;
      case &amp;quot;delete&amp;quot;:&lt;br /&gt;
        var result = confirm(&lt;br /&gt;
          &amp;quot;Voulez-vous vraiment supprimer définitivement le personnage &amp;quot; +&lt;br /&gt;
            pseudo +&lt;br /&gt;
            &amp;quot; ?&amp;quot;&lt;br /&gt;
        );&lt;br /&gt;
        if (result) {&lt;br /&gt;
          deleteCharacter(characters, pseudo, characterElement, battle);&lt;br /&gt;
        }&lt;br /&gt;
        break;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleNewCharacter(&lt;br /&gt;
  characters,&lt;br /&gt;
  characterTemplate,&lt;br /&gt;
  charactersContainer,&lt;br /&gt;
  battle,&lt;br /&gt;
  pseudo&lt;br /&gt;
) {&lt;br /&gt;
  var newCharacterTemplate = characterTemplate.cloneNode(true);&lt;br /&gt;
  var spanInput = newCharacterTemplate.querySelector(&amp;quot;span.input&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  newCharacterTemplate.setAttribute(&amp;quot;tabindex&amp;quot;, &amp;quot;0&amp;quot;);&lt;br /&gt;
  charactersContainer.appendChild(newCharacterTemplate);&lt;br /&gt;
&lt;br /&gt;
  if (pseudo) {&lt;br /&gt;
    spanInput.textContent = pseudo;&lt;br /&gt;
    spanInput.setAttribute(&amp;quot;data-name&amp;quot;, pseudo);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  newCharacterTemplate.addEventListener(&amp;quot;click&amp;quot;, function (event) {&lt;br /&gt;
    var target = event.target;&lt;br /&gt;
&lt;br /&gt;
    if (target.tagName === &amp;quot;path&amp;quot; || target.tagName === &amp;quot;svg&amp;quot;) {&lt;br /&gt;
      handleClickOnCharacter(&lt;br /&gt;
        spanInput,&lt;br /&gt;
        target,&lt;br /&gt;
        characters,&lt;br /&gt;
        newCharacterTemplate,&lt;br /&gt;
        battle&lt;br /&gt;
      );&lt;br /&gt;
    } else {&lt;br /&gt;
      handleClickOnCharacter(&lt;br /&gt;
        spanInput,&lt;br /&gt;
        null,&lt;br /&gt;
        characters,&lt;br /&gt;
        newCharacterTemplate,&lt;br /&gt;
        battle,&lt;br /&gt;
        true&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  newCharacterTemplate.addEventListener(&amp;quot;keydown&amp;quot;, function (event) {&lt;br /&gt;
    if (event.keyCode === 13) {&lt;br /&gt;
      event.target.click();&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  return [newCharacterTemplate, spanInput];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function validPseudo(pseudo) {&lt;br /&gt;
  var newPseudo = pseudoFormat(pseudo);&lt;br /&gt;
&lt;br /&gt;
  if (!newPseudo) {&lt;br /&gt;
    return &amp;quot;Pseudo&amp;quot;;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return newPseudo;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addNewCharacter(&lt;br /&gt;
  characters,&lt;br /&gt;
  characterTemplate,&lt;br /&gt;
  charactersContainer,&lt;br /&gt;
  battle,&lt;br /&gt;
  pseudoToDuplicate&lt;br /&gt;
) {&lt;br /&gt;
  function editAndSetCharacterPseudoInput(selectedCharacter, spanInput) {&lt;br /&gt;
    var maxPseudoLength = 20;&lt;br /&gt;
&lt;br /&gt;
    var selection = window.getSelection();&lt;br /&gt;
    var range = document.createRange();&lt;br /&gt;
&lt;br /&gt;
    if (pseudoToDuplicate) {&lt;br /&gt;
      spanInput.textContent = pseudoToDuplicate;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    spanInput.contentEditable = true;&lt;br /&gt;
    spanInput.focus();&lt;br /&gt;
    range.selectNodeContents(spanInput);&lt;br /&gt;
    selection.removeAllRanges();&lt;br /&gt;
    selection.addRange(range);&lt;br /&gt;
&lt;br /&gt;
    function pseudoValidation() {&lt;br /&gt;
      var characterPseudo = validPseudo(spanInput.textContent);&lt;br /&gt;
      var characterDataObject = { name: characterPseudo };&lt;br /&gt;
&lt;br /&gt;
      if (pseudoToDuplicate) {&lt;br /&gt;
        characterDataObject = copyObject(&lt;br /&gt;
          characters.savedCharacters[pseudoToDuplicate]&lt;br /&gt;
        );&lt;br /&gt;
        characterDataObject.name = characterPseudo;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      [characterDataObject, characterPseudo] = addUniquePseudo(&lt;br /&gt;
        characterDataObject,&lt;br /&gt;
        Object.keys(characters.savedCharacters)&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      selection.removeAllRanges();&lt;br /&gt;
      spanInput.contentEditable = false;&lt;br /&gt;
      spanInput.textContent = characterPseudo;&lt;br /&gt;
      spanInput.setAttribute(&amp;quot;data-name&amp;quot;, characterPseudo);&lt;br /&gt;
&lt;br /&gt;
      updateForm(&lt;br /&gt;
        characterDataObject,&lt;br /&gt;
        characters.characterCreation,&lt;br /&gt;
        characters,&lt;br /&gt;
        selectedCharacter,&lt;br /&gt;
        battle&lt;br /&gt;
      );&lt;br /&gt;
      saveCharacter(&lt;br /&gt;
        characters.savedCharacters,&lt;br /&gt;
        characters.characterCreation,&lt;br /&gt;
        battle,&lt;br /&gt;
        true&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handleMaxLength(event) {&lt;br /&gt;
      if (spanInput.textContent.length &amp;gt; maxPseudoLength) {&lt;br /&gt;
        spanInput.textContent = spanInput.textContent.slice(0, maxPseudoLength);&lt;br /&gt;
        range.setStart(spanInput.childNodes[0], maxPseudoLength);&lt;br /&gt;
        selection.removeAllRanges();&lt;br /&gt;
        selection.addRange(range);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handleBlur() {&lt;br /&gt;
      spanInput.removeEventListener(&amp;quot;blur&amp;quot;, handleBlur);&lt;br /&gt;
      spanInput.removeEventListener(&amp;quot;input&amp;quot;, handleMaxLength);&lt;br /&gt;
      pseudoValidation();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handleKeyDown(event) {&lt;br /&gt;
      if (event.key === &amp;quot;Enter&amp;quot;) {&lt;br /&gt;
        event.preventDefault();&lt;br /&gt;
&lt;br /&gt;
        spanInput.removeEventListener(&amp;quot;keydown&amp;quot;, handleKeyDown);&lt;br /&gt;
        spanInput.removeEventListener(&amp;quot;blur&amp;quot;, handleBlur);&lt;br /&gt;
        spanInput.removeEventListener(&amp;quot;input&amp;quot;, handleMaxLength);&lt;br /&gt;
&lt;br /&gt;
        pseudoValidation();&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    spanInput.addEventListener(&amp;quot;input&amp;quot;, handleMaxLength);&lt;br /&gt;
    spanInput.addEventListener(&amp;quot;keydown&amp;quot;, handleKeyDown);&lt;br /&gt;
    spanInput.addEventListener(&amp;quot;blur&amp;quot;, handleBlur);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  hideElement(characters.characterCreation);&lt;br /&gt;
  var [selectedCharacter, spanInput] = handleNewCharacter(&lt;br /&gt;
    characters,&lt;br /&gt;
    characterTemplate,&lt;br /&gt;
    charactersContainer,&lt;br /&gt;
    battle&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  editAndSetCharacterPseudoInput(selectedCharacter, spanInput);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleFocus() {&lt;br /&gt;
  var tooltipLinks = document.querySelectorAll(&amp;quot;div.tooltip a&amp;quot;);&lt;br /&gt;
  tooltipLinks.forEach(function (link) {&lt;br /&gt;
    link.setAttribute(&amp;quot;tabindex&amp;quot;, -1);&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function resetBonusVariation(bonusVariation) {&lt;br /&gt;
  function resetInput(input) {&lt;br /&gt;
    input.removeAttribute(&amp;quot;min&amp;quot;);&lt;br /&gt;
    input.removeAttribute(&amp;quot;max&amp;quot;);&lt;br /&gt;
    input.defaultValue = 0;&lt;br /&gt;
    input.value = input.defaultValue;&lt;br /&gt;
  }&lt;br /&gt;
  var { minValue, maxValue, checkbox, container, disabledText, selectedText } =&lt;br /&gt;
    bonusVariation;&lt;br /&gt;
&lt;br /&gt;
  resetInput(minValue);&lt;br /&gt;
  resetInput(maxValue);&lt;br /&gt;
  showElement(disabledText);&lt;br /&gt;
  hideElement(selectedText);&lt;br /&gt;
  hideElement(container);&lt;br /&gt;
  checkbox.checked = false;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleBonusVariationUpdate(&lt;br /&gt;
  characterCreation,&lt;br /&gt;
  bonusVariation,&lt;br /&gt;
  resetSkill&lt;br /&gt;
) {&lt;br /&gt;
  var selectedBonus = characterCreation.bonusVariation.value;&lt;br /&gt;
  var displayName = characterCreation.bonusVariationName.value;&lt;br /&gt;
&lt;br /&gt;
  if (&lt;br /&gt;
    resetSkill &amp;amp;&amp;amp;&lt;br /&gt;
    (selectedBonus.startsWith(&amp;quot;attackSkill&amp;quot;) ||&lt;br /&gt;
      selectedBonus.startsWith(&amp;quot;horseSkill&amp;quot;) ||&lt;br /&gt;
      selectedBonus.startsWith(&amp;quot;skillBonus&amp;quot;))&lt;br /&gt;
  ) {&lt;br /&gt;
    resetBonusVariation(bonusVariation);&lt;br /&gt;
    return;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (&lt;br /&gt;
    characterCreation.hasOwnProperty(selectedBonus) &amp;amp;&amp;amp;&lt;br /&gt;
    selectedBonus != 0 &amp;amp;&amp;amp;&lt;br /&gt;
    displayName != 0&lt;br /&gt;
  ) {&lt;br /&gt;
    handleBonusVariation(&lt;br /&gt;
      characterCreation[selectedBonus],&lt;br /&gt;
      bonusVariation,&lt;br /&gt;
      displayName&lt;br /&gt;
    );&lt;br /&gt;
  } else {&lt;br /&gt;
    resetBonusVariation(bonusVariation);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getTargetContent(targetParent, targetName, isSkill) {&lt;br /&gt;
  var targetContent = &amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  if (targetParent.children.length &amp;lt;= 1) {&lt;br /&gt;
    targetContent = targetParent.textContent;&lt;br /&gt;
  } else if (targetName === &amp;quot;weaponUpgrade&amp;quot;) {&lt;br /&gt;
    targetContent = targetParent.children[1].textContent;&lt;br /&gt;
  } else if (targetName === &amp;quot;level&amp;quot;) {&lt;br /&gt;
    targetContent = targetParent.textContent.replace(&amp;quot;Lv&amp;quot;, &amp;quot;&amp;quot;).trim();&lt;br /&gt;
  } else if (isSkill) {&lt;br /&gt;
    var container = targetParent.children[1];&lt;br /&gt;
&lt;br /&gt;
    for (var index = 0; index &amp;lt; container.children.length; index++) {&lt;br /&gt;
      var element = container.children[index];&lt;br /&gt;
&lt;br /&gt;
      if (element.checkVisibility()) {&lt;br /&gt;
        targetContent += element.textContent;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    for (var index = 1; index &amp;lt; targetParent.children.length; index++) {&lt;br /&gt;
      var element = targetParent.children[index];&lt;br /&gt;
&lt;br /&gt;
      if (element.checkVisibility()) {&lt;br /&gt;
        targetContent += element.textContent;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return targetContent.trim();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleBonusVariation(target, bonusVariation, displayName) {&lt;br /&gt;
  var {&lt;br /&gt;
    minValue,&lt;br /&gt;
    maxValue,&lt;br /&gt;
    checkbox,&lt;br /&gt;
    container,&lt;br /&gt;
    disabledText,&lt;br /&gt;
    selectedText,&lt;br /&gt;
    displaySpan,&lt;br /&gt;
  } = bonusVariation;&lt;br /&gt;
&lt;br /&gt;
  var {&lt;br /&gt;
    min: targetMin,&lt;br /&gt;
    max: targetMax,&lt;br /&gt;
    name: targetName,&lt;br /&gt;
    value: targetValue,&lt;br /&gt;
    parentElement: targetParent,&lt;br /&gt;
    tagName,&lt;br /&gt;
  } = target;&lt;br /&gt;
&lt;br /&gt;
  targetMin = Number(targetMin);&lt;br /&gt;
  targetMax = Number(targetMax);&lt;br /&gt;
  targetValue = Number(targetValue);&lt;br /&gt;
&lt;br /&gt;
  var isSkill = tagName === &amp;quot;SELECT&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  if (isSkill) {&lt;br /&gt;
    var options = target.options;&lt;br /&gt;
&lt;br /&gt;
    targetMin = options[0].value;&lt;br /&gt;
    targetMax = options[options.length - 1].value;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  minValue.min = targetMin;&lt;br /&gt;
  minValue.max = targetMax;&lt;br /&gt;
  minValue.defaultValue = targetMin;&lt;br /&gt;
&lt;br /&gt;
  maxValue.min = targetMin;&lt;br /&gt;
  maxValue.max = targetMax;&lt;br /&gt;
  maxValue.defaultValue = targetMin;&lt;br /&gt;
&lt;br /&gt;
  hideElement(disabledText);&lt;br /&gt;
  showElement(selectedText);&lt;br /&gt;
&lt;br /&gt;
  if (displayName) {&lt;br /&gt;
    minValue.value = Math.min(Math.max(minValue.value, targetMin), targetMax);&lt;br /&gt;
    maxValue.value = Math.max(Math.min(maxValue.value, targetMax), targetMin);&lt;br /&gt;
&lt;br /&gt;
    displaySpan.textContent = displayName;&lt;br /&gt;
  } else {&lt;br /&gt;
    var { input, inputName, tabButton } = bonusVariation;&lt;br /&gt;
    var targetContent = getTargetContent(targetParent, targetName, isSkill);&lt;br /&gt;
&lt;br /&gt;
    input.value = targetName;&lt;br /&gt;
    inputName.value = targetContent;&lt;br /&gt;
    displaySpan.textContent = targetContent;&lt;br /&gt;
&lt;br /&gt;
    minValue.value = Math.max(targetValue - 10, targetMin);&lt;br /&gt;
    maxValue.value = Math.min(targetValue + 10, targetMax);&lt;br /&gt;
&lt;br /&gt;
    showElement(container);&lt;br /&gt;
    checkbox.checked = true;&lt;br /&gt;
&lt;br /&gt;
    tabButton.click();&lt;br /&gt;
    tabButton.scrollIntoView(true);&lt;br /&gt;
&lt;br /&gt;
    input.dispatchEvent(newChangeEvent());&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function characterManagement(characters, battle) {&lt;br /&gt;
  var {&lt;br /&gt;
    newCharacterTemplate: characterTemplate,&lt;br /&gt;
    charactersContainer,&lt;br /&gt;
    addNewCharacterButton,&lt;br /&gt;
    saveButton,&lt;br /&gt;
    characterCreation,&lt;br /&gt;
    bonusVariation,&lt;br /&gt;
  } = characters;&lt;br /&gt;
&lt;br /&gt;
  Object.keys(characters.savedCharacters).forEach(function (pseudo) {&lt;br /&gt;
    handleNewCharacter(&lt;br /&gt;
      characters,&lt;br /&gt;
      characterTemplate,&lt;br /&gt;
      charactersContainer,&lt;br /&gt;
      battle,&lt;br /&gt;
      pseudo&lt;br /&gt;
    );&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  addNewCharacterButton.addEventListener(&amp;quot;click&amp;quot;, function (event) {&lt;br /&gt;
    if (!characters.unsavedChanges) {&lt;br /&gt;
      addNewCharacter(&lt;br /&gt;
        characters,&lt;br /&gt;
        characterTemplate,&lt;br /&gt;
        charactersContainer,&lt;br /&gt;
        battle&lt;br /&gt;
      );&lt;br /&gt;
    } else {&lt;br /&gt;
      var result = confirm(&lt;br /&gt;
        &amp;quot;Voulez-vous continuer ? Les dernières modifications ne seront pas sauvegardées.&amp;quot;&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      if (result) {&lt;br /&gt;
        addNewCharacter(&lt;br /&gt;
          characters,&lt;br /&gt;
          characterTemplate,&lt;br /&gt;
          charactersContainer,&lt;br /&gt;
          battle&lt;br /&gt;
        );&lt;br /&gt;
        saveButtonGreen(saveButton);&lt;br /&gt;
        characters.unsavedChanges = false;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  handleUploadCharacter(&lt;br /&gt;
    characters,&lt;br /&gt;
    characterTemplate,&lt;br /&gt;
    charactersContainer,&lt;br /&gt;
    battle&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  function handleLongPress(target) {&lt;br /&gt;
    if (target.tagName !== &amp;quot;INPUT&amp;quot; &amp;amp;&amp;amp; target.tagName !== &amp;quot;SELECT&amp;quot;) {&lt;br /&gt;
      target = target.querySelector(&amp;quot;input&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      !target ||&lt;br /&gt;
      (target.type !== &amp;quot;number&amp;quot; &amp;amp;&amp;amp;&lt;br /&gt;
        !target.classList.contains(&amp;quot;skill-select&amp;quot;) &amp;amp;&amp;amp;&lt;br /&gt;
        target.name !== &amp;quot;weaponUpgrade&amp;quot;) ||&lt;br /&gt;
      target.classList.contains(&amp;quot;disabled-variation&amp;quot;)&lt;br /&gt;
    ) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    handleBonusVariation(target, bonusVariation, null);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;click&amp;quot;, function (event) {&lt;br /&gt;
    if (event.shiftKey || event.ctrlKey) {&lt;br /&gt;
      handleLongPress(event.target);&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  var longPressTimer;&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;touchstart&amp;quot;, function (event) {&lt;br /&gt;
    longPressTimer = setTimeout(function () {&lt;br /&gt;
      handleLongPress(event.target);&lt;br /&gt;
    }, 800);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;touchend&amp;quot;, function () {&lt;br /&gt;
    clearTimeout(longPressTimer);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;touchmove&amp;quot;, function () {&lt;br /&gt;
    clearTimeout(longPressTimer);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  filterForm(characters, battle);&lt;br /&gt;
  characterCreationListener(characters, battle);&lt;br /&gt;
  handleFocus();&lt;br /&gt;
&lt;br /&gt;
  window.addEventListener(&amp;quot;beforeunload&amp;quot;, function (event) {&lt;br /&gt;
    if (characters.unsavedChanges) {&lt;br /&gt;
      event.preventDefault();&lt;br /&gt;
      return &amp;quot;&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addMonsterElement(characters, battle, monsterVnum, iframeInfo) {&lt;br /&gt;
  var { monsterTemplate, monstersContainer } = characters;&lt;br /&gt;
  var monsterElement = monsterTemplate.cloneNode(true);&lt;br /&gt;
  var spanInput = monsterElement.querySelector(&amp;quot;span.input&amp;quot;);&lt;br /&gt;
  var deleteSvg = monsterElement.querySelector(&amp;quot;svg&amp;quot;);&lt;br /&gt;
  var monsterName = getMonsterName(monsterVnum);&lt;br /&gt;
  var link = createWikiLink(monsterName);&lt;br /&gt;
&lt;br /&gt;
  monsterElement.setAttribute(&amp;quot;tabindex&amp;quot;, &amp;quot;0&amp;quot;);&lt;br /&gt;
  spanInput.appendChild(link);&lt;br /&gt;
  monstersContainer.appendChild(monsterElement);&lt;br /&gt;
  characters.monsterElements[monsterVnum] = monsterElement;&lt;br /&gt;
&lt;br /&gt;
  deleteSvg.addEventListener(&amp;quot;click&amp;quot;, function () {&lt;br /&gt;
    var monster = characters.savedMonsters[monsterVnum];&lt;br /&gt;
    iframeInfo[monster.category].shouldBeUpdated = true;&lt;br /&gt;
&lt;br /&gt;
    deleteMonster(characters, battle, monsterVnum);&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addNewMonster(&lt;br /&gt;
  characters,&lt;br /&gt;
  battle,&lt;br /&gt;
  monsterVnum,&lt;br /&gt;
  monsterImage,&lt;br /&gt;
  iframeInfo,&lt;br /&gt;
  category&lt;br /&gt;
) {&lt;br /&gt;
  if (isValueInArray(monsterVnum, Object.keys(characters.savedMonsters)))&lt;br /&gt;
    return;&lt;br /&gt;
&lt;br /&gt;
  var newMonster = {&lt;br /&gt;
    image: monsterImage,&lt;br /&gt;
    category: category,&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  characters.savedMonsters[monsterVnum] = newMonster;&lt;br /&gt;
&lt;br /&gt;
  addMonsterElement(characters, battle, monsterVnum, iframeInfo);&lt;br /&gt;
  updateSavedMonsters(characters.savedMonsters);&lt;br /&gt;
  addBattleChoice(battle.battleChoice, monsterVnum, newMonster, true);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addButtonsToCards(characters, iframeDoc, iframeInfo, category) {&lt;br /&gt;
  var buttonTemplates = characters.monsterButtonTemplates.children[0];&lt;br /&gt;
  var cardToEdit = iframeDoc.getElementById(&amp;quot;cards-container&amp;quot;).children;&lt;br /&gt;
  var { nameToVnum } = iframeInfo;&lt;br /&gt;
  var vnumToButtons = iframeInfo[category].vnumToButtons;&lt;br /&gt;
&lt;br /&gt;
  for (var cardIndex = 0; cardIndex &amp;lt; cardToEdit.length; cardIndex++) {&lt;br /&gt;
    var card = cardToEdit[cardIndex];&lt;br /&gt;
    var cardName = card.querySelector(&amp;quot;[data-name]&amp;quot;).firstChild.title;&lt;br /&gt;
    var buttonTemplatesClone = buttonTemplates.cloneNode(true);&lt;br /&gt;
&lt;br /&gt;
    cardName = cardName.replace(/\s/g, &amp;quot; &amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (!nameToVnum.hasOwnProperty(cardName)) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var monsterVnum = nameToVnum[cardName];&lt;br /&gt;
&lt;br /&gt;
    buttonTemplatesClone.dataset.monsterId = monsterVnum;&lt;br /&gt;
    card.lastElementChild.appendChild(buttonTemplatesClone);&lt;br /&gt;
    vnumToButtons[monsterVnum] = buttonTemplatesClone.children;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateiFrameButtons(characters, iframeInfo, category) {&lt;br /&gt;
  var addedMonsters = Object.keys(characters.savedMonsters);&lt;br /&gt;
  var { currentiFrameIsMonster } = iframeInfo;&lt;br /&gt;
  var vnumToButtons = iframeInfo[category].vnumToButtons;&lt;br /&gt;
  var isPolymorphModal = category === &amp;quot;monster&amp;quot; &amp;amp;&amp;amp; !currentiFrameIsMonster;&lt;br /&gt;
&lt;br /&gt;
  for (var monsterVnum in vnumToButtons) {&lt;br /&gt;
    var [addButton, deleteButton, selectButton] = vnumToButtons[monsterVnum];&lt;br /&gt;
&lt;br /&gt;
    if (isPolymorphModal) {&lt;br /&gt;
      hideElement(addButton);&lt;br /&gt;
      hideElement(deleteButton);&lt;br /&gt;
      showElement(selectButton);&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isValueInArray(monsterVnum, addedMonsters)) {&lt;br /&gt;
      hideElement(addButton);&lt;br /&gt;
      showElement(deleteButton);&lt;br /&gt;
      hideElement(selectButton);&lt;br /&gt;
    } else {&lt;br /&gt;
      showElement(addButton);&lt;br /&gt;
      hideElement(deleteButton);&lt;br /&gt;
      hideElement(selectButton);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  iframeInfo.lastiFrameIsMonster = currentiFrameIsMonster;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getMonsterImage(buttonsContainer) {&lt;br /&gt;
  var elder = buttonsContainer.parentElement.firstElementChild;&lt;br /&gt;
  var image = elder.querySelector(&amp;quot;img&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (image) {&lt;br /&gt;
    return image.getAttribute(&amp;quot;src&amp;quot;) || &amp;quot;&amp;quot;;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return &amp;quot;&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleiFrame(iframeInfo, category) {&lt;br /&gt;
  var { characters, battle } = iframeInfo;&lt;br /&gt;
  var iframeInfoCategory = iframeInfo[category];&lt;br /&gt;
  var { iframe, pageName, vnumToButtons } = iframeInfoCategory;&lt;br /&gt;
  var loadingAnimation = iframeInfoCategory.iframe.previousElementSibling;&lt;br /&gt;
&lt;br /&gt;
  iframe.src = mw.util.getUrl(pageName);&lt;br /&gt;
&lt;br /&gt;
  iframe.addEventListener(&amp;quot;load&amp;quot;, function () {&lt;br /&gt;
    var iframeDoc = this.contentDocument || this.contentWindow.document;&lt;br /&gt;
    var iframeBody = iframeDoc.body;&lt;br /&gt;
    var content = iframeDoc.getElementById(&amp;quot;show-after-loading&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    iframeBody.firstElementChild.replaceWith(content);&lt;br /&gt;
&lt;br /&gt;
    iframeBody.style.background = &amp;quot;transparent&amp;quot;;&lt;br /&gt;
    iframeBody.style.paddingRight = &amp;quot;10px&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    addButtonsToCards(characters, iframeDoc, iframeInfo, category);&lt;br /&gt;
    updateiFrameButtons(characters, iframeInfo, category);&lt;br /&gt;
&lt;br /&gt;
    iframeInfoCategory.loadIsFinished = true;&lt;br /&gt;
&lt;br /&gt;
    hideElement(loadingAnimation);&lt;br /&gt;
    showElement(iframe);&lt;br /&gt;
&lt;br /&gt;
    iframeDoc.addEventListener(&amp;quot;click&amp;quot;, handleButtonClick);&lt;br /&gt;
&lt;br /&gt;
    function handleButtonClick(event) {&lt;br /&gt;
      var target = event.target;&lt;br /&gt;
      var link = target.closest(&amp;quot;a&amp;quot;);&lt;br /&gt;
      var buttonsContainer = target.closest(&amp;quot;.handle-monster&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
      if (link) {&lt;br /&gt;
        event.preventDefault();&lt;br /&gt;
        window.open(link.href, &amp;quot;_blank&amp;quot;);&lt;br /&gt;
      } else if (buttonsContainer) {&lt;br /&gt;
        var { monsterId: monsterVnum } = buttonsContainer.dataset;&lt;br /&gt;
&lt;br /&gt;
        // polymorph iframe&lt;br /&gt;
        if (category === &amp;quot;monster&amp;quot; &amp;amp;&amp;amp; !iframeInfo.currentiFrameIsMonster) {&lt;br /&gt;
          var monsterImage = getMonsterImage(buttonsContainer);&lt;br /&gt;
          changePolymorphValues(&lt;br /&gt;
            characters.characterCreation,&lt;br /&gt;
            monsterVnum,&lt;br /&gt;
            monsterImage&lt;br /&gt;
          );&lt;br /&gt;
          handlePolymorphDisplay(&lt;br /&gt;
            characters.polymorphDisplay,&lt;br /&gt;
            monsterVnum,&lt;br /&gt;
            monsterImage&lt;br /&gt;
          );&lt;br /&gt;
          iframe.dispatchEvent(newChangeEvent());&lt;br /&gt;
        } else {&lt;br /&gt;
          var addedMonsters = Object.keys(characters.savedMonsters);&lt;br /&gt;
          var [addButton, deleteButton] = vnumToButtons[monsterVnum];&lt;br /&gt;
&lt;br /&gt;
          if (isValueInArray(monsterVnum, addedMonsters)) {&lt;br /&gt;
            deleteMonster(characters, battle, monsterVnum);&lt;br /&gt;
            showElement(addButton);&lt;br /&gt;
            hideElement(deleteButton);&lt;br /&gt;
          } else {&lt;br /&gt;
            var monsterImage = getMonsterImage(buttonsContainer);&lt;br /&gt;
            addNewMonster(&lt;br /&gt;
              characters,&lt;br /&gt;
              battle,&lt;br /&gt;
              monsterVnum,&lt;br /&gt;
              monsterImage,&lt;br /&gt;
              iframeInfo,&lt;br /&gt;
              category&lt;br /&gt;
            );&lt;br /&gt;
            hideElement(addButton);&lt;br /&gt;
            showElement(deleteButton);&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getNameToVnumMapping() {&lt;br /&gt;
  var nameToVnum = {};&lt;br /&gt;
&lt;br /&gt;
  for (var monsterVnum in monsterData) {&lt;br /&gt;
    nameToVnum[monsterData[monsterVnum][monsterData[monsterVnum].length - 1]] =&lt;br /&gt;
      monsterVnum;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return nameToVnum;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function monsterManagement(characters, battle) {&lt;br /&gt;
  var { monsteriFrame, stoneiFrame } = characters;&lt;br /&gt;
  var monsterVnums = Object.keys(monsterData);&lt;br /&gt;
&lt;br /&gt;
  var iframeInfo = {&lt;br /&gt;
    lastiFrameIsMonster: false,&lt;br /&gt;
    currentiFrameIsMonster: false,&lt;br /&gt;
    characters: characters,&lt;br /&gt;
    battle: battle,&lt;br /&gt;
    nameToVnum: getNameToVnumMapping(),&lt;br /&gt;
    monster: {&lt;br /&gt;
      isLoaded: false,&lt;br /&gt;
      loadIsFinished: false,&lt;br /&gt;
      shouldBeUpdated: false,&lt;br /&gt;
      vnumToButtons: {},&lt;br /&gt;
      pageName: &amp;quot;Monstres&amp;quot;,&lt;br /&gt;
      iframe: monsteriFrame,&lt;br /&gt;
    },&lt;br /&gt;
    stone: {&lt;br /&gt;
      isLoaded: false,&lt;br /&gt;
      loadIsFinished: false,&lt;br /&gt;
      shouldBeUpdated: false,&lt;br /&gt;
      vnumToButtons: {},&lt;br /&gt;
      pageName: &amp;quot;Pierres Metin&amp;quot;,&lt;br /&gt;
      iframe: stoneiFrame,&lt;br /&gt;
    },&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  document.addEventListener(&amp;quot;modalOpen&amp;quot;, function (event) {&lt;br /&gt;
    var modalName = event.detail.name;&lt;br /&gt;
&lt;br /&gt;
    if (modalName === &amp;quot;monster&amp;quot; || modalName === &amp;quot;stone&amp;quot;) {&lt;br /&gt;
      handleModal(event.target, modalName);&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  function handleModal(target, modalName) {&lt;br /&gt;
    var iframeInfoCategory = iframeInfo[modalName];&lt;br /&gt;
&lt;br /&gt;
    if (modalName === &amp;quot;monster&amp;quot;) {&lt;br /&gt;
      var isMonsteriFrame = target.id === &amp;quot;add-new-monster&amp;quot;;&lt;br /&gt;
      iframeInfo.currentiFrameIsMonster = isMonsteriFrame;&lt;br /&gt;
&lt;br /&gt;
      if (&lt;br /&gt;
        iframeInfoCategory.loadIsFinished &amp;amp;&amp;amp;&lt;br /&gt;
        ((isMonsteriFrame &amp;amp;&amp;amp; !iframeInfo.lastiFrameIsMonster) ||&lt;br /&gt;
          (!isMonsteriFrame &amp;amp;&amp;amp; iframeInfo.lastiFrameIsMonster))&lt;br /&gt;
      ) {&lt;br /&gt;
        iframeInfoCategory.shouldBeUpdated = true;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!iframeInfoCategory.isLoaded) {&lt;br /&gt;
      handleiFrame(iframeInfo, modalName);&lt;br /&gt;
      iframeInfoCategory.isLoaded = true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      iframeInfoCategory.loadIsFinished &amp;amp;&amp;amp;&lt;br /&gt;
      iframeInfoCategory.shouldBeUpdated&lt;br /&gt;
    ) {&lt;br /&gt;
      updateiFrameButtons(characters, iframeInfo, modalName);&lt;br /&gt;
      iframeInfoCategory.shouldBeUpdated = false;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  Object.keys(characters.savedMonsters)&lt;br /&gt;
    .slice()&lt;br /&gt;
    .forEach(function (monsterVnum) {&lt;br /&gt;
      if (isValueInArray(monsterVnum, monsterVnums)) {&lt;br /&gt;
        addMonsterElement(characters, battle, monsterVnum, iframeInfo);&lt;br /&gt;
      } else {&lt;br /&gt;
        deleteMonster(characters, battle, monsterVnum);&lt;br /&gt;
      }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function hideAttackType(container, input, attackType) {&lt;br /&gt;
  hideElement(container);&lt;br /&gt;
&lt;br /&gt;
  if (input.checked) {&lt;br /&gt;
    var defaultInput = attackType.defaultInput;&lt;br /&gt;
&lt;br /&gt;
    input.checked = false;&lt;br /&gt;
    defaultInput.checked = true;&lt;br /&gt;
    defaultInput.dispatchEvent(newChangeEvent());&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterAttackTypeSelectionCharacter(attacker, attackType) {&lt;br /&gt;
  var attackerClass = attacker.class;&lt;br /&gt;
  var attackerIsNotPolymorph = !isPolymorph(attacker);&lt;br /&gt;
  var { elements: attackTypeElements } = attackType;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; attackTypeElements.length; index++) {&lt;br /&gt;
    var { container, input, inputClass, inputValue } =&lt;br /&gt;
      attackTypeElements[index];&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      attackerIsNotPolymorph &amp;amp;&amp;amp;&lt;br /&gt;
      attacker[inputValue] &amp;amp;&amp;amp;&lt;br /&gt;
      (attackerClass === inputClass ||&lt;br /&gt;
        (inputValue.startsWith(&amp;quot;horseSkill&amp;quot;) &amp;amp;&amp;amp;&lt;br /&gt;
          isRiding(attacker) &amp;amp;&amp;amp;&lt;br /&gt;
          (!inputClass || isValueInArray(attackerClass, inputClass))))&lt;br /&gt;
    ) {&lt;br /&gt;
      showElement(container);&lt;br /&gt;
    } else {&lt;br /&gt;
      hideAttackType(container, input, attackType);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterAttackTypeSelectionMonster(attackType) {&lt;br /&gt;
  var attackTypeElements = attackType.elements;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; attackTypeElements.length; index++) {&lt;br /&gt;
    var { container, input } = attackTypeElements[index];&lt;br /&gt;
    hideAttackType(container, input, attackType);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function removeBattleElement(battleChoice, nameOrVnum, category, type) {&lt;br /&gt;
  var elements = battleChoice[category][type].elements;&lt;br /&gt;
&lt;br /&gt;
  if (elements.hasOwnProperty(nameOrVnum)) {&lt;br /&gt;
    elements[nameOrVnum].container.remove();&lt;br /&gt;
    delete elements[nameOrVnum];&lt;br /&gt;
    battleChoice[category][type].count--;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function removeBattleChoice(battleChoice, nameOrVnum, type) {&lt;br /&gt;
  battleChoice.categories.forEach(function (category) {&lt;br /&gt;
    if (category === &amp;quot;attacker&amp;quot; &amp;amp;&amp;amp; type === &amp;quot;stone&amp;quot;) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
    var selected = battleChoice[category].selected;&lt;br /&gt;
&lt;br /&gt;
    if (selected) {&lt;br /&gt;
      var { type: selectedType, nameOrVnum: selectedNameOrVnum } =&lt;br /&gt;
        parseTypeAndName(selected);&lt;br /&gt;
&lt;br /&gt;
      if (nameOrVnum === selectedNameOrVnum &amp;amp;&amp;amp; type === selectedType) {&lt;br /&gt;
        resetBattleChoiceButton(battleChoice, category);&lt;br /&gt;
        battleChoice[category].selected = null;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    removeBattleElement(battleChoice, nameOrVnum, category, type);&lt;br /&gt;
    updateBattleChoiceText(battleChoice, category, type);&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addBattleElement(&lt;br /&gt;
  battleChoice,&lt;br /&gt;
  pseudoOrVnum,&lt;br /&gt;
  characterOrMonster,&lt;br /&gt;
  category,&lt;br /&gt;
  isMonster&lt;br /&gt;
) {&lt;br /&gt;
  var { template, raceToImage } = battleChoice;&lt;br /&gt;
  var battleChoiceCategory = battleChoice[category];&lt;br /&gt;
  var templateClone = template.cloneNode(true);&lt;br /&gt;
  var label = templateClone.firstElementChild;&lt;br /&gt;
  var [input, image, span] = label.children;&lt;br /&gt;
  var imageSrc;&lt;br /&gt;
  var name;&lt;br /&gt;
  var type;&lt;br /&gt;
&lt;br /&gt;
  if (isMonster) {&lt;br /&gt;
    type = characterOrMonster.category;&lt;br /&gt;
&lt;br /&gt;
    if (type === &amp;quot;stone&amp;quot; &amp;amp;&amp;amp; category === &amp;quot;attacker&amp;quot;) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
    imageSrc = characterOrMonster.image;&lt;br /&gt;
    name = getMonsterName(pseudoOrVnum);&lt;br /&gt;
  } else {&lt;br /&gt;
    type = &amp;quot;character&amp;quot;;&lt;br /&gt;
    imageSrc = raceToImage[characterOrMonster.race];&lt;br /&gt;
    name = pseudoOrVnum;&lt;br /&gt;
    label.classList.add(&amp;quot;notranslate&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var value = type + &amp;quot;-&amp;quot; + pseudoOrVnum;&lt;br /&gt;
  var id = category + &amp;quot;-&amp;quot; + value;&lt;br /&gt;
  var currentBattleChoice = battleChoiceCategory[type];&lt;br /&gt;
&lt;br /&gt;
  label.setAttribute(&amp;quot;for&amp;quot;, id);&lt;br /&gt;
  input.value = value;&lt;br /&gt;
  input.id = id;&lt;br /&gt;
  input.name = category;&lt;br /&gt;
  span.textContent = name;&lt;br /&gt;
&lt;br /&gt;
  handleImageFromWiki(image, imageSrc);&lt;br /&gt;
&lt;br /&gt;
  currentBattleChoice.container.appendChild(templateClone);&lt;br /&gt;
  currentBattleChoice.count++;&lt;br /&gt;
  currentBattleChoice.elements[pseudoOrVnum] = {&lt;br /&gt;
    container: templateClone,&lt;br /&gt;
    image: image,&lt;br /&gt;
    name: name,&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  updateBattleChoiceText(battleChoice, category, type);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addBattleChoice(&lt;br /&gt;
  battleChoice,&lt;br /&gt;
  pseudoOrVnum,&lt;br /&gt;
  characterOrMonster,&lt;br /&gt;
  isMonster = false&lt;br /&gt;
) {&lt;br /&gt;
  addBattleElement(&lt;br /&gt;
    battleChoice,&lt;br /&gt;
    pseudoOrVnum,&lt;br /&gt;
    characterOrMonster,&lt;br /&gt;
    &amp;quot;attacker&amp;quot;,&lt;br /&gt;
    isMonster&lt;br /&gt;
  );&lt;br /&gt;
  addBattleElement(&lt;br /&gt;
    battleChoice,&lt;br /&gt;
    pseudoOrVnum,&lt;br /&gt;
    characterOrMonster,&lt;br /&gt;
    &amp;quot;victim&amp;quot;,&lt;br /&gt;
    isMonster&lt;br /&gt;
  );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateBattleChoiceImage(battleChoice, characterName, newRace) {&lt;br /&gt;
  var imageSrc = battleChoice.raceToImage[newRace];&lt;br /&gt;
&lt;br /&gt;
  battleChoice.categories.forEach(function (category) {&lt;br /&gt;
    handleImageFromWiki(&lt;br /&gt;
      battleChoice[category].character.elements[characterName].image,&lt;br /&gt;
      imageSrc&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    var selected = battleChoice[category].selected;&lt;br /&gt;
&lt;br /&gt;
    if (isCharacterSelected(characterName, selected)) {&lt;br /&gt;
      updateBattleChoiceButton(battleChoice, category, selected);&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateBattleChoiceText(battleChoice, category, type) {&lt;br /&gt;
  var { count, container } = battleChoice[category][type];&lt;br /&gt;
  var parentContainer = container.parentElement;&lt;br /&gt;
&lt;br /&gt;
  if (count === 0) {&lt;br /&gt;
    hideElement(parentContainer);&lt;br /&gt;
    showElement(parentContainer.nextElementSibling);&lt;br /&gt;
  } else if (count === 1) {&lt;br /&gt;
    showElement(parentContainer);&lt;br /&gt;
    hideElement(parentContainer.nextElementSibling);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateBattleChoice(characters, battleChoice) {&lt;br /&gt;
  var templateImage = battleChoice.template.querySelector(&amp;quot;img&amp;quot;);&lt;br /&gt;
  var attackerImage = battleChoice.attacker.buttonContent.querySelector(&amp;quot;img&amp;quot;);&lt;br /&gt;
  var victimImage = battleChoice.victim.buttonContent.querySelector(&amp;quot;img&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  resetImageFromWiki(templateImage);&lt;br /&gt;
  resetImageFromWiki(attackerImage);&lt;br /&gt;
  resetImageFromWiki(victimImage);&lt;br /&gt;
&lt;br /&gt;
  for (var [pseudo, character] of Object.entries(characters.savedCharacters)) {&lt;br /&gt;
    addBattleChoice(battleChoice, pseudo, character);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (var [vnum, monster] of Object.entries(characters.savedMonsters)) {&lt;br /&gt;
    addBattleChoice(battleChoice, vnum, monster, true);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateBattleChoiceButton(battleChoice, category, data) {&lt;br /&gt;
  var battleChoiceCategory = battleChoice[category];&lt;br /&gt;
  var { defaultButtonContent, buttonContent } = battleChoiceCategory;&lt;br /&gt;
  var [buttonImage, buttonSpan] = buttonContent.firstElementChild.children;&lt;br /&gt;
  var { type, nameOrVnum } = parseTypeAndName(data);&lt;br /&gt;
  var { name, image } = battleChoiceCategory[type].elements[nameOrVnum];&lt;br /&gt;
&lt;br /&gt;
  hideElement(defaultButtonContent);&lt;br /&gt;
  showElement(buttonContent);&lt;br /&gt;
&lt;br /&gt;
  buttonSpan.textContent = name;&lt;br /&gt;
  buttonImage.src = image.src;&lt;br /&gt;
  battleChoiceCategory.selected = data;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function resetBattleChoiceButton(battleChoice, category) {&lt;br /&gt;
  var { defaultButtonContent, buttonContent } = battleChoice[category];&lt;br /&gt;
&lt;br /&gt;
  showElement(defaultButtonContent);&lt;br /&gt;
  hideElement(buttonContent);&lt;br /&gt;
&lt;br /&gt;
  if (category === &amp;quot;attacker&amp;quot;) {&lt;br /&gt;
    filterAttackTypeSelectionMonster(battleChoice.attackType);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isPC(character) {&lt;br /&gt;
  if (character.race === 0 || character.race === 1) {&lt;br /&gt;
    return false;&lt;br /&gt;
  }&lt;br /&gt;
  return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isBoss(character) {&lt;br /&gt;
  return character.race === 0 &amp;amp;&amp;amp; character.rank &amp;gt;= 5;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isStone(character) {&lt;br /&gt;
  return character.race === 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isMeleeAttacker(monster) {&lt;br /&gt;
  return monster.attack == 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isRangeAttacker(monster) {&lt;br /&gt;
  return monster.attack == 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isMagicAttacker(monster) {&lt;br /&gt;
  return monster.attack == 2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isMagicClass(character) {&lt;br /&gt;
  return character.race === &amp;quot;shaman&amp;quot; || character.class === &amp;quot;black_magic&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isDispell(character, skillId) {&lt;br /&gt;
  return character.class === &amp;quot;weaponary&amp;quot; &amp;amp;&amp;amp; skillId === 6;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isPolymorph(character) {&lt;br /&gt;
  return isChecked(character.isPolymorph);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isRiding(character) {&lt;br /&gt;
  return isChecked(character.isRiding);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isBow(weaponType) {&lt;br /&gt;
  return weaponType === 2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcAttackFactor(attacker, victim) {&lt;br /&gt;
  function calcCoeffK(dex, level) {&lt;br /&gt;
    return Math.min(90, Math.floor((2 * dex + level) / 3));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var K1 = calcCoeffK(attacker.polymorphDex, attacker.level);&lt;br /&gt;
  var K2 = calcCoeffK(victim.polymorphDex, attacker.level);&lt;br /&gt;
&lt;br /&gt;
  var AR = (K1 + 210) / 300;&lt;br /&gt;
  var ER = (((2 * K2 + 5) / (K2 + 95)) * 3) / 10;&lt;br /&gt;
&lt;br /&gt;
  return truncateNumber(AR - ER, 8);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcMainAttackValue(attacker) {&lt;br /&gt;
  var leadership = 0;&lt;br /&gt;
  var weaponGrowth = 0;&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker)) {&lt;br /&gt;
    weaponGrowth = attacker.weapon.growth;&lt;br /&gt;
    leadership = attacker.leadership;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return 2 * (attacker.level + weaponGrowth) + leadership;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcStatAttackValue(character) {&lt;br /&gt;
  switch (character.race) {&lt;br /&gt;
    case &amp;quot;warrior&amp;quot;:&lt;br /&gt;
    case &amp;quot;sura&amp;quot;:&lt;br /&gt;
      return 2 * character.str;&lt;br /&gt;
    case &amp;quot;ninja&amp;quot;:&lt;br /&gt;
      return Math.floor((1 / 4) * (character.str + 7 * character.dex));&lt;br /&gt;
    case &amp;quot;shaman&amp;quot;:&lt;br /&gt;
      return Math.floor((1 / 3) * (5 * character.int + character.dex));&lt;br /&gt;
    case &amp;quot;lycan&amp;quot;:&lt;br /&gt;
      return character.vit + 2 * character.dex;&lt;br /&gt;
    default:&lt;br /&gt;
      return 2 * character.str;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcSecondaryAttackValue(attacker, isPlayerVsPlayer) {&lt;br /&gt;
  var attackValueOther = 0;&lt;br /&gt;
&lt;br /&gt;
  var minAttackValue = 0;&lt;br /&gt;
  var maxAttackValue = 0;&lt;br /&gt;
&lt;br /&gt;
  var minWeaponAttackValue = 0;&lt;br /&gt;
  var maxWeaponAttackValue = 0;&lt;br /&gt;
&lt;br /&gt;
  var minAttackValueSlash = 0;&lt;br /&gt;
  var maxAttackValueSlash = 0;&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker)) {&lt;br /&gt;
    var { type, isSerpent, minAttackValue, maxAttackValue, growth } =&lt;br /&gt;
      attacker.weapon;&lt;br /&gt;
&lt;br /&gt;
    if (isSerpent) {&lt;br /&gt;
      minAttackValue = Math.max(0, attacker.minAttackValueRandom - growth);&lt;br /&gt;
      maxAttackValue = Math.max(&lt;br /&gt;
        minAttackValue,&lt;br /&gt;
        attacker.maxAttackValueRandom - growth&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    minWeaponAttackValue = minAttackValue + growth;&lt;br /&gt;
    maxWeaponAttackValue = maxAttackValue + growth;&lt;br /&gt;
&lt;br /&gt;
    minAttackValueSlash = Math.min(&lt;br /&gt;
      attacker.minAttackValueSlash,&lt;br /&gt;
      attacker.maxAttackValueSlash&lt;br /&gt;
    );&lt;br /&gt;
    maxAttackValueSlash = Math.max(&lt;br /&gt;
      attacker.minAttackValueSlash,&lt;br /&gt;
      attacker.maxAttackValueSlash&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    attackValueOther += attacker.attackValue;&lt;br /&gt;
&lt;br /&gt;
    if (isBow(type) &amp;amp;&amp;amp; !isPolymorph(attacker)) {&lt;br /&gt;
      attackValueOther += 25;&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    minAttackValue = attacker.minAttackValue;&lt;br /&gt;
    maxAttackValue = attacker.maxAttackValue;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  minAttackValue += attacker.minAttackValuePolymorph;&lt;br /&gt;
  maxAttackValue += attacker.maxAttackValuePolymorph;&lt;br /&gt;
&lt;br /&gt;
  attackValueOther += attacker.statAttackValue;&lt;br /&gt;
  attackValueOther += attacker.horseAttackValue;&lt;br /&gt;
&lt;br /&gt;
  var weaponInterval = maxAttackValue - minAttackValue + 1;&lt;br /&gt;
  var slashInterval = maxAttackValueSlash - minAttackValueSlash + 1;&lt;br /&gt;
&lt;br /&gt;
  var totalCardinal = weaponInterval * slashInterval * 1_000_000;&lt;br /&gt;
  var minInterval = Math.min(weaponInterval, slashInterval);&lt;br /&gt;
&lt;br /&gt;
  minAttackValue += minAttackValueSlash;&lt;br /&gt;
  maxAttackValue += maxAttackValueSlash;&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    minAttackValue: minAttackValue,&lt;br /&gt;
    maxAttackValue: maxAttackValue,&lt;br /&gt;
    attackValueOther: attackValueOther,&lt;br /&gt;
    totalCardinal: totalCardinal,&lt;br /&gt;
    weights: calcWeights(minAttackValue, maxAttackValue, minInterval),&lt;br /&gt;
    possibleDamageCount: maxAttackValue - minAttackValue + 1,&lt;br /&gt;
    weapon: {&lt;br /&gt;
      minAttackValue: minWeaponAttackValue,&lt;br /&gt;
      maxAttackValue: maxWeaponAttackValue,&lt;br /&gt;
      interval: weaponInterval,&lt;br /&gt;
    },&lt;br /&gt;
    isPlayerVsPlayer: isPlayerVsPlayer,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcMagicAttackValue(attacker, isPlayerVsPlayer) {&lt;br /&gt;
  var minMagicAttackValueSlash = 0;&lt;br /&gt;
  var maxMagicAttackValueSlash = 0;&lt;br /&gt;
&lt;br /&gt;
  var minWeaponAttackValue = 0;&lt;br /&gt;
  var maxWeaponAttackValue = 0;&lt;br /&gt;
&lt;br /&gt;
  var {&lt;br /&gt;
    isSerpent,&lt;br /&gt;
    minMagicAttackValue,&lt;br /&gt;
    maxMagicAttackValue,&lt;br /&gt;
    minAttackValue,&lt;br /&gt;
    maxAttackValue,&lt;br /&gt;
    growth,&lt;br /&gt;
  } = attacker.weapon;&lt;br /&gt;
&lt;br /&gt;
  if (isSerpent) {&lt;br /&gt;
    minMagicAttackValue = Math.max(0, attacker.minMagicAttackValueRandom);&lt;br /&gt;
    maxMagicAttackValue = Math.max(&lt;br /&gt;
      minMagicAttackValue,&lt;br /&gt;
      attacker.maxMagicAttackValueRandom&lt;br /&gt;
    );&lt;br /&gt;
    minAttackValue = Math.max(0, attacker.minAttackValueRandom - growth);&lt;br /&gt;
    maxAttackValue = Math.max(&lt;br /&gt;
      minAttackValue,&lt;br /&gt;
      attacker.maxAttackValueRandom - growth&lt;br /&gt;
    );&lt;br /&gt;
  } else {&lt;br /&gt;
    minMagicAttackValue += growth;&lt;br /&gt;
    maxMagicAttackValue += growth;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  minWeaponAttackValue = minAttackValue + growth;&lt;br /&gt;
  maxWeaponAttackValue = maxAttackValue + growth;&lt;br /&gt;
&lt;br /&gt;
  minMagicAttackValueSlash = Math.min(&lt;br /&gt;
    attacker.minMagicAttackValueSlash,&lt;br /&gt;
    attacker.maxMagicAttackValueSlash&lt;br /&gt;
  );&lt;br /&gt;
  maxMagicAttackValueSlash = Math.max(&lt;br /&gt;
    attacker.minMagicAttackValueSlash,&lt;br /&gt;
    attacker.maxMagicAttackValueSlash&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  var weaponInterval = maxMagicAttackValue - minMagicAttackValue + 1;&lt;br /&gt;
  var slashInterval = maxMagicAttackValueSlash - minMagicAttackValueSlash + 1;&lt;br /&gt;
&lt;br /&gt;
  var totalCardinal = weaponInterval * slashInterval * 1_000_000;&lt;br /&gt;
  var minInterval = Math.min(weaponInterval, slashInterval);&lt;br /&gt;
&lt;br /&gt;
  minMagicAttackValue += minMagicAttackValueSlash;&lt;br /&gt;
  maxMagicAttackValue += maxMagicAttackValueSlash;&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    minMagicAttackValue: minMagicAttackValue,&lt;br /&gt;
    maxMagicAttackValue: maxMagicAttackValue,&lt;br /&gt;
    magicAttackValueAugmentation: getMagicAttackValueAugmentation(&lt;br /&gt;
      minMagicAttackValue,&lt;br /&gt;
      maxMagicAttackValue,&lt;br /&gt;
      attacker.magicAttackValue&lt;br /&gt;
    ),&lt;br /&gt;
    totalCardinal: totalCardinal,&lt;br /&gt;
    weights: calcWeights(minMagicAttackValue, maxMagicAttackValue, minInterval),&lt;br /&gt;
    possibleDamageCount: maxMagicAttackValue - minMagicAttackValue + 1,&lt;br /&gt;
    weapon: {&lt;br /&gt;
      minAttackValue: minWeaponAttackValue,&lt;br /&gt;
      maxAttackValue: maxWeaponAttackValue,&lt;br /&gt;
      interval: maxWeaponAttackValue - minWeaponAttackValue + 1,&lt;br /&gt;
    },&lt;br /&gt;
    isPlayerVsPlayer: isPlayerVsPlayer,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getPolymorphPower(polymorphPoint, polymorphPowerTable) {&lt;br /&gt;
  return polymorphPowerTable[polymorphPoint];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSkillPower(skillPoint, skillPowerTable) {&lt;br /&gt;
  return skillPowerTable[skillPoint];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getMarriageBonusValue(character, marriageTable, itemName) {&lt;br /&gt;
  var index;&lt;br /&gt;
  var lovePoint = character.lovePoint;&lt;br /&gt;
&lt;br /&gt;
  if (lovePoint &amp;lt; 65) {&lt;br /&gt;
    index = 0;&lt;br /&gt;
  } else if (lovePoint &amp;lt; 80) {&lt;br /&gt;
    index = 1;&lt;br /&gt;
  } else if (lovePoint &amp;lt; 100) {&lt;br /&gt;
    index = 2;&lt;br /&gt;
  } else {&lt;br /&gt;
    index = 3;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return marriageTable[itemName][index];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcDamageWithPrimaryBonuses(damage, bonusValues) {&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.attackValueCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  damage += bonusValues.attackValueMarriage;&lt;br /&gt;
&lt;br /&gt;
  damage = Math.floor(&lt;br /&gt;
    (damage * bonusValues.monsterResistanceMarriageCoeff) / 100&lt;br /&gt;
  );&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.monsterResistanceCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  damage += Math.floor((damage * bonusValues.typeBonusCoeff) / 100);&lt;br /&gt;
  damage +=&lt;br /&gt;
    Math.floor((damage * bonusValues.raceBonusCoeff) / 100) -&lt;br /&gt;
    Math.floor((damage * bonusValues.raceResistanceCoeff) / 100);&lt;br /&gt;
  damage += Math.floor((damage * bonusValues.stoneBonusCoeff) / 100);&lt;br /&gt;
  damage += Math.floor((damage * bonusValues.monsterBonusCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  var elementBonusCoeff = bonusValues.elementBonusCoeff;&lt;br /&gt;
&lt;br /&gt;
  damage +=&lt;br /&gt;
    Math.trunc((damage * elementBonusCoeff[0]) / 10000) +&lt;br /&gt;
    Math.trunc((damage * elementBonusCoeff[1]) / 10000) +&lt;br /&gt;
    Math.trunc((damage * elementBonusCoeff[2]) / 10000) +&lt;br /&gt;
    Math.trunc((damage * elementBonusCoeff[3]) / 10000) +&lt;br /&gt;
    Math.trunc((damage * elementBonusCoeff[4]) / 10000) +&lt;br /&gt;
    Math.trunc((damage * elementBonusCoeff[5]) / 10000);&lt;br /&gt;
&lt;br /&gt;
  damage = Math.floor(damage * bonusValues.damageMultiplier);&lt;br /&gt;
&lt;br /&gt;
  return damage;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcFinalDamage(&lt;br /&gt;
  damage,&lt;br /&gt;
  bonusValues,&lt;br /&gt;
  damageType,&lt;br /&gt;
  minPiercingDamage,&lt;br /&gt;
  tempDamage&lt;br /&gt;
) {&lt;br /&gt;
  if (damageType.isPiercingHit) {&lt;br /&gt;
    damage += bonusValues.defenseBoost + Math.min(0, minPiercingDamage);&lt;br /&gt;
    damage += Math.floor(&lt;br /&gt;
      (tempDamage * bonusValues.extraPiercingHitCoeff) / 1000&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.averageDamageCoeff) / 100);&lt;br /&gt;
  damage = Math.floor(&lt;br /&gt;
    (damage * bonusValues.averageDamageResistanceCoeff) / 100&lt;br /&gt;
  );&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.skillDamageCoeff) / 100);&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.skillDamageResistanceCoeff) / 100);&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.rankBonusCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  if (bonusValues.useDarkProtection) {&lt;br /&gt;
    var { darkProtectionPoint, darkProtectionSp } = bonusValues;&lt;br /&gt;
&lt;br /&gt;
    var damageReduction = Math.floor(damage / 3);&lt;br /&gt;
    var spAbsorption = Math.floor(&lt;br /&gt;
      (damageReduction * darkProtectionPoint) / 100&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    if (spAbsorption &amp;lt;= darkProtectionSp) {&lt;br /&gt;
      damage -= damageReduction;&lt;br /&gt;
    } else {&lt;br /&gt;
      damage -= Math.floor((darkProtectionSp * 100) / darkProtectionPoint);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  damage = Math.max(0, damage + bonusValues.defensePercent);&lt;br /&gt;
  damage += Math.min(&lt;br /&gt;
    300,&lt;br /&gt;
    Math.floor((damage * bonusValues.damageBonusCoeff) / 100)&lt;br /&gt;
  );&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.empireMalusCoeff) / 10);&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.sungMaStrBonusCoeff) / 10000);&lt;br /&gt;
  damage -= Math.floor(damage * bonusValues.sungmaStrMalusCoeff);&lt;br /&gt;
&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.whiteDragonElixirCoeff) / 100);&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.steelDragonElixirCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  return damage;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveFinalDamage(&lt;br /&gt;
  damage,&lt;br /&gt;
  bonusValues,&lt;br /&gt;
  damageType,&lt;br /&gt;
  weapon,&lt;br /&gt;
  minPiercingDamage,&lt;br /&gt;
  damageWithPrimaryBonuses,&lt;br /&gt;
  damageWeighted,&lt;br /&gt;
  weight&lt;br /&gt;
) {&lt;br /&gt;
  damage = Math.floor(damage * bonusValues.magicResistanceCoeff);&lt;br /&gt;
  damage = Math.trunc((damage * bonusValues.weaponDefenseCoeff) / 100);&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.tigerStrengthCoeff) / 100);&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.berserkBonusCoeff) / 100);&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.fearBonusCoeff) / 100);&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.blessingBonusCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  const isCriticalHit = damageType.isCriticalHit;&lt;br /&gt;
&lt;br /&gt;
  if (isCriticalHit &amp;amp;&amp;amp; bonusValues.isPlayerVsPlayer) {&lt;br /&gt;
    for (&lt;br /&gt;
      let weaponAttackValue = weapon.minAttackValue;&lt;br /&gt;
      weaponAttackValue &amp;lt;= weapon.maxAttackValue;&lt;br /&gt;
      weaponAttackValue++&lt;br /&gt;
    ) {&lt;br /&gt;
      const criticalDamage = damage + 2 * weaponAttackValue;&lt;br /&gt;
      const finalDamage = calcFinalDamage(&lt;br /&gt;
        criticalDamage,&lt;br /&gt;
        bonusValues,&lt;br /&gt;
        damageType,&lt;br /&gt;
        minPiercingDamage,&lt;br /&gt;
        damageWithPrimaryBonuses&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      addKeyValue(damageWeighted, finalDamage, weight / weapon.interval);&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    if (isCriticalHit) {&lt;br /&gt;
      damage *= 2;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    damage = calcFinalDamage(&lt;br /&gt;
      damage,&lt;br /&gt;
      bonusValues,&lt;br /&gt;
      damageType,&lt;br /&gt;
      minPiercingDamage,&lt;br /&gt;
      damageWithPrimaryBonuses&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    addKeyValue(damageWeighted, damage, weight);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveFinalSkillDamage(&lt;br /&gt;
  damage,&lt;br /&gt;
  bonusValues,&lt;br /&gt;
  damageType,&lt;br /&gt;
  weapon,&lt;br /&gt;
  minPiercingDamage,&lt;br /&gt;
  damageWeighted,&lt;br /&gt;
  weight,&lt;br /&gt;
  savedCriticalDamage&lt;br /&gt;
) {&lt;br /&gt;
  damage = Math.floor(damage * bonusValues.magicResistanceCoeff);&lt;br /&gt;
  damage = Math.trunc((damage * bonusValues.weaponDefenseCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  damage -= bonusValues.defense;&lt;br /&gt;
&lt;br /&gt;
  damage = floorMultiplication(damage, bonusValues.skillWardCoeff);&lt;br /&gt;
  damage = floorMultiplication(damage, bonusValues.skillBonusCoeff);&lt;br /&gt;
&lt;br /&gt;
  const tempDamage = Math.floor(&lt;br /&gt;
    (damage * bonusValues.skillBonusByBonusCoeff) / 100&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  damage = Math.floor(&lt;br /&gt;
    (tempDamage * bonusValues.magicAttackValueCoeff) / 100 + 0.5&lt;br /&gt;
  );&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.tigerStrengthCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  const isCriticalHit = damageType.isCriticalHit;&lt;br /&gt;
&lt;br /&gt;
  if (isCriticalHit &amp;amp;&amp;amp; bonusValues.isPlayerVsPlayer) {&lt;br /&gt;
    const { minAttackValue, maxAttackValue, interval } = weapon;&lt;br /&gt;
    const criticalWeight = weight / interval;&lt;br /&gt;
&lt;br /&gt;
    for (&lt;br /&gt;
      let weaponAttackValue = minAttackValue;&lt;br /&gt;
      weaponAttackValue &amp;lt;= maxAttackValue;&lt;br /&gt;
      weaponAttackValue++&lt;br /&gt;
    ) {&lt;br /&gt;
      const criticalDamage = damage + 2 * weaponAttackValue;&lt;br /&gt;
&lt;br /&gt;
      if (&lt;br /&gt;
        savedCriticalDamage &amp;amp;&amp;amp;&lt;br /&gt;
        savedCriticalDamage.hasOwnProperty(criticalDamage) &amp;amp;&amp;amp;&lt;br /&gt;
        minPiercingDamage &amp;gt;= 0&lt;br /&gt;
      ) {&lt;br /&gt;
        const savedDamage = savedCriticalDamage[criticalDamage];&lt;br /&gt;
        damageWeighted[savedDamage] += criticalWeight;&lt;br /&gt;
        continue;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      const finalDamage = calcFinalDamage(&lt;br /&gt;
        criticalDamage,&lt;br /&gt;
        bonusValues,&lt;br /&gt;
        damageType,&lt;br /&gt;
        minPiercingDamage,&lt;br /&gt;
        tempDamage&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      addKeyValue(damageWeighted, finalDamage, criticalWeight);&lt;br /&gt;
      if (savedCriticalDamage) {&lt;br /&gt;
        savedCriticalDamage[criticalDamage] = finalDamage;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    if (isCriticalHit) {&lt;br /&gt;
      damage *= 2;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    damage = calcFinalDamage(&lt;br /&gt;
      damage,&lt;br /&gt;
      bonusValues,&lt;br /&gt;
      damageType,&lt;br /&gt;
      minPiercingDamage,&lt;br /&gt;
      tempDamage&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    addKeyValue(damageWeighted, damage, weight);&lt;br /&gt;
&lt;br /&gt;
    return damage;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function computePolymorphPoint(attacker, victim, polymorphPowerTable) {&lt;br /&gt;
  attacker.polymorphDex = attacker.dex;&lt;br /&gt;
  victim.polymorphDex = victim.dex;&lt;br /&gt;
&lt;br /&gt;
  attacker.minAttackValuePolymorph = 0;&lt;br /&gt;
  attacker.maxAttackValuePolymorph = 0;&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker) &amp;amp;&amp;amp; isPolymorph(attacker)) {&lt;br /&gt;
    var polymorphPowerPct =&lt;br /&gt;
      getPolymorphPower(attacker.polymorphPoint, polymorphPowerTable) / 100;&lt;br /&gt;
    var polymorphMonster = createMonster(attacker.polymorphMonster, null, true);&lt;br /&gt;
&lt;br /&gt;
    var polymorphStr = floorMultiplication(&lt;br /&gt;
      polymorphPowerPct,&lt;br /&gt;
      polymorphMonster.str&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    attacker.polymorphDex += floorMultiplication(&lt;br /&gt;
      polymorphPowerPct,&lt;br /&gt;
      polymorphMonster.dex&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    attacker.minAttackValuePolymorph = floorMultiplication(&lt;br /&gt;
      polymorphPowerPct,&lt;br /&gt;
      polymorphMonster.minAttackValue&lt;br /&gt;
    );&lt;br /&gt;
    attacker.maxAttackValuePolymorph = floorMultiplication(&lt;br /&gt;
      polymorphPowerPct,&lt;br /&gt;
      polymorphMonster.maxAttackValue&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    if (!attacker.weapon) {&lt;br /&gt;
      attacker.maxAttackValuePolymorph += 1;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    attacker.attackValue = 0;&lt;br /&gt;
&lt;br /&gt;
    if (isMagicClass(attacker)) {&lt;br /&gt;
      attacker.statAttackValue = 2 * (polymorphStr + attacker.int);&lt;br /&gt;
    } else {&lt;br /&gt;
      attacker.statAttackValue = 2 * (polymorphStr + attacker.str);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function computeHorse(attacker) {&lt;br /&gt;
  attacker.horseAttackValue = 0;&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker) &amp;amp;&amp;amp; isRiding(attacker) &amp;amp;&amp;amp; !isPolymorph(attacker)) {&lt;br /&gt;
    var horseConstant = 30;&lt;br /&gt;
&lt;br /&gt;
    if (attacker.class === &amp;quot;weaponary&amp;quot;) {&lt;br /&gt;
      horseConstant = 60;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    attacker.horseAttackValue = floorMultiplication(&lt;br /&gt;
      2 * attacker.level + attacker.statAttackValue,&lt;br /&gt;
      attacker.horsePoint / horseConstant&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getRankBonus(attacker) {&lt;br /&gt;
  if (!isChecked(attacker.lowRank)) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  switch (attacker.rank) {&lt;br /&gt;
    case &amp;quot;aggressive&amp;quot;:&lt;br /&gt;
      return 1;&lt;br /&gt;
    case &amp;quot;fraudulent&amp;quot;:&lt;br /&gt;
      return 2;&lt;br /&gt;
    case &amp;quot;malicious&amp;quot;:&lt;br /&gt;
      return 3;&lt;br /&gt;
    case &amp;quot;cruel&amp;quot;:&lt;br /&gt;
      return 5;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcElementCoeffPvP(elementBonus, mapping, attacker, victim) {&lt;br /&gt;
  var minElementMalus = 0;&lt;br /&gt;
  var maxDifference = 0;&lt;br /&gt;
  var savedElementDifferences = [];&lt;br /&gt;
  var elementBonusIndex = 0;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; elementBonus.length; index++) {&lt;br /&gt;
    if (!attacker[mapping.elementBonus[index]]) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var elementDifference =&lt;br /&gt;
      attacker[mapping.elementBonus[index]] -&lt;br /&gt;
      victim[mapping.elementResistance[index]];&lt;br /&gt;
&lt;br /&gt;
    if (elementDifference &amp;gt;= 0) {&lt;br /&gt;
      elementBonus[elementBonusIndex] = 10 * elementDifference;&lt;br /&gt;
      minElementMalus -= elementDifference;&lt;br /&gt;
      maxDifference = Math.max(maxDifference, elementDifference);&lt;br /&gt;
      elementBonusIndex++;&lt;br /&gt;
    } else {&lt;br /&gt;
      savedElementDifferences.push(elementDifference);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (!savedElementDifferences.length) {&lt;br /&gt;
    return;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  minElementMalus += maxDifference;&lt;br /&gt;
  savedElementDifferences.sort(compareNumbers);&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; savedElementDifferences.length; index++) {&lt;br /&gt;
    var elementDifference = savedElementDifferences[index];&lt;br /&gt;
&lt;br /&gt;
    elementBonus[elementBonusIndex + index] =&lt;br /&gt;
      10 * Math.max(minElementMalus, elementDifference);&lt;br /&gt;
&lt;br /&gt;
    minElementMalus = Math.min(&lt;br /&gt;
      0,&lt;br /&gt;
      Math.max(minElementMalus, minElementMalus - elementDifference)&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcCriticalHitChance(criticalHitPercentage) {&lt;br /&gt;
  if (criticalHitPercentage &amp;lt;= 9) {&lt;br /&gt;
    return Math.floor((criticalHitPercentage + 5) / 5);&lt;br /&gt;
  }&lt;br /&gt;
  return Math.floor((criticalHitPercentage + 5) / 6);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcCriticalSkillChance(criticalHitPercentage) {&lt;br /&gt;
  if (criticalHitPercentage === 0) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  } else if (criticalHitPercentage &amp;lt;= 9) {&lt;br /&gt;
    return Math.floor((criticalHitPercentage + 7) / 3);&lt;br /&gt;
  }&lt;br /&gt;
  return Math.floor((criticalHitPercentage + 5) / 3);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcPiercingSkillChance(piercingHitPercentage) {&lt;br /&gt;
  if (piercingHitPercentage &amp;lt;= 9) {&lt;br /&gt;
    return Math.floor(piercingHitPercentage / 2);&lt;br /&gt;
  }&lt;br /&gt;
  return 5 + Math.floor((piercingHitPercentage - 10) / 4);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function magicResistanceToCoeff(magicResistance) {&lt;br /&gt;
  if (magicResistance) {&lt;br /&gt;
    return 2000 / (6 * magicResistance + 1000) - 1;&lt;br /&gt;
  }&lt;br /&gt;
  return 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createBattleValues(attacker, victim, battle, skillType) {&lt;br /&gt;
  var {&lt;br /&gt;
    mapping,&lt;br /&gt;
    constants: { polymorphPowerTable, skillPowerTable, marriageTable },&lt;br /&gt;
  } = battle;&lt;br /&gt;
  var calcAttackValues;&lt;br /&gt;
&lt;br /&gt;
  var missPercentage = 0;&lt;br /&gt;
  var attackValueMeleeMagic = 0;&lt;br /&gt;
  var attackValueMarriage = 0;&lt;br /&gt;
  var monsterResistanceMarriage = 0;&lt;br /&gt;
  var monsterResistance = 0;&lt;br /&gt;
  var typeBonus = 0;&lt;br /&gt;
  var raceBonus = 0;&lt;br /&gt;
  var raceResistance = 0;&lt;br /&gt;
  var stoneBonus = 0;&lt;br /&gt;
  var monsterBonus = 0;&lt;br /&gt;
  var elementBonus = [0, 0, 0, 0, 0, 0]; // fire, ice, lightning, earth, darkness, wind, order doesn't matter&lt;br /&gt;
  var defenseMarriage = 0;&lt;br /&gt;
  var damageMultiplier = 1;&lt;br /&gt;
  var useDamage = 1;&lt;br /&gt;
  var defense = victim.defense;&lt;br /&gt;
  var defenseBoost = defense;&lt;br /&gt;
  var magicResistance = 0;&lt;br /&gt;
  var weaponDefense = 0;&lt;br /&gt;
  var tigerStrength = 0;&lt;br /&gt;
  var berserkBonus = 0;&lt;br /&gt;
  var blessingBonus = 0;&lt;br /&gt;
  var fearBonus = 0;&lt;br /&gt;
  var magicAttackValueMeleeMagic = 0;&lt;br /&gt;
  var criticalHitPercentage = attacker.criticalHit;&lt;br /&gt;
  var isPlayerVsPlayer = false;&lt;br /&gt;
  var piercingHitPercentage = attacker.piercingHit;&lt;br /&gt;
  var extraPiercingHitPercentage = Math.max(0, piercingHitPercentage - 100);&lt;br /&gt;
  var averageDamage = 0;&lt;br /&gt;
  var averageDamageResistance = 0;&lt;br /&gt;
  var skillDamage = 0;&lt;br /&gt;
  var skillDamageResistance = 0;&lt;br /&gt;
  var rankBonus = 0;&lt;br /&gt;
  var useDarkProtection = false;&lt;br /&gt;
  var darkProtectionPoint = 0;&lt;br /&gt;
  var defensePercent = 0;&lt;br /&gt;
  var damageBonus = 0;&lt;br /&gt;
  var empireMalus = 0;&lt;br /&gt;
  var sungMaStrBonus = 0;&lt;br /&gt;
  var sungmaStrMalus = 0;&lt;br /&gt;
  var whiteDragonElixir = 0;&lt;br /&gt;
  var steelDragonElixir = 0;&lt;br /&gt;
&lt;br /&gt;
  attacker.statAttackValue = calcStatAttackValue(attacker);&lt;br /&gt;
&lt;br /&gt;
  computePolymorphPoint(attacker, victim, polymorphPowerTable);&lt;br /&gt;
  computeHorse(attacker);&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker)) {&lt;br /&gt;
    if (weaponData.hasOwnProperty(attacker.weapon)) {&lt;br /&gt;
      attacker.weapon = createWeapon(attacker.weapon);&lt;br /&gt;
    } else {&lt;br /&gt;
      attacker.weapon = createWeapon(0);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    attacker.weapon.getValues(attacker.weaponUpgrade);&lt;br /&gt;
&lt;br /&gt;
    attackValueMeleeMagic =&lt;br /&gt;
      attacker.attackValuePercent + Math.min(100, attacker.attackMeleeMagic);&lt;br /&gt;
&lt;br /&gt;
    var weaponType = attacker.weapon.type;&lt;br /&gt;
&lt;br /&gt;
    if (skillType &amp;amp;&amp;amp; attacker.class === &amp;quot;archery&amp;quot;) {&lt;br /&gt;
      if (weaponType !== 2) {&lt;br /&gt;
        useDamage = 0;&lt;br /&gt;
        weaponType = 2;&lt;br /&gt;
      }&lt;br /&gt;
      defense = 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var weaponDefenseName = mapping.defenseWeapon[weaponType];&lt;br /&gt;
    var weaponDefenseBreakName = mapping.breakWeapon[weaponType];&lt;br /&gt;
&lt;br /&gt;
    if (victim.hasOwnProperty(weaponDefenseName)) {&lt;br /&gt;
      weaponDefense = victim[weaponDefenseName];&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isChecked(attacker.whiteDragonElixir)) {&lt;br /&gt;
      whiteDragonElixir = 10;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isPC(victim)) {&lt;br /&gt;
      isPlayerVsPlayer = true;&lt;br /&gt;
&lt;br /&gt;
      if (!skillType) {&lt;br /&gt;
        if (weaponType === 2 &amp;amp;&amp;amp; !isPolymorph(attacker)) {&lt;br /&gt;
          missPercentage = victim.arrowBlock;&lt;br /&gt;
        } else {&lt;br /&gt;
          missPercentage = victim.meleeBlock;&lt;br /&gt;
        }&lt;br /&gt;
        missPercentage +=&lt;br /&gt;
          victim.meleeArrowBlock -&lt;br /&gt;
          (missPercentage * victim.meleeArrowBlock) / 100;&lt;br /&gt;
&lt;br /&gt;
        criticalHitPercentage = calcCriticalHitChance(criticalHitPercentage);&lt;br /&gt;
        berserkBonus = calcBerserkBonus(skillPowerTable, victim);&lt;br /&gt;
        blessingBonus = calcBlessingBonus(skillPowerTable, victim);&lt;br /&gt;
        fearBonus = calcFearBonus(skillPowerTable, victim);&lt;br /&gt;
        averageDamageResistance = victim.averageDamageResistance;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      typeBonus = Math.max(1, attacker.humanBonus - victim.humanResistance);&lt;br /&gt;
      raceBonus = attacker[mapping.raceBonus[victim.race]];&lt;br /&gt;
      raceResistance = victim[mapping.raceResistance[attacker.race]];&lt;br /&gt;
&lt;br /&gt;
      calcElementCoeffPvP(elementBonus, mapping, attacker, victim);&lt;br /&gt;
&lt;br /&gt;
      if (weaponType !== 2 &amp;amp;&amp;amp; attacker.hasOwnProperty(weaponDefenseBreakName)) {&lt;br /&gt;
        weaponDefense -= attacker[weaponDefenseBreakName];&lt;br /&gt;
      }&lt;br /&gt;
    } else {&lt;br /&gt;
      if (isChecked(attacker.isMarried)) {&lt;br /&gt;
        if (isChecked(attacker.loveNecklace)) {&lt;br /&gt;
          attackValueMarriage = getMarriageBonusValue(&lt;br /&gt;
            attacker,&lt;br /&gt;
            marriageTable,&lt;br /&gt;
            &amp;quot;loveNecklace&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isChecked(attacker.loveEarrings)) {&lt;br /&gt;
          criticalHitPercentage += getMarriageBonusValue(&lt;br /&gt;
            attacker,&lt;br /&gt;
            marriageTable,&lt;br /&gt;
            &amp;quot;loveEarrings&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isChecked(attacker.harmonyEarrings)) {&lt;br /&gt;
          piercingHitPercentage += getMarriageBonusValue(&lt;br /&gt;
            attacker,&lt;br /&gt;
            marriageTable,&lt;br /&gt;
            &amp;quot;harmonyEarrings&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (isChecked(attacker.tigerStrength)) {&lt;br /&gt;
        tigerStrength = 40;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      for (var index = 0; index &amp;lt; elementBonus.length; index++) {&lt;br /&gt;
        var elementBonusName = mapping.elementBonus[index];&lt;br /&gt;
        var elementResistanceName = mapping.elementResistance[index];&lt;br /&gt;
&lt;br /&gt;
        if (attacker[elementBonusName] &amp;amp;&amp;amp; victim[elementBonusName]) {&lt;br /&gt;
          elementBonus[index] =&lt;br /&gt;
            50 * (attacker[elementBonusName] - victim[elementResistanceName]);&lt;br /&gt;
        } else {&lt;br /&gt;
          elementBonus[index] = 5 * attacker[elementBonusName];&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      var victimType = victim.type;&lt;br /&gt;
&lt;br /&gt;
      if (victimType !== -1) {&lt;br /&gt;
        typeBonus = attacker[mapping.typeFlag[victimType]];&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      monsterBonus = attacker.monsterBonus;&lt;br /&gt;
&lt;br /&gt;
      if (isStone(victim)) {&lt;br /&gt;
        stoneBonus = attacker.stoneBonus;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (isBoss(victim)) {&lt;br /&gt;
        if (skillType) {&lt;br /&gt;
          skillDamage += attacker.skillBossDamage;&lt;br /&gt;
        } else {&lt;br /&gt;
          averageDamage += attacker.bossDamage;&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (isChecked(attacker.onYohara)) {&lt;br /&gt;
        var sungmaStrDifference = attacker.sungmaStr - attacker.sungmaStrMalus;&lt;br /&gt;
&lt;br /&gt;
        if (sungmaStrDifference &amp;gt;= 0) {&lt;br /&gt;
          sungMaStrBonus = sungmaStrDifference;&lt;br /&gt;
        } else {&lt;br /&gt;
          sungmaStrMalus = 0.5;&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (skillType) {&lt;br /&gt;
      skillDamage += attacker.skillDamage;&lt;br /&gt;
    } else {&lt;br /&gt;
      averageDamage += attacker.averageDamage;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    rankBonus = getRankBonus(attacker);&lt;br /&gt;
    damageBonus = attacker.damageBonus;&lt;br /&gt;
&lt;br /&gt;
    if (isChecked(attacker.empireMalus)) {&lt;br /&gt;
      empireMalus = 1;&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    if (isPC(victim)) {&lt;br /&gt;
      if (isChecked(victim.isMarried)) {&lt;br /&gt;
        if (isChecked(victim.harmonyBracelet)) {&lt;br /&gt;
          monsterResistanceMarriage = getMarriageBonusValue(&lt;br /&gt;
            victim,&lt;br /&gt;
            marriageTable,&lt;br /&gt;
            &amp;quot;harmonyBracelet&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isChecked(victim.harmonyNecklace) &amp;amp;&amp;amp; !skillType) {&lt;br /&gt;
          defenseMarriage = getMarriageBonusValue(&lt;br /&gt;
            victim,&lt;br /&gt;
            marriageTable,&lt;br /&gt;
            &amp;quot;harmonyNecklace&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      monsterResistance = victim.monsterResistance;&lt;br /&gt;
&lt;br /&gt;
      for (var index = 0; index &amp;lt; elementBonus.length; index++) {&lt;br /&gt;
        var elementBonusName = mapping.elementBonus[index];&lt;br /&gt;
        var elementResistanceName = mapping.elementResistance[index];&lt;br /&gt;
&lt;br /&gt;
        if (attacker[elementBonusName]) {&lt;br /&gt;
          elementBonus[index] =&lt;br /&gt;
            80 * (attacker[elementBonusName] - victim[elementResistanceName]);&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (!skillType) {&lt;br /&gt;
        if (isMeleeAttacker(attacker)) {&lt;br /&gt;
          missPercentage = victim.meleeBlock;&lt;br /&gt;
          averageDamageResistance = victim.averageDamageResistance;&lt;br /&gt;
          berserkBonus = calcBerserkBonus(skillPowerTable, victim);&lt;br /&gt;
          blessingBonus = calcBlessingBonus(skillPowerTable, victim);&lt;br /&gt;
          fearBonus = calcFearBonus(skillPowerTable, victim);&lt;br /&gt;
        } else if (isRangeAttacker(attacker)) {&lt;br /&gt;
          missPercentage = victim.arrowBlock;&lt;br /&gt;
          weaponDefense = victim.arrowDefense;&lt;br /&gt;
          averageDamageResistance = victim.averageDamageResistance;&lt;br /&gt;
          berserkBonus = calcBerserkBonus(skillPowerTable, victim);&lt;br /&gt;
          blessingBonus = calcBlessingBonus(skillPowerTable, victim);&lt;br /&gt;
          fearBonus = calcFearBonus(skillPowerTable, victim);&lt;br /&gt;
        } else if (isMagicAttacker(attacker)) {&lt;br /&gt;
          missPercentage = victim.arrowBlock;&lt;br /&gt;
          skillDamageResistance = victim.skillDamageResistance;&lt;br /&gt;
          magicResistance = victim.magicResistance;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        missPercentage +=&lt;br /&gt;
          victim.meleeArrowBlock -&lt;br /&gt;
          (missPercentage * victim.meleeArrowBlock) / 100;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    typeBonus = 1;&lt;br /&gt;
    damageMultiplier = attacker.damageMultiplier;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillType) {&lt;br /&gt;
    criticalHitPercentage = calcCriticalSkillChance(criticalHitPercentage);&lt;br /&gt;
    piercingHitPercentage = calcPiercingSkillChance(piercingHitPercentage);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (isPC(victim)) {&lt;br /&gt;
    if (!skillType &amp;amp;&amp;amp; isChecked(victim.biologist70)) {&lt;br /&gt;
      defenseBoost = Math.floor((defenseBoost * 110) / 100);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    criticalHitPercentage = Math.max(&lt;br /&gt;
      0,&lt;br /&gt;
      criticalHitPercentage - victim.criticalHitResistance&lt;br /&gt;
    );&lt;br /&gt;
    piercingHitPercentage = Math.max(&lt;br /&gt;
      0,&lt;br /&gt;
      piercingHitPercentage - victim.piercingHitResistance&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    if (skillType) {&lt;br /&gt;
      skillDamageResistance = victim.skillDamageResistance;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      victim.useDarkProtection &amp;amp;&amp;amp;&lt;br /&gt;
      victim.class === &amp;quot;black_magic&amp;quot; &amp;amp;&amp;amp;&lt;br /&gt;
      victim.skillDarkProtection&lt;br /&gt;
    ) {&lt;br /&gt;
      useDarkProtection = true;&lt;br /&gt;
      darkProtectionPoint = calcDarkProtectionPoint(skillPowerTable, victim);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isMagicClass(victim)) {&lt;br /&gt;
      defensePercent = (-2 * victim.magicDefense * victim.defensePercent) / 100;&lt;br /&gt;
    } else {&lt;br /&gt;
      defensePercent = (-2 * defenseBoost * victim.defensePercent) / 100;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isChecked(victim.steelDragonElixir)) {&lt;br /&gt;
      steelDragonElixir = 10;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillType === &amp;quot;magic&amp;quot;) {&lt;br /&gt;
    attackValueMeleeMagic = 0;&lt;br /&gt;
    magicAttackValueMeleeMagic =&lt;br /&gt;
      attacker.attackMagic + Math.min(100, attacker.attackMeleeMagic);&lt;br /&gt;
    attackValueMarriage = 0;&lt;br /&gt;
    defense = 0;&lt;br /&gt;
    if (isDispell(attacker, 6)) {&lt;br /&gt;
      typeBonus = 0;&lt;br /&gt;
      raceBonus = 0;&lt;br /&gt;
      raceResistance = 0;&lt;br /&gt;
      stoneBonus = 0;&lt;br /&gt;
      monsterBonus = 0;&lt;br /&gt;
      for (var index = 0; index &amp;lt; elementBonus.length; index++) {&lt;br /&gt;
        elementBonus[index] = 0;&lt;br /&gt;
      }&lt;br /&gt;
    } else {&lt;br /&gt;
      magicResistance = victim.magicResistance;&lt;br /&gt;
    }&lt;br /&gt;
    weaponDefense = 0;&lt;br /&gt;
    calcAttackValues = calcMagicAttackValue;&lt;br /&gt;
  } else {&lt;br /&gt;
    calcAttackValues = calcSecondaryAttackValue;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  missPercentage = Math.min(100, missPercentage);&lt;br /&gt;
&lt;br /&gt;
  var bonusValues = {&lt;br /&gt;
    missPercentage: missPercentage,&lt;br /&gt;
    weaponBonusCoeff: 1,&lt;br /&gt;
    attackValueCoeff: 100 + attackValueMeleeMagic,&lt;br /&gt;
    attackValueMarriage: attackValueMarriage,&lt;br /&gt;
    monsterResistanceMarriageCoeff: 100 - monsterResistanceMarriage,&lt;br /&gt;
    monsterResistanceCoeff: 100 - monsterResistance,&lt;br /&gt;
    typeBonusCoeff: typeBonus,&lt;br /&gt;
    raceBonusCoeff: raceBonus,&lt;br /&gt;
    raceResistanceCoeff: raceResistance,&lt;br /&gt;
    stoneBonusCoeff: stoneBonus,&lt;br /&gt;
    monsterBonusCoeff: monsterBonus,&lt;br /&gt;
    elementBonusCoeff: elementBonus,&lt;br /&gt;
    damageMultiplier: damageMultiplier,&lt;br /&gt;
    useDamage: useDamage,&lt;br /&gt;
    defense: defense,&lt;br /&gt;
    defenseBoost: defenseBoost,&lt;br /&gt;
    defenseMarriage: defenseMarriage,&lt;br /&gt;
    tigerStrengthCoeff: 100 + tigerStrength,&lt;br /&gt;
    magicResistanceCoeff: magicResistanceToCoeff(magicResistance),&lt;br /&gt;
    weaponDefenseCoeff: 100 - weaponDefense,&lt;br /&gt;
    berserkBonusCoeff: 100 + berserkBonus,&lt;br /&gt;
    blessingBonusCoeff: 100 - blessingBonus,&lt;br /&gt;
    fearBonusCoeff: 100 - fearBonus,&lt;br /&gt;
    magicAttackValueCoeff: 100 + magicAttackValueMeleeMagic,&lt;br /&gt;
    isPlayerVsPlayer: isPlayerVsPlayer,&lt;br /&gt;
    extraPiercingHitCoeff: 5 * extraPiercingHitPercentage,&lt;br /&gt;
    averageDamageCoeff: 100 + averageDamage,&lt;br /&gt;
    averageDamageResistanceCoeff: 100 - Math.min(99, averageDamageResistance),&lt;br /&gt;
    skillDamageCoeff: 100 + skillDamage,&lt;br /&gt;
    skillDamageResistanceCoeff: 100 - Math.min(99, skillDamageResistance),&lt;br /&gt;
    useDarkProtection: useDarkProtection,&lt;br /&gt;
    darkProtectionPoint: darkProtectionPoint,&lt;br /&gt;
    darkProtectionSp: victim.darkProtectionSp,&lt;br /&gt;
    rankBonusCoeff: 100 + rankBonus,&lt;br /&gt;
    defensePercent: Math.floor(defensePercent),&lt;br /&gt;
    damageBonusCoeff: Math.min(20, damageBonus),&lt;br /&gt;
    empireMalusCoeff: 10 - empireMalus,&lt;br /&gt;
    sungMaStrBonusCoeff: 10000 + sungMaStrBonus,&lt;br /&gt;
    sungmaStrMalusCoeff: sungmaStrMalus,&lt;br /&gt;
    whiteDragonElixirCoeff: 100 + whiteDragonElixir,&lt;br /&gt;
    steelDragonElixirCoeff: 100 - steelDragonElixir,&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  criticalHitPercentage = Math.min(criticalHitPercentage, 100);&lt;br /&gt;
  piercingHitPercentage = Math.min(piercingHitPercentage, 100);&lt;br /&gt;
&lt;br /&gt;
  var damageTypeCombinaison = [&lt;br /&gt;
    {&lt;br /&gt;
      isCriticalHit: false,&lt;br /&gt;
      isPiercingHit: false,&lt;br /&gt;
      weight:&lt;br /&gt;
        (100 - criticalHitPercentage) *&lt;br /&gt;
        (100 - piercingHitPercentage) *&lt;br /&gt;
        (100 - missPercentage),&lt;br /&gt;
      name: &amp;quot;normalHit&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      isCriticalHit: true,&lt;br /&gt;
      isPiercingHit: false,&lt;br /&gt;
      weight:&lt;br /&gt;
        criticalHitPercentage *&lt;br /&gt;
        (100 - piercingHitPercentage) *&lt;br /&gt;
        (100 - missPercentage),&lt;br /&gt;
      name: &amp;quot;criticalHit&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      isCriticalHit: false,&lt;br /&gt;
      isPiercingHit: true,&lt;br /&gt;
      weight:&lt;br /&gt;
        (100 - criticalHitPercentage) *&lt;br /&gt;
        piercingHitPercentage *&lt;br /&gt;
        (100 - missPercentage),&lt;br /&gt;
      name: &amp;quot;piercingHit&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      isCriticalHit: true,&lt;br /&gt;
      isPiercingHit: true,&lt;br /&gt;
      weight:&lt;br /&gt;
        criticalHitPercentage * piercingHitPercentage * (100 - missPercentage),&lt;br /&gt;
      name: &amp;quot;criticalPiercingHit&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
  ];&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    attacker: attacker,&lt;br /&gt;
    victim: victim,&lt;br /&gt;
    attackFactor: calcAttackFactor(attacker, victim),&lt;br /&gt;
    mainAttackValue: calcMainAttackValue(attacker),&lt;br /&gt;
    attackValues: calcAttackValues(attacker, isPlayerVsPlayer),&lt;br /&gt;
    bonusValues: bonusValues,&lt;br /&gt;
    damageTypeCombinaison: damageTypeCombinaison,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateBattleValues(battleValues, skillFormula, skillInfo) {&lt;br /&gt;
  var weaponBonus = 0;&lt;br /&gt;
  var skillWard = 0;&lt;br /&gt;
  var skillBonus = 0;&lt;br /&gt;
  var skillBonusByBonus = 0;&lt;br /&gt;
  var { attacker: attacker, bonusValues: bonusValues } = battleValues;&lt;br /&gt;
  var {&lt;br /&gt;
    range: [minVariation, maxVariation],&lt;br /&gt;
  } = skillInfo;&lt;br /&gt;
  var variationLength = maxVariation - minVariation + 1;&lt;br /&gt;
&lt;br /&gt;
  if (skillInfo.hasOwnProperty(&amp;quot;weaponBonus&amp;quot;)) {&lt;br /&gt;
    var [weaponType, weaponBonusValue] = skillInfo.weaponBonus;&lt;br /&gt;
&lt;br /&gt;
    if (weaponType === attacker.weapon.type) {&lt;br /&gt;
      weaponBonus = weaponBonusValue;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillInfo.skillBonus) {&lt;br /&gt;
    skillBonus = skillInfo.skillBonus;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillInfo.skillWard) {&lt;br /&gt;
    skillWard = skillInfo.skillWard;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillInfo.skillBonusByBonus) {&lt;br /&gt;
    skillBonusByBonus = skillInfo.skillBonusByBonus;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillInfo.removeWeaponReduction) {&lt;br /&gt;
    bonusValues.weaponDefenseCoeff = 100;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  bonusValues.weaponBonusCoeff = 100 + weaponBonus;&lt;br /&gt;
  bonusValues.skillWardCoeff = 1 - skillWard / 100;&lt;br /&gt;
  bonusValues.skillBonusCoeff = 1 + skillBonus / 100;&lt;br /&gt;
  bonusValues.skillBonusByBonusCoeff = 100 + skillBonusByBonus;&lt;br /&gt;
&lt;br /&gt;
  battleValues.skillFormula = skillFormula;&lt;br /&gt;
  battleValues.skillRange = skillInfo.range;&lt;br /&gt;
  battleValues.attackValues.totalCardinal *= variationLength;&lt;br /&gt;
  battleValues.attackValues.possibleDamageCount *= variationLength;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcWeights(minValue, maxValue, minInterval) {&lt;br /&gt;
  var firstWeightLimit = minValue + minInterval - 1;&lt;br /&gt;
  var lastWeightsLimit = maxValue - minInterval + 1;&lt;br /&gt;
  var weights = [];&lt;br /&gt;
&lt;br /&gt;
  for (var value = minValue; value &amp;lt; firstWeightLimit; value++) {&lt;br /&gt;
    weights.push(value - minValue + 1);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (var value = firstWeightLimit; value &amp;lt;= lastWeightsLimit; value++) {&lt;br /&gt;
    weights.push(minInterval);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (var value = lastWeightsLimit + 1; value &amp;lt;= maxValue; value++) {&lt;br /&gt;
    weights.push(maxValue - value + 1);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return weights;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcBerserkBonus(skillPowerTable, victim) {&lt;br /&gt;
  if (!isChecked(victim.useBerserk) || victim.class !== &amp;quot;body&amp;quot;) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var skillPower = getSkillPower(victim.skillBerserk, skillPowerTable);&lt;br /&gt;
&lt;br /&gt;
  if (!skillPower) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var berserkBonus = Math.floor(skillPower * 25);&lt;br /&gt;
&lt;br /&gt;
  return berserkBonus;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcBlessingBonus(skillPowerTable, victim) {&lt;br /&gt;
  if (!isChecked(victim.isBlessed)) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var int = victim.intBlessing;&lt;br /&gt;
  var dex = victim.dexBlessing;&lt;br /&gt;
  var skillPower = getSkillPower(victim.skillBlessing, skillPowerTable);&lt;br /&gt;
&lt;br /&gt;
  if (!skillPower) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var blessingBonus = floorMultiplication(&lt;br /&gt;
    ((int * 0.3 + 5) * (2 * skillPower + 0.5) + 0.3 * dex) / (skillPower + 2.3),&lt;br /&gt;
    1&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  if (victim.class === &amp;quot;dragon&amp;quot; &amp;amp;&amp;amp; isChecked(victim.blessingOnself)) {&lt;br /&gt;
    blessingBonus = floorMultiplication(blessingBonus, 1.1);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return blessingBonus;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcFearBonus(skillPowerTable, victim) {&lt;br /&gt;
  if (!isChecked(victim.useFear) || victim.class !== &amp;quot;weaponary&amp;quot;) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var skillPower = getSkillPower(victim.skillFear, skillPowerTable);&lt;br /&gt;
&lt;br /&gt;
  if (!skillPower) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var fearBonus = 5 + Math.floor(skillPower * 20);&lt;br /&gt;
&lt;br /&gt;
  return fearBonus;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcDarkProtectionPoint(skillPowerTable, victim) {&lt;br /&gt;
  var skillPower = getSkillPower(victim.skillDarkProtection, skillPowerTable);&lt;br /&gt;
&lt;br /&gt;
  return floorMultiplication(100 - victim.int * 0.84 * skillPower, 1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSkillFormula(battle, skillId, battleValues, removeSkillVariation) {&lt;br /&gt;
  var { attacker, victim, attackFactor } = battleValues;&lt;br /&gt;
  var skillPowerTable = battle.constants.skillPowerTable;&lt;br /&gt;
&lt;br /&gt;
  var skillFormula;&lt;br /&gt;
  var skillInfo = { range: [0, 0] };&lt;br /&gt;
&lt;br /&gt;
  var { class: attackerClass, level: lv, vit, str, int, dex } = attacker;&lt;br /&gt;
&lt;br /&gt;
  if (skillId &amp;lt;= 9) {&lt;br /&gt;
    var skillPower = getSkillPower(&lt;br /&gt;
      attacker[&amp;quot;attackSkill&amp;quot; + skillId],&lt;br /&gt;
      skillPowerTable&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    var improvedBySkillBonus = false;&lt;br /&gt;
    var improvedByBonus = false;&lt;br /&gt;
&lt;br /&gt;
    if (attackerClass === &amp;quot;body&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Triple lacération&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.1 * atk + (0.5 * atk + 1.5 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Moulinet à l'épée&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              3 * atk + (0.8 * atk + 5 * str + 3 * dex + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Accélération&lt;br /&gt;
        case 5:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * atk + (atk + dex * 3 + str * 7 + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Volonté de vivre&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              (3 * atk + (atk + 1.5 * str) * skillPower) * 1.07,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          break;&lt;br /&gt;
        // Tremblement de terre&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              3 * atk +&lt;br /&gt;
                (0.9 * atk + variation + 5 * str + 3 * dex + lv) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;mental&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Attaque de l'esprit&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2.3 * atk + (4 * atk + 4 * str + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Attaque de la paume&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2.3 * atk + (3 * atk + 4 * str + 3 * vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Charge&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * atk + (2 * atk + 2 * dex + 2 * vit + 4 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          break;&lt;br /&gt;
        // Coup d'épée&lt;br /&gt;
        case 5:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * atk + (atk + 3 * dex + 5 * str + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Orbe de l'épée&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              (2 * atk + (2 * atk + 2 * dex + 2 * vit + 4 * str) * skillPower) *&lt;br /&gt;
                1.1,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          break;&lt;br /&gt;
        // Tremblement de terre&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              3 * atk +&lt;br /&gt;
                (0.9 * atk + variation + 5 * str + 3 * dex + lv) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;blade_fight&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Embuscade&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk + (1.2 * atk + variation + 4 * dex + 4 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [1, 50];&lt;br /&gt;
          skillInfo.range = [500, 700];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Attaque rapide&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk + (1.6 * atk + variation + 7 * dex + 7 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [1, 35];&lt;br /&gt;
          skillInfo.range = [200, 300];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Dague filante&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * atk + (0.5 * atk + 9 * dex + 7 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Brume empoisonnée&lt;br /&gt;
        case 5:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * lv + (atk + 3 * str + 18 * dex) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Poison insidieux&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              (2 * lv + (atk + 3 * str + 18 * dex) * skillPower) * 1.1,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          break;&lt;br /&gt;
        // Étoiles brillantes&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk + (1.7 * atk + variation + 6 * dex + 5 * lv) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;archery&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Tir à répétition&lt;br /&gt;
        // case 1:&lt;br /&gt;
        //   skillFormula = function (atk) {&lt;br /&gt;
        //     return floorMultiplication(&lt;br /&gt;
        //       atk + 0.2 * atk * Math.floor(2 + 6 * skillPower) + (0.8 * atk + 8 * dex * attackFactor + 2 * int) * skillPower,&lt;br /&gt;
        //       1&lt;br /&gt;
        //     );&lt;br /&gt;
        //   };&lt;br /&gt;
        //   improvedByBonus = true;&lt;br /&gt;
        //   break;&lt;br /&gt;
        // Pluie de flèches&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk + (1.7 * atk + 5 * dex + str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Flèche de feu&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.5 * atk + (2.6 * atk + 0.9 * int + variation) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [100, 300];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Foulée de plume&lt;br /&gt;
        case 4:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              (3 * dex + 200 + 2 * str + 2 * int) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.removeWeaponReduction = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Flèche empoisonnée&lt;br /&gt;
        case 5:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk +&lt;br /&gt;
                (1.4 * atk + variation + 7 * dex + 4 * str + 4 * int) *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [100, 200];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Coup étincelant&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              (atk +&lt;br /&gt;
                (1.2 * atk + variation + 6 * dex + 3 * str + 3 * int) *&lt;br /&gt;
                  skillPower) *&lt;br /&gt;
                1.2,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [100, 200];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Tir tempête&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.9 * atk + (2.6 * atk + variation) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;weaponary&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Toucher brûlant&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk +&lt;br /&gt;
                2 * lv +&lt;br /&gt;
                2 * int +&lt;br /&gt;
                (2 * atk + 4 * str + 14 * int) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Tourbillon du dragon&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.1 * atk +&lt;br /&gt;
                2 * lv +&lt;br /&gt;
                2 * int +&lt;br /&gt;
                (1.5 * atk + str + 12 * int) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Contre-sort&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              40 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                2 * int +&lt;br /&gt;
                (10 * int + 7 * mav + variation) * attackFactor * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [50, 100];&lt;br /&gt;
          break;&lt;br /&gt;
        // Coup démoniaque&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.9 * atk + (2.6 * atk + variation) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;black_magic&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Attaque des ténèbres&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              40 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                2 * int +&lt;br /&gt;
                (13 * int + 6 * mav + variation) * attackFactor * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [50, 100];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Attaque de flammes&lt;br /&gt;
        // case 2:&lt;br /&gt;
        //   skillFormula = function (mav, variation) {&lt;br /&gt;
        //     return floorMultiplication(&lt;br /&gt;
        //       5 * lv + 2 * int + (7 * int + 8 * mav + 4 * str + 2 * vit + variation) * skillPower,&lt;br /&gt;
        //       1&lt;br /&gt;
        //     );&lt;br /&gt;
        //   };&lt;br /&gt;
        //   skillInfo.range = [180, 100];&lt;br /&gt;
        //   improvedByBonus = true;&lt;br /&gt;
        //   break;&lt;br /&gt;
        // Esprit de flammes&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              30 +&lt;br /&gt;
                2 * lv +&lt;br /&gt;
                2 * int +&lt;br /&gt;
                (7 * int + 6 * mav + variation) * attackFactor * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [200, 500];&lt;br /&gt;
          break;&lt;br /&gt;
        // Frappe de l'esprit&lt;br /&gt;
        // case 5:&lt;br /&gt;
        //   skillFormula = function (mav, variation) {&lt;br /&gt;
        //     return floorMultiplication(&lt;br /&gt;
        //       40 + 2 * lv + 2 * int + (2 * vit + 2 * dex + 13 * int + 6 * mav + variation) * attackFactor * skillPower,&lt;br /&gt;
        //       1&lt;br /&gt;
        //     );&lt;br /&gt;
        //   };&lt;br /&gt;
        //   skillInfo.range = [180, 200];&lt;br /&gt;
        //   break;&lt;br /&gt;
        // Orbe des ténèbres&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (mav) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              120 +&lt;br /&gt;
                6 * lv +&lt;br /&gt;
                (5 * vit + 5 * dex + 29 * int + 9 * mav) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Vague mortelle&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              120 +&lt;br /&gt;
                6 * lv +&lt;br /&gt;
                (5 * vit + 5 * dex + 30 * int + variation + 9 * mav) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;dragon&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Talisman volant&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (mav) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              70 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                (18 * int + 7 * str + 5 * mav + 50) * attackFactor * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [4, 10];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Dragon chassant&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (mav) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              60 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                (16 * int + 6 * dex + 6 * mav + 120) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [4, 10];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Rugissement du dragon&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (mav) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              70 +&lt;br /&gt;
                3 * lv +&lt;br /&gt;
                (20 * int + 3 * str + 10 * mav + 100) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [4, 10];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Météore&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              120 +&lt;br /&gt;
                6 * lv +&lt;br /&gt;
                (5 * vit + 5 * dex + 30 * int + variation + 9 * mav) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;heal&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Jet de foudre&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              60 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                (8 * int + 2 * dex + 8 * mav + variation) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [6, 10];&lt;br /&gt;
          skillInfo.range = [5 * int, 15 * int];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Invocation de foudre&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              40 +&lt;br /&gt;
                4 * lv +&lt;br /&gt;
                (13 * int + 2 * str + 10 * mav + variation) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [6, 10];&lt;br /&gt;
          skillInfo.range = [5 * int, 16 * int];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Griffe de foudre&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              50 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                (8 * int + 2 * str + 8 * mav + variation) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 800];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;lycan&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Déchiqueter&lt;br /&gt;
        // case 1:&lt;br /&gt;
        //   skillFormula = function (atk) {&lt;br /&gt;
        //     return floorMultiplication(&lt;br /&gt;
        //       1.1 * atk + (0.3 * atk + 1.5 * str) * skillPower,&lt;br /&gt;
        //       1&lt;br /&gt;
        //     );&lt;br /&gt;
        //   };&lt;br /&gt;
        //   skillInfo.weaponBonus = [5, 54];&lt;br /&gt;
        //   improvedByBonus = true;&lt;br /&gt;
        //   break;&lt;br /&gt;
        // Souffle de loup&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * atk + (atk + 3 * dex + 5 * str + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [5, 35];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Bond de loup&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk + (1.6 * atk + 200 + 7 * dex + 7 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [5, 35];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Griffe de loup&lt;br /&gt;
        case 4:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              3 * atk + (0.8 * atk + 6 * str + 2 * dex + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Tempête cinglante&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.8 * atk +&lt;br /&gt;
                (atk + 6 * dex + variation + 3 * str + lv) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
    if (improvedBySkillBonus) {&lt;br /&gt;
      skillInfo.skillBonus =&lt;br /&gt;
        16 * getSkillPower(attacker.skillBonus, skillPowerTable);&lt;br /&gt;
&lt;br /&gt;
      var skillWardChoice = victim.skillWardChoice;&lt;br /&gt;
&lt;br /&gt;
      if (skillWardChoice &amp;amp;&amp;amp; skillWardChoice === attackerClass) {&lt;br /&gt;
        skillInfo.skillWard =&lt;br /&gt;
          24 * getSkillPower(victim.skillWard, skillPowerTable);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (improvedByBonus) {&lt;br /&gt;
      skillInfo.skillBonusByBonus = attacker[&amp;quot;skillBonus&amp;quot; + skillId];&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (removeSkillVariation) {&lt;br /&gt;
      var averageVariation = (skillInfo.range[0] + skillInfo.range[0]) / 2;&lt;br /&gt;
      skillInfo.range = [averageVariation, averageVariation];&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    var skillPower = getSkillPower(&lt;br /&gt;
      attacker[&amp;quot;horseSkill&amp;quot; + skillId],&lt;br /&gt;
      skillPowerTable&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    switch (skillId) {&lt;br /&gt;
      // Combat équestre&lt;br /&gt;
      case 137:&lt;br /&gt;
        skillFormula = function (atk) {&lt;br /&gt;
          return floorMultiplication(atk + 2 * atk * skillPower, 1);&lt;br /&gt;
        };&lt;br /&gt;
        break;&lt;br /&gt;
      // Charge à cheval&lt;br /&gt;
      case 138:&lt;br /&gt;
        skillFormula = function (atk) {&lt;br /&gt;
          return floorMultiplication(&lt;br /&gt;
            2.4 * (200 + 1.5 * lv) + 600 * skillPower,&lt;br /&gt;
            1&lt;br /&gt;
          );&lt;br /&gt;
        };&lt;br /&gt;
        break;&lt;br /&gt;
      // Vague de Pouvoir&lt;br /&gt;
      case 139:&lt;br /&gt;
        skillFormula = function (atk) {&lt;br /&gt;
          return floorMultiplication(&lt;br /&gt;
            2 * (200 + 1.5 * lv) + 600 * skillPower,&lt;br /&gt;
            1&lt;br /&gt;
          );&lt;br /&gt;
        };&lt;br /&gt;
        break;&lt;br /&gt;
      // Grêle de flèches&lt;br /&gt;
      case 140:&lt;br /&gt;
        skillFormula = function (atk) {&lt;br /&gt;
          return floorMultiplication(atk + 2 * atk * skillPower, 1);&lt;br /&gt;
        };&lt;br /&gt;
        break;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  updateBattleValues(battleValues, skillFormula, skillInfo);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcMagicAttackValueAugmentation(&lt;br /&gt;
  magicAttackValueWeapon,&lt;br /&gt;
  magicAttackValueBonus&lt;br /&gt;
) {&lt;br /&gt;
  if (magicAttackValueBonus) {&lt;br /&gt;
    return Math.max(&lt;br /&gt;
      1,&lt;br /&gt;
      0.0025056 *&lt;br /&gt;
        magicAttackValueBonus ** 0.602338 *&lt;br /&gt;
        magicAttackValueWeapon ** 1.20476&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
  return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getMagicAttackValueAugmentation(&lt;br /&gt;
  minMagicAttackValue,&lt;br /&gt;
  maxMagicAttackValue,&lt;br /&gt;
  magicAttackValueBonus&lt;br /&gt;
) {&lt;br /&gt;
  var magicAttackValueAugmentation = [];&lt;br /&gt;
&lt;br /&gt;
  for (&lt;br /&gt;
    var magicAttackValue = minMagicAttackValue;&lt;br /&gt;
    magicAttackValue &amp;lt;= maxMagicAttackValue;&lt;br /&gt;
    magicAttackValue++&lt;br /&gt;
  ) {&lt;br /&gt;
    magicAttackValueAugmentation.push(&lt;br /&gt;
      calcMagicAttackValueAugmentation(magicAttackValue, magicAttackValueBonus)&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return magicAttackValueAugmentation;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcPhysicalDamage(battleValues) {&lt;br /&gt;
  var {&lt;br /&gt;
    attackFactor,&lt;br /&gt;
    mainAttackValue,&lt;br /&gt;
    attackValues: {&lt;br /&gt;
      minAttackValue,&lt;br /&gt;
      maxAttackValue,&lt;br /&gt;
      attackValueOther,&lt;br /&gt;
      weights,&lt;br /&gt;
      weapon,&lt;br /&gt;
    },&lt;br /&gt;
    bonusValues,&lt;br /&gt;
    damageTypeCombinaison,&lt;br /&gt;
  } = battleValues;&lt;br /&gt;
&lt;br /&gt;
  var damageWeightedByType = {};&lt;br /&gt;
&lt;br /&gt;
  if (bonusValues.missPercentage) {&lt;br /&gt;
    damageWeightedByType.miss = bonusValues.missPercentage / 100;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (var damageType of damageTypeCombinaison) {&lt;br /&gt;
    if (!damageType.weight) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var damageWeighted = {};&lt;br /&gt;
    damageWeightedByType[damageType.name] = damageWeighted;&lt;br /&gt;
&lt;br /&gt;
    for (&lt;br /&gt;
      var attackValue = minAttackValue;&lt;br /&gt;
      attackValue &amp;lt;= maxAttackValue;&lt;br /&gt;
      attackValue++&lt;br /&gt;
    ) {&lt;br /&gt;
      var weight = weights[attackValue - minAttackValue] * damageType.weight;&lt;br /&gt;
&lt;br /&gt;
      var secondaryAttackValue = 2 * attackValue + attackValueOther;&lt;br /&gt;
      var rawDamage =&lt;br /&gt;
        mainAttackValue +&lt;br /&gt;
        floorMultiplication(attackFactor, secondaryAttackValue);&lt;br /&gt;
&lt;br /&gt;
      var damageWithPrimaryBonuses = calcDamageWithPrimaryBonuses(&lt;br /&gt;
        rawDamage,&lt;br /&gt;
        bonusValues&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      var minPiercingDamage =&lt;br /&gt;
        damageWithPrimaryBonuses -&lt;br /&gt;
        bonusValues.defenseBoost -&lt;br /&gt;
        bonusValues.defenseMarriage;&lt;br /&gt;
&lt;br /&gt;
      if (minPiercingDamage &amp;lt;= 2) {&lt;br /&gt;
        for (var damage = 1; damage &amp;lt;= 5; damage++) {&lt;br /&gt;
          saveFinalDamage(&lt;br /&gt;
            damage,&lt;br /&gt;
            bonusValues,&lt;br /&gt;
            damageType,&lt;br /&gt;
            weapon,&lt;br /&gt;
            minPiercingDamage,&lt;br /&gt;
            damageWithPrimaryBonuses,&lt;br /&gt;
            damageWeighted,&lt;br /&gt;
            weight / 5&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
      } else {&lt;br /&gt;
        saveFinalDamage(&lt;br /&gt;
          minPiercingDamage,&lt;br /&gt;
          bonusValues,&lt;br /&gt;
          damageType,&lt;br /&gt;
          weapon,&lt;br /&gt;
          minPiercingDamage,&lt;br /&gt;
          damageWithPrimaryBonuses,&lt;br /&gt;
          damageWeighted,&lt;br /&gt;
          weight&lt;br /&gt;
        );&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return damageWeightedByType;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcPhysicalSkillDamage(battleValues) {&lt;br /&gt;
  var {&lt;br /&gt;
    attackFactor,&lt;br /&gt;
    mainAttackValue,&lt;br /&gt;
    attackValues: {&lt;br /&gt;
      minAttackValue,&lt;br /&gt;
      maxAttackValue,&lt;br /&gt;
      attackValueOther,&lt;br /&gt;
      weights,&lt;br /&gt;
      weapon,&lt;br /&gt;
    },&lt;br /&gt;
    bonusValues,&lt;br /&gt;
    damageTypeCombinaison,&lt;br /&gt;
    skillFormula,&lt;br /&gt;
    skillRange: [minVariation, maxVariation],&lt;br /&gt;
  } = battleValues;&lt;br /&gt;
&lt;br /&gt;
  var damageWeightedByType = {};&lt;br /&gt;
&lt;br /&gt;
  for (var damageType of damageTypeCombinaison) {&lt;br /&gt;
    if (!damageType.weight) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var damageWeighted = {};&lt;br /&gt;
    var savedDamage = {};&lt;br /&gt;
    var savedCriticalDamage = {};&lt;br /&gt;
&lt;br /&gt;
    damageWeightedByType[damageType.name] = damageWeighted;&lt;br /&gt;
&lt;br /&gt;
    for (&lt;br /&gt;
      var attackValue = minAttackValue;&lt;br /&gt;
      attackValue &amp;lt;= maxAttackValue;&lt;br /&gt;
      attackValue++&lt;br /&gt;
    ) {&lt;br /&gt;
      var weight = weights[attackValue - minAttackValue] * damageType.weight;&lt;br /&gt;
&lt;br /&gt;
      var secondaryAttackValue = 2 * attackValue + attackValueOther;&lt;br /&gt;
      var rawDamage =&lt;br /&gt;
        mainAttackValue +&lt;br /&gt;
        floorMultiplication(attackFactor, secondaryAttackValue);&lt;br /&gt;
&lt;br /&gt;
      var damageWithPrimaryBonuses = calcDamageWithPrimaryBonuses(&lt;br /&gt;
        rawDamage,&lt;br /&gt;
        bonusValues&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      for (&lt;br /&gt;
        var variation = minVariation;&lt;br /&gt;
        variation &amp;lt;= maxVariation;&lt;br /&gt;
        variation++&lt;br /&gt;
      ) {&lt;br /&gt;
        if (damageWithPrimaryBonuses &amp;lt;= 2) {&lt;br /&gt;
          for (var damage = 1; damage &amp;lt;= 5; damage++) {&lt;br /&gt;
            var damageWithFormula = skillFormula(&lt;br /&gt;
              damage * bonusValues.useDamage,&lt;br /&gt;
              variation&lt;br /&gt;
            );&lt;br /&gt;
&lt;br /&gt;
            damageWithFormula = Math.floor(&lt;br /&gt;
              (damageWithFormula * bonusValues.weaponBonusCoeff) / 100&lt;br /&gt;
            );&lt;br /&gt;
&lt;br /&gt;
            saveFinalSkillDamage(&lt;br /&gt;
              damageWithFormula,&lt;br /&gt;
              bonusValues,&lt;br /&gt;
              damageType,&lt;br /&gt;
              weapon,&lt;br /&gt;
              damageWithPrimaryBonuses,&lt;br /&gt;
              damageWeighted,&lt;br /&gt;
              weight&lt;br /&gt;
            );&lt;br /&gt;
          }&lt;br /&gt;
        } else {&lt;br /&gt;
          var damageWithFormula = skillFormula(&lt;br /&gt;
            damageWithPrimaryBonuses * bonusValues.useDamage,&lt;br /&gt;
            variation&lt;br /&gt;
          );&lt;br /&gt;
&lt;br /&gt;
          if (savedDamage.hasOwnProperty(damageWithFormula)) {&lt;br /&gt;
            var finalDamage = savedDamage[damageWithFormula];&lt;br /&gt;
            damageWeighted[finalDamage] += weight;&lt;br /&gt;
            continue;&lt;br /&gt;
          }&lt;br /&gt;
&lt;br /&gt;
          var finalDamage = Math.floor(&lt;br /&gt;
            (damageWithFormula * bonusValues.weaponBonusCoeff) / 100&lt;br /&gt;
          );&lt;br /&gt;
&lt;br /&gt;
          finalDamage = saveFinalSkillDamage(&lt;br /&gt;
            finalDamage,&lt;br /&gt;
            bonusValues,&lt;br /&gt;
            damageType,&lt;br /&gt;
            weapon,&lt;br /&gt;
            damageWithPrimaryBonuses,&lt;br /&gt;
            damageWeighted,&lt;br /&gt;
            weight,&lt;br /&gt;
            savedCriticalDamage&lt;br /&gt;
          );&lt;br /&gt;
&lt;br /&gt;
          if (finalDamage) {&lt;br /&gt;
            savedDamage[damageWithFormula] = finalDamage;&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return damageWeightedByType;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcMagicSkillDamage(battleValues) {&lt;br /&gt;
  var {&lt;br /&gt;
    attackValues: {&lt;br /&gt;
      minMagicAttackValue,&lt;br /&gt;
      maxMagicAttackValue,&lt;br /&gt;
      magicAttackValueAugmentation,&lt;br /&gt;
      weights,&lt;br /&gt;
      weapon,&lt;br /&gt;
    },&lt;br /&gt;
    bonusValues,&lt;br /&gt;
    damageTypeCombinaison,&lt;br /&gt;
    skillFormula,&lt;br /&gt;
    skillRange: [minVariation, maxVariation],&lt;br /&gt;
  } = battleValues;&lt;br /&gt;
&lt;br /&gt;
  var damageWeightedByType = {};&lt;br /&gt;
&lt;br /&gt;
  for (var damageType of damageTypeCombinaison) {&lt;br /&gt;
    if (!damageType.weight) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var damageWeighted = {};&lt;br /&gt;
    var savedDamage = {};&lt;br /&gt;
    var savedCriticalDamage = {};&lt;br /&gt;
&lt;br /&gt;
    damageWeightedByType[damageType.name] = damageWeighted;&lt;br /&gt;
&lt;br /&gt;
    for (&lt;br /&gt;
      var magicAttackValue = minMagicAttackValue;&lt;br /&gt;
      magicAttackValue &amp;lt;= maxMagicAttackValue;&lt;br /&gt;
      magicAttackValue++&lt;br /&gt;
    ) {&lt;br /&gt;
      var index = magicAttackValue - minMagicAttackValue;&lt;br /&gt;
      var weight = weights[index] * damageType.weight;&lt;br /&gt;
&lt;br /&gt;
      for (&lt;br /&gt;
        var variation = minVariation;&lt;br /&gt;
        variation &amp;lt;= maxVariation;&lt;br /&gt;
        variation++&lt;br /&gt;
      ) {&lt;br /&gt;
        var rawDamage = skillFormula(&lt;br /&gt;
          magicAttackValue + magicAttackValueAugmentation[index],&lt;br /&gt;
          variation&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        if (savedDamage.hasOwnProperty(rawDamage)) {&lt;br /&gt;
          var finalDamage = savedDamage[rawDamage];&lt;br /&gt;
          damageWeighted[finalDamage] += weight;&lt;br /&gt;
          continue;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var damageWithPrimaryBonuses = Math.floor(&lt;br /&gt;
          (rawDamage * bonusValues.weaponBonusCoeff) / 100&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        damageWithPrimaryBonuses = calcDamageWithPrimaryBonuses(&lt;br /&gt;
          damageWithPrimaryBonuses,&lt;br /&gt;
          bonusValues&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        if (damageWithPrimaryBonuses &amp;lt;= 2) {&lt;br /&gt;
          for (var damage = 1; damage &amp;lt;= 5; damage++) {&lt;br /&gt;
            saveFinalSkillDamage(&lt;br /&gt;
              damage,&lt;br /&gt;
              bonusValues,&lt;br /&gt;
              damageType,&lt;br /&gt;
              weapon,&lt;br /&gt;
              damageWithPrimaryBonuses,&lt;br /&gt;
              damageWeighted,&lt;br /&gt;
              weight&lt;br /&gt;
            );&lt;br /&gt;
          }&lt;br /&gt;
        } else {&lt;br /&gt;
          var finalDamage = saveFinalSkillDamage(&lt;br /&gt;
            damageWithPrimaryBonuses,&lt;br /&gt;
            bonusValues,&lt;br /&gt;
            damageType,&lt;br /&gt;
            weapon,&lt;br /&gt;
            damageWithPrimaryBonuses,&lt;br /&gt;
            damageWeighted,&lt;br /&gt;
            weight,&lt;br /&gt;
            savedCriticalDamage&lt;br /&gt;
          );&lt;br /&gt;
&lt;br /&gt;
          if (finalDamage) {&lt;br /&gt;
            savedDamage[rawDamage] = finalDamage;&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return damageWeightedByType;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcDamage(&lt;br /&gt;
  attacker,&lt;br /&gt;
  victim,&lt;br /&gt;
  attackType,&lt;br /&gt;
  battle,&lt;br /&gt;
  removeSkillVariation&lt;br /&gt;
) {&lt;br /&gt;
  var damageCalculator, skillId, skillType;&lt;br /&gt;
&lt;br /&gt;
  if (attackType === &amp;quot;physical&amp;quot;) {&lt;br /&gt;
    damageCalculator = calcPhysicalDamage;&lt;br /&gt;
  } else if (attackType.startsWith(&amp;quot;attackSkill&amp;quot;)) {&lt;br /&gt;
    skillId = Number(attackType.split(&amp;quot;attackSkill&amp;quot;)[1]);&lt;br /&gt;
&lt;br /&gt;
    if (isMagicClass(attacker) || isDispell(attacker, skillId)) {&lt;br /&gt;
      skillType = &amp;quot;magic&amp;quot;;&lt;br /&gt;
      damageCalculator = calcMagicSkillDamage;&lt;br /&gt;
    } else {&lt;br /&gt;
      skillType = &amp;quot;physical&amp;quot;;&lt;br /&gt;
      damageCalculator = calcPhysicalSkillDamage;&lt;br /&gt;
    }&lt;br /&gt;
  } else if (attackType.startsWith(&amp;quot;horseSkill&amp;quot;)) {&lt;br /&gt;
    skillType = &amp;quot;physical&amp;quot;;&lt;br /&gt;
    skillId = Number(attackType.split(&amp;quot;horseSkill&amp;quot;)[1]);&lt;br /&gt;
    damageCalculator = calcPhysicalSkillDamage;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var battleValues = createBattleValues(attacker, victim, battle, skillType);&lt;br /&gt;
&lt;br /&gt;
  if (skillId) {&lt;br /&gt;
    getSkillFormula(battle, skillId, battleValues, removeSkillVariation);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    damageWeightedByType: damageCalculator(battleValues),&lt;br /&gt;
    attackValues: battleValues.attackValues,&lt;br /&gt;
    skillType: skillType,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function damageWithoutVariation(&lt;br /&gt;
  attacker,&lt;br /&gt;
  victim,&lt;br /&gt;
  attackType,&lt;br /&gt;
  battle,&lt;br /&gt;
  characters&lt;br /&gt;
) {&lt;br /&gt;
  var startDamageTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
  var { damageWeightedByType, attackValues, skillType } = calcDamage(&lt;br /&gt;
    attacker,&lt;br /&gt;
    victim,&lt;br /&gt;
    attackType,&lt;br /&gt;
    battle&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  var endDamageTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
  displayResults(&lt;br /&gt;
    attackValues,&lt;br /&gt;
    damageWeightedByType,&lt;br /&gt;
    battle,&lt;br /&gt;
    attacker.name,&lt;br /&gt;
    victim.name&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  var endDisplayTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
  displayFightInfo(&lt;br /&gt;
    attackValues.possibleDamageCount,&lt;br /&gt;
    endDamageTime - startDamageTime,&lt;br /&gt;
    endDisplayTime - endDamageTime,&lt;br /&gt;
    battle&lt;br /&gt;
  );&lt;br /&gt;
  addPotentialErrorInformation(&lt;br /&gt;
    battle.errorInformation,&lt;br /&gt;
    attacker,&lt;br /&gt;
    victim,&lt;br /&gt;
    skillType,&lt;br /&gt;
    characters&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  hideElement(battle.bonusVariationResultContainer);&lt;br /&gt;
  showElement(battle.fightResultTitle);&lt;br /&gt;
  showElement(battle.fightResultContainer);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function damageWithVariation(&lt;br /&gt;
  attacker,&lt;br /&gt;
  victim,&lt;br /&gt;
  attackType,&lt;br /&gt;
  battle,&lt;br /&gt;
  entity,&lt;br /&gt;
  entityVariation&lt;br /&gt;
) {&lt;br /&gt;
  var startTime = performance.now();&lt;br /&gt;
  var damageByBonus = [];&lt;br /&gt;
  var augmentationByBonus = [];&lt;br /&gt;
  var {&lt;br /&gt;
    bonusVariationMinValue: minVariation,&lt;br /&gt;
    bonusVariationMaxValue: maxVariation,&lt;br /&gt;
  } = entity;&lt;br /&gt;
  var step = Math.ceil((maxVariation - minVariation + 1) / 500);&lt;br /&gt;
  var simulationCount = 0;&lt;br /&gt;
  var simulationTime;&lt;br /&gt;
  var firstDamage = 1;&lt;br /&gt;
&lt;br /&gt;
  for (&lt;br /&gt;
    var bonusValue = minVariation;&lt;br /&gt;
    bonusValue &amp;lt;= maxVariation;&lt;br /&gt;
    bonusValue += step&lt;br /&gt;
  ) {&lt;br /&gt;
    entity[entityVariation] = bonusValue;&lt;br /&gt;
&lt;br /&gt;
    var { damageWeightedByType, totalCardinal } = calcDamage(&lt;br /&gt;
      copyObject(attacker),&lt;br /&gt;
      copyObject(victim),&lt;br /&gt;
      attackType,&lt;br /&gt;
      battle,&lt;br /&gt;
      true&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    var meanDamage = calcMeanDamage(damageWeightedByType, totalCardinal);&lt;br /&gt;
&lt;br /&gt;
    if (bonusValue === minVariation) {&lt;br /&gt;
      firstDamage = Math.max(meanDamage, 1e-3);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    damageByBonus.push({ x: bonusValue, y: meanDamage });&lt;br /&gt;
    augmentationByBonus.push({&lt;br /&gt;
      x: bonusValue,&lt;br /&gt;
      y: meanDamage / firstDamage - 1,&lt;br /&gt;
    });&lt;br /&gt;
    simulationCount++;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var endTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
  battle.damageByBonus = damageByBonus.concat(entityVariation);&lt;br /&gt;
&lt;br /&gt;
  addToBonusVariationChart(&lt;br /&gt;
    damageByBonus,&lt;br /&gt;
    augmentationByBonus,&lt;br /&gt;
    entity.bonusVariationName,&lt;br /&gt;
    battle.bonusVariationChart&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  simulationCount = battle.numberFormats.default.format(simulationCount);&lt;br /&gt;
  simulationTime = battle.numberFormats.second.format(&lt;br /&gt;
    (endTime - startTime) / 1000&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  battle.simulationCounter.textContent = simulationCount;&lt;br /&gt;
  battle.simulationTime.textContent = simulationTime;&lt;br /&gt;
&lt;br /&gt;
  hideElement(battle.fightResultContainer);&lt;br /&gt;
  showElement(battle.fightResultTitle);&lt;br /&gt;
  showElement(battle.bonusVariationResultContainer);&lt;br /&gt;
&lt;br /&gt;
  if (&lt;br /&gt;
    isChecked(attacker.useBonusVariation) &amp;amp;&amp;amp;&lt;br /&gt;
    isChecked(victim.useBonusVariation)&lt;br /&gt;
  ) {&lt;br /&gt;
    showElement(battle.errorInformation[&amp;quot;attacker-victim-variation&amp;quot;]);&lt;br /&gt;
  } else {&lt;br /&gt;
    hideElement(battle.errorInformation[&amp;quot;attacker-victim-variation&amp;quot;]);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function changeMonsterValues(monster, instance, attacker) {&lt;br /&gt;
  switch (instance) {&lt;br /&gt;
    case &amp;quot;SungMahiTower&amp;quot;:&lt;br /&gt;
      var sungMahiFloor = 1;&lt;br /&gt;
      var sungMahiStep = 1;&lt;br /&gt;
      var rawDefense = 120;&lt;br /&gt;
&lt;br /&gt;
      if (isPC(attacker)) {&lt;br /&gt;
        sungMahiFloor = attacker.sungMahiFloor;&lt;br /&gt;
        sungMahiStep = attacker.sungMahiStep;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (monster.rank === 5) {&lt;br /&gt;
        monster.level = 121;&lt;br /&gt;
        monster.dex = 75;&lt;br /&gt;
        rawDefense += 1;&lt;br /&gt;
      } else if (monster.rank === 6) {&lt;br /&gt;
        monster.level = 123;&lt;br /&gt;
        monster.dex = 75;&lt;br /&gt;
        rawDefense += 1;&lt;br /&gt;
      } else {&lt;br /&gt;
        monster.level = 120;&lt;br /&gt;
        monster.dex = 68;&lt;br /&gt;
      }&lt;br /&gt;
      monster.vit = 100;&lt;br /&gt;
      monster.rawDefense = rawDefense + (sungMahiStep - 1) * 6;&lt;br /&gt;
      monster.fistDefense = 0;&lt;br /&gt;
      monster.swordDefense = 0;&lt;br /&gt;
      monster.twoHandedSwordDefense = 0;&lt;br /&gt;
      monster.daggerDefense = 0;&lt;br /&gt;
      monster.bellDefense = 0;&lt;br /&gt;
      monster.fanDefense = 0;&lt;br /&gt;
      monster.arrowDefense = 0;&lt;br /&gt;
      monster.clawDefense = 0;&lt;br /&gt;
      monster.magicResistance = 0;&lt;br /&gt;
      monster.fireResistance = -20;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  // Alastor&lt;br /&gt;
  if (monster.vnum === 6790) {&lt;br /&gt;
    monster.iceResistance = 0;&lt;br /&gt;
    monster.iceBonus = 0;&lt;br /&gt;
    monster.lightningResistance = -10;&lt;br /&gt;
    monster.lightningBonus = 65;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createWeapon(vnum) {&lt;br /&gt;
  var weapon = copyObject(weaponData[vnum]);&lt;br /&gt;
  var serpentVnums = [360, 380, 1210, 2230, 3250, 5200, 6150, 7330];&lt;br /&gt;
  var weaponValues = weapon[1];&lt;br /&gt;
  var isSerpent = isValueInArray(Number(vnum), serpentVnums);&lt;br /&gt;
  var isSpecial = Array.isArray(weaponValues[0]);&lt;br /&gt;
  var isMagic;&lt;br /&gt;
&lt;br /&gt;
  if (isSpecial) {&lt;br /&gt;
    isMagic = weaponValues[0][1] &amp;gt; 0;&lt;br /&gt;
  } else {&lt;br /&gt;
    isMagic = weaponValues[1] &amp;gt; 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    type: weapon[0],&lt;br /&gt;
    maxUpgrade: weapon[2].length - 1,&lt;br /&gt;
    isSerpent: isSerpent,&lt;br /&gt;
    isMagic: isMagic,&lt;br /&gt;
    getValues: function (upgrade) {&lt;br /&gt;
      var currentWeaponValues = weaponValues;&lt;br /&gt;
&lt;br /&gt;
      if (upgrade === undefined) {&lt;br /&gt;
        // rare bug when weaponUpgrade is deleted&lt;br /&gt;
        console.warn(&amp;quot;WeaponUpgrade is missing.&amp;quot;);&lt;br /&gt;
        upgrade = this.maxUpgrade;&lt;br /&gt;
      }&lt;br /&gt;
      upgrade = Math.min(upgrade, this.maxUpgrade);&lt;br /&gt;
&lt;br /&gt;
      if (isSpecial) {&lt;br /&gt;
        currentWeaponValues = weaponValues[upgrade];&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      this.minAttackValue = currentWeaponValues[2];&lt;br /&gt;
      this.maxAttackValue = currentWeaponValues[3];&lt;br /&gt;
      this.minMagicAttackValue = currentWeaponValues[0];&lt;br /&gt;
      this.maxMagicAttackValue = currentWeaponValues[1];&lt;br /&gt;
      this.growth = weapon[2][upgrade];&lt;br /&gt;
    },&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createMonster(monsterVnum, attacker, polymorphMonster) {&lt;br /&gt;
  var monsterAttributes = monsterData[monsterVnum];&lt;br /&gt;
&lt;br /&gt;
  var monster = {&lt;br /&gt;
    vnum: Number(monsterVnum),&lt;br /&gt;
    name: monsterAttributes[36],&lt;br /&gt;
    rank: monsterAttributes[0],&lt;br /&gt;
    race: monsterAttributes[1],&lt;br /&gt;
    attack: monsterAttributes[2],&lt;br /&gt;
    level: monsterAttributes[3],&lt;br /&gt;
    type: monsterAttributes[4],&lt;br /&gt;
    str: monsterAttributes[5],&lt;br /&gt;
    dex: monsterAttributes[6],&lt;br /&gt;
    vit: monsterAttributes[7],&lt;br /&gt;
    int: monsterAttributes[8],&lt;br /&gt;
    minAttackValue: monsterAttributes[9],&lt;br /&gt;
    maxAttackValue: monsterAttributes[10],&lt;br /&gt;
    rawDefense: monsterAttributes[11],&lt;br /&gt;
    criticalHit: monsterAttributes[12],&lt;br /&gt;
    piercingHit: monsterAttributes[13],&lt;br /&gt;
    fistDefense: monsterAttributes[14],&lt;br /&gt;
    swordDefense: monsterAttributes[15],&lt;br /&gt;
    twoHandedSwordDefense: monsterAttributes[16],&lt;br /&gt;
    daggerDefense: monsterAttributes[17],&lt;br /&gt;
    bellDefense: monsterAttributes[18],&lt;br /&gt;
    fanDefense: monsterAttributes[19],&lt;br /&gt;
    arrowDefense: monsterAttributes[20],&lt;br /&gt;
    clawDefense: monsterAttributes[21],&lt;br /&gt;
    fireResistance: monsterAttributes[22],&lt;br /&gt;
    lightningResistance: monsterAttributes[23],&lt;br /&gt;
    magicResistance: monsterAttributes[24],&lt;br /&gt;
    windResistance: monsterAttributes[25],&lt;br /&gt;
    lightningBonus: monsterAttributes[26],&lt;br /&gt;
    fireBonus: monsterAttributes[27],&lt;br /&gt;
    iceBonus: monsterAttributes[28],&lt;br /&gt;
    windBonus: monsterAttributes[29],&lt;br /&gt;
    earthBonus: monsterAttributes[30],&lt;br /&gt;
    darknessBonus: monsterAttributes[31],&lt;br /&gt;
    darknessResistance: monsterAttributes[32],&lt;br /&gt;
    iceResistance: monsterAttributes[33],&lt;br /&gt;
    earthResistance: monsterAttributes[34],&lt;br /&gt;
    damageMultiplier: monsterAttributes[35],&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  // monster.instance = 0;&lt;br /&gt;
&lt;br /&gt;
  // if (attacker &amp;amp;&amp;amp; monster.instance === 0) {&lt;br /&gt;
  //   changeMonsterValues(monster, &amp;quot;SungMahiTower&amp;quot;, attacker);&lt;br /&gt;
  // }&lt;br /&gt;
  if (!polymorphMonster) {&lt;br /&gt;
    changeMonsterValues(monster);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  monster.defense = monster.rawDefense + monster.level + monster.vit;&lt;br /&gt;
&lt;br /&gt;
  return monster;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addPotentialErrorInformation(&lt;br /&gt;
  errorInformation,&lt;br /&gt;
  attacker,&lt;br /&gt;
  victim,&lt;br /&gt;
  skillType,&lt;br /&gt;
  characters&lt;br /&gt;
) {&lt;br /&gt;
  for (var error of Object.values(errorInformation)) {&lt;br /&gt;
    hideElement(error);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker)) {&lt;br /&gt;
    if (isRiding(attacker)) {&lt;br /&gt;
      if (attacker.horsePoint === 0) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;horse-level&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
      showElement(errorInformation[&amp;quot;horse-stat&amp;quot;]);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isPolymorph(attacker)) {&lt;br /&gt;
      if (attacker.polymorphPoint === 0) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;polymorph-level&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (&lt;br /&gt;
        (attacker.polymorphPoint &amp;lt;= 39 &amp;amp;&amp;amp; attacker.attackValuePercent &amp;lt;= 199) ||&lt;br /&gt;
        (attacker.polymorphPoint === 40 &amp;amp;&amp;amp; attacker.attackValuePercent &amp;lt;= 299)&lt;br /&gt;
      ) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;polymorph-bonus&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
    if (skillType === &amp;quot;magic&amp;quot;) {&lt;br /&gt;
      if (attacker.magicAttackValue) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;magic-attack-value-bonus&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
      if (victim.magicResistance) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;magic-resistance&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    showElement(errorInformation[&amp;quot;monster-attacker&amp;quot;]);&lt;br /&gt;
    if (isMagicAttacker(attacker) &amp;amp;&amp;amp; victim.magicResistance) {&lt;br /&gt;
      showElement(errorInformation[&amp;quot;magic-resistance&amp;quot;]);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (isPC(victim)) {&lt;br /&gt;
    if (isRiding(victim)) {&lt;br /&gt;
      showElement(errorInformation[&amp;quot;horse-stat&amp;quot;]);&lt;br /&gt;
    }&lt;br /&gt;
    if (isPolymorph(victim)) {&lt;br /&gt;
      if (attacker.polymorphPoint === 0) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;polymorph-level&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
      showElement(errorInformation[&amp;quot;polymorph-defense&amp;quot;]);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (characters.unsavedChanges) {&lt;br /&gt;
    showElement(errorInformation[&amp;quot;save&amp;quot;]);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function reduceChartPointsListener(battle) {&lt;br /&gt;
  var {&lt;br /&gt;
    reduceChartPointsContainer,&lt;br /&gt;
    reduceChartPoints,&lt;br /&gt;
    numberFormats: { second: numberFormat },&lt;br /&gt;
    displayTime,&lt;br /&gt;
  } = battle;&lt;br /&gt;
&lt;br /&gt;
  reduceChartPoints.addEventListener(&amp;quot;change&amp;quot;, function () {&lt;br /&gt;
    reduceChartPoints.disabled = true;&lt;br /&gt;
&lt;br /&gt;
    var startDisplayTime = performance.now();&lt;br /&gt;
    var scatterDataByType = battle.scatterDataByType;&lt;br /&gt;
    var {&lt;br /&gt;
      chart,&lt;br /&gt;
      maxPoints,&lt;br /&gt;
      chart: {&lt;br /&gt;
        data: { datasets },&lt;br /&gt;
      },&lt;br /&gt;
    } = battle.damageChart;&lt;br /&gt;
    var addAnimations = false;&lt;br /&gt;
&lt;br /&gt;
    for (var index = 0; index &amp;lt; datasets.length; index++) {&lt;br /&gt;
      var dataset = datasets[index];&lt;br /&gt;
      var scatterData = scatterDataByType[dataset.name];&lt;br /&gt;
&lt;br /&gt;
      if (dataset.canBeReduced &amp;amp;&amp;amp; reduceChartPoints.checked) {&lt;br /&gt;
        dataset.data = aggregateDamage(scatterData, maxPoints);&lt;br /&gt;
        addAnimations = true;&lt;br /&gt;
      } else {&lt;br /&gt;
        dataset.data = scatterData;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    handleChartAnimations(chart, addAnimations);&lt;br /&gt;
    chart.update();&lt;br /&gt;
&lt;br /&gt;
    displayTime.textContent = numberFormat.format(&lt;br /&gt;
      (performance.now() - startDisplayTime) / 1000&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    setTimeout(function () {&lt;br /&gt;
      reduceChartPoints.disabled = false;&lt;br /&gt;
    }, 1000);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  reduceChartPointsContainer.addEventListener(&amp;quot;pointerup&amp;quot;, function (event) {&lt;br /&gt;
    if (event.pointerType === &amp;quot;mouse&amp;quot;) {&lt;br /&gt;
      if (event.target.closest(&amp;quot;label&amp;quot;)) {&lt;br /&gt;
        return;&lt;br /&gt;
      }&lt;br /&gt;
      reduceChartPoints.click();&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function downloadRawDataListener(battle) {&lt;br /&gt;
  var { downLoadRawData, downLoadRawDataVariation } = battle;&lt;br /&gt;
  var fileType = &amp;quot;text/csv;charset=utf-8;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  downLoadRawData.addEventListener(&amp;quot;click&amp;quot;, function () {&lt;br /&gt;
    var damageWeightedByType = battle.damageWeightedByType;&lt;br /&gt;
    var filename = &amp;quot;raw_damage.csv&amp;quot;;&lt;br /&gt;
    var csvContent = &amp;quot;damage,probabilities,damageType\n&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    for (var damageType in damageWeightedByType) {&lt;br /&gt;
      var damageWeighted = damageWeightedByType[damageType];&lt;br /&gt;
&lt;br /&gt;
      for (var damage in damageWeighted) {&lt;br /&gt;
        csvContent +=&lt;br /&gt;
          damage + &amp;quot;,&amp;quot; + damageWeighted[damage] + &amp;quot;,&amp;quot; + damageType + &amp;quot;\n&amp;quot;;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    downloadData(csvContent, fileType, filename);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  downLoadRawDataVariation.addEventListener(&amp;quot;click&amp;quot;, function () {&lt;br /&gt;
    var damageByBonus = battle.damageByBonus;&lt;br /&gt;
    var damageByBonusLength = damageByBonus.length;&lt;br /&gt;
    var filename = &amp;quot;damage_variation.csv&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    if (!damageByBonusLength) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var csvContent =&lt;br /&gt;
      damageByBonus[damageByBonusLength - 1] + &amp;quot;,averageDamage\n&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    for (var index = 0; index &amp;lt; damageByBonusLength - 1; index++) {&lt;br /&gt;
      var row = damageByBonus[index];&lt;br /&gt;
&lt;br /&gt;
      csvContent += row.x + &amp;quot;,&amp;quot; + row.y + &amp;quot;\n&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    downloadData(csvContent, fileType, filename);&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function displayResults(&lt;br /&gt;
  attackValues,&lt;br /&gt;
  damageWeightedByType,&lt;br /&gt;
  battle,&lt;br /&gt;
  attackerName,&lt;br /&gt;
  victimName&lt;br /&gt;
) {&lt;br /&gt;
  var [meanDamage, minDamage, maxDamage, scatterDataByType, uniqueDamageCount] =&lt;br /&gt;
    prepareDamageData(damageWeightedByType, attackValues);&lt;br /&gt;
&lt;br /&gt;
  addToDamageChart(&lt;br /&gt;
    scatterDataByType,&lt;br /&gt;
    battle.damageChart,&lt;br /&gt;
    battle.reduceChartPoints.checked&lt;br /&gt;
  );&lt;br /&gt;
  updateDamageChartDescription(&lt;br /&gt;
    battle.uniqueDamageCounters,&lt;br /&gt;
    uniqueDamageCount,&lt;br /&gt;
    battle.numberFormats.default&lt;br /&gt;
  );&lt;br /&gt;
  displayFightResults(&lt;br /&gt;
    battle,&lt;br /&gt;
    attackerName,&lt;br /&gt;
    victimName,&lt;br /&gt;
    meanDamage,&lt;br /&gt;
    minDamage,&lt;br /&gt;
    maxDamage&lt;br /&gt;
  );&lt;br /&gt;
  battle.damageWeightedByType = damageWeightedByType;&lt;br /&gt;
  battle.scatterDataByType = scatterDataByType;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function displayFightResults(&lt;br /&gt;
  battle,&lt;br /&gt;
  attackerName,&lt;br /&gt;
  victimName,&lt;br /&gt;
  meanDamage,&lt;br /&gt;
  minDamage,&lt;br /&gt;
  maxDamage&lt;br /&gt;
) {&lt;br /&gt;
  var {&lt;br /&gt;
    tableResultFight,&lt;br /&gt;
    tableResultHistory,&lt;br /&gt;
    savedFights,&lt;br /&gt;
    numberFormats: { default: numberFormat },&lt;br /&gt;
    deleteFightTemplate,&lt;br /&gt;
  } = battle;&lt;br /&gt;
&lt;br /&gt;
  hideElement(tableResultHistory.rows[1]);&lt;br /&gt;
&lt;br /&gt;
  var valuesToDisplay = [&lt;br /&gt;
    attackerName,&lt;br /&gt;
    victimName,&lt;br /&gt;
    battle.battleChoice.attackType.selectedText,&lt;br /&gt;
    meanDamage,&lt;br /&gt;
    minDamage,&lt;br /&gt;
    maxDamage,&lt;br /&gt;
  ];&lt;br /&gt;
&lt;br /&gt;
  savedFights.push(valuesToDisplay);&lt;br /&gt;
  updateSavedFights(savedFights);&lt;br /&gt;
&lt;br /&gt;
  editTableResultRow(tableResultFight.rows[1], valuesToDisplay, numberFormat);&lt;br /&gt;
  addRowToTableResultHistory(&lt;br /&gt;
    tableResultHistory,&lt;br /&gt;
    valuesToDisplay,&lt;br /&gt;
    deleteFightTemplate,&lt;br /&gt;
    numberFormat&lt;br /&gt;
  );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function displayFightInfo(&lt;br /&gt;
  possibleDamageCount,&lt;br /&gt;
  damageTimeDuration,&lt;br /&gt;
  displayTimeDuration,&lt;br /&gt;
  battle&lt;br /&gt;
) {&lt;br /&gt;
  var container = battle.possibleDamageCounter.parentElement;&lt;br /&gt;
&lt;br /&gt;
  if (possibleDamageCount &amp;lt;= 1) {&lt;br /&gt;
    hideElement(container);&lt;br /&gt;
    return;&lt;br /&gt;
  } else {&lt;br /&gt;
    showElement(container);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var { numberFormats, possibleDamageCounter, damageTime, displayTime } =&lt;br /&gt;
    battle;&lt;br /&gt;
&lt;br /&gt;
  possibleDamageCount = numberFormats.default.format(possibleDamageCount);&lt;br /&gt;
  damageTimeDuration = numberFormats.second.format(damageTimeDuration / 1000);&lt;br /&gt;
  displayTimeDuration = numberFormats.second.format(displayTimeDuration / 1000);&lt;br /&gt;
&lt;br /&gt;
  possibleDamageCounter.textContent = possibleDamageCount;&lt;br /&gt;
  damageTime.textContent = damageTimeDuration;&lt;br /&gt;
  displayTime.textContent = displayTimeDuration;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function parseTypeAndName(data) {&lt;br /&gt;
  var [type, nameOrVnum] = splitFirst(data, &amp;quot;-&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    type: type,&lt;br /&gt;
    nameOrVnum: nameOrVnum,&lt;br /&gt;
    isCharacter: type === &amp;quot;character&amp;quot;,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isCharacterSelected(characterName, selected) {&lt;br /&gt;
  if (!selected) {&lt;br /&gt;
    return false;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var { nameOrVnum, isCharacter } = parseTypeAndName(selected);&lt;br /&gt;
&lt;br /&gt;
  return nameOrVnum === characterName &amp;amp;&amp;amp; isCharacter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function useBonusVariationMode(character, variation) {&lt;br /&gt;
  return (&lt;br /&gt;
    isChecked(character.useBonusVariation) &amp;amp;&amp;amp;&lt;br /&gt;
    character.hasOwnProperty(variation) &amp;amp;&amp;amp;&lt;br /&gt;
    character.bonusVariationMinValue &amp;lt; character.bonusVariationMaxValue&lt;br /&gt;
  );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createBattle(characters, battle) {&lt;br /&gt;
  var battleChoice = battle.battleChoice;&lt;br /&gt;
  var battleForm = battleChoice.form;&lt;br /&gt;
  var lastInvalidTime = 0;&lt;br /&gt;
&lt;br /&gt;
  battleForm.addEventListener(&amp;quot;change&amp;quot;, handleBattleFormChange);&lt;br /&gt;
  battleForm.addEventListener(&amp;quot;invalid&amp;quot;, handleBattleFormInvalid, true);&lt;br /&gt;
  battleForm.addEventListener(&amp;quot;submit&amp;quot;, handleBattleFormSubmit);&lt;br /&gt;
&lt;br /&gt;
  function handleBattleFormChange(event) {&lt;br /&gt;
    var target = event.target;&lt;br /&gt;
    var { name: targetName, value: targetValue, type: targetType } = target;&lt;br /&gt;
&lt;br /&gt;
    if (targetType !== &amp;quot;radio&amp;quot;) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (targetName === &amp;quot;attackType&amp;quot;) {&lt;br /&gt;
      battleChoice.attackType.selectedText =&lt;br /&gt;
        target.previousElementSibling.dataset.o;&lt;br /&gt;
    } else {&lt;br /&gt;
      updateBattleChoiceButton(battleChoice, targetName, targetValue);&lt;br /&gt;
&lt;br /&gt;
      if (targetName === &amp;quot;attacker&amp;quot;) {&lt;br /&gt;
        filterAttackTypeSelection(characters, battleChoice, targetValue);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function handleBattleFormInvalid(event) {&lt;br /&gt;
    var currentTime = Date.now();&lt;br /&gt;
&lt;br /&gt;
    if (currentTime - lastInvalidTime &amp;lt; 100) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    lastInvalidTime = currentTime;&lt;br /&gt;
&lt;br /&gt;
    var target = event.target;&lt;br /&gt;
    var modal = target.closest(&amp;quot;.modal&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (!modal) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var dataModal = modal.dataset.modal;&lt;br /&gt;
&lt;br /&gt;
    if (!dataModal) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var category = dataModal.split(&amp;quot;-&amp;quot;)[0];&lt;br /&gt;
&lt;br /&gt;
    if (isValueInArray(category, battleChoice.categories)) {&lt;br /&gt;
      battleChoice[category].button.click();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function handleBattleFormSubmit(event) {&lt;br /&gt;
    event.preventDefault();&lt;br /&gt;
&lt;br /&gt;
    // auto save&lt;br /&gt;
    if (characters.unsavedChanges) {&lt;br /&gt;
      characters.saveButton.click();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var battleInfo = new FormData(event.target);&lt;br /&gt;
    var attackerData = battleInfo.get(&amp;quot;attacker&amp;quot;);&lt;br /&gt;
    var attackType = battleInfo.get(&amp;quot;attackType&amp;quot;);&lt;br /&gt;
    var victimData = battleInfo.get(&amp;quot;victim&amp;quot;);&lt;br /&gt;
    var attackerVariation;&lt;br /&gt;
    var victimVariation;&lt;br /&gt;
&lt;br /&gt;
    if (!attackerData &amp;amp;&amp;amp; !attackType &amp;amp;&amp;amp; !victimData) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var { nameOrVnum: attackerNameOrVnum, isCharacter: attackerIsPlayer } =&lt;br /&gt;
      parseTypeAndName(attackerData);&lt;br /&gt;
    var { nameOrVnum: victimNameOrVnum, isCharacter: victimIsPlayer } =&lt;br /&gt;
      parseTypeAndName(victimData);&lt;br /&gt;
&lt;br /&gt;
    if (attackerIsPlayer) {&lt;br /&gt;
      var attacker = copyObject(characters.savedCharacters[attackerNameOrVnum]);&lt;br /&gt;
      attackerVariation = attacker.bonusVariation;&lt;br /&gt;
    } else {&lt;br /&gt;
      var attacker = createMonster(attackerNameOrVnum);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (victimIsPlayer) {&lt;br /&gt;
      var victim = copyObject(characters.savedCharacters[victimNameOrVnum]);&lt;br /&gt;
      victimVariation = victim.bonusVariation;&lt;br /&gt;
    } else {&lt;br /&gt;
      var victim = createMonster(victimNameOrVnum, attacker);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (useBonusVariationMode(attacker, attackerVariation)) {&lt;br /&gt;
      damageWithVariation(&lt;br /&gt;
        attacker,&lt;br /&gt;
        victim,&lt;br /&gt;
        attackType,&lt;br /&gt;
        battle,&lt;br /&gt;
        attacker,&lt;br /&gt;
        attackerVariation&lt;br /&gt;
      );&lt;br /&gt;
    } else if (useBonusVariationMode(victim, victimVariation)) {&lt;br /&gt;
      damageWithVariation(&lt;br /&gt;
        attacker,&lt;br /&gt;
        victim,&lt;br /&gt;
        attackType,&lt;br /&gt;
        battle,&lt;br /&gt;
        victim,&lt;br /&gt;
        victimVariation&lt;br /&gt;
      );&lt;br /&gt;
    } else {&lt;br /&gt;
      damageWithoutVariation(attacker, victim, attackType, battle, characters);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createMapping() {&lt;br /&gt;
  var mapping = {&lt;br /&gt;
    typeFlag: [&lt;br /&gt;
      &amp;quot;animalBonus&amp;quot;, // 0&lt;br /&gt;
      &amp;quot;humanBonus&amp;quot;, // 1&lt;br /&gt;
      &amp;quot;orcBonus&amp;quot;, // 2&lt;br /&gt;
      &amp;quot;mysticBonus&amp;quot;, // 3&lt;br /&gt;
      &amp;quot;undeadBonus&amp;quot;, // 4&lt;br /&gt;
      &amp;quot;insectBonus&amp;quot;, // 5&lt;br /&gt;
      &amp;quot;desertBonus&amp;quot;, // 6&lt;br /&gt;
      &amp;quot;devilBonus&amp;quot;, // 7&lt;br /&gt;
    ],&lt;br /&gt;
    raceBonus: {&lt;br /&gt;
      warrior: &amp;quot;warriorBonus&amp;quot;,&lt;br /&gt;
      sura: &amp;quot;suraBonus&amp;quot;,&lt;br /&gt;
      ninja: &amp;quot;ninjaBonus&amp;quot;,&lt;br /&gt;
      shaman: &amp;quot;shamanBonus&amp;quot;,&lt;br /&gt;
      lycan: &amp;quot;lycanBonus&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    raceResistance: {&lt;br /&gt;
      warrior: &amp;quot;warriorResistance&amp;quot;,&lt;br /&gt;
      sura: &amp;quot;suraResistance&amp;quot;,&lt;br /&gt;
      ninja: &amp;quot;ninjaResistance&amp;quot;,&lt;br /&gt;
      shaman: &amp;quot;shamanResistance&amp;quot;,&lt;br /&gt;
      lycan: &amp;quot;lycanResistance&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    defenseWeapon: [&lt;br /&gt;
      &amp;quot;swordDefense&amp;quot;, // 0&lt;br /&gt;
      &amp;quot;daggerDefense&amp;quot;, // 1&lt;br /&gt;
      &amp;quot;arrowDefense&amp;quot;, // 2&lt;br /&gt;
      &amp;quot;twoHandedSwordDefense&amp;quot;, // 3&lt;br /&gt;
      &amp;quot;bellDefense&amp;quot;, // 4&lt;br /&gt;
      &amp;quot;clawDefense&amp;quot;, // 5&lt;br /&gt;
      &amp;quot;fanDefense&amp;quot;, // 6&lt;br /&gt;
      &amp;quot;swordDefense&amp;quot;, // 7&lt;br /&gt;
      &amp;quot;fistDefense&amp;quot;, // 8&lt;br /&gt;
    ],&lt;br /&gt;
    breakWeapon: [&lt;br /&gt;
      &amp;quot;breakSwordDefense&amp;quot;, // 0&lt;br /&gt;
      &amp;quot;breakDaggerDefense&amp;quot;, // 1&lt;br /&gt;
      &amp;quot;breakArrowDefense&amp;quot;, // 2&lt;br /&gt;
      &amp;quot;breakTwoHandedSwordDefense&amp;quot;, // 3&lt;br /&gt;
      &amp;quot;breakBellDefense&amp;quot;, // 4&lt;br /&gt;
      &amp;quot;breakClawDefense&amp;quot;, // 5&lt;br /&gt;
      &amp;quot;breakFanDefense&amp;quot;, // 6&lt;br /&gt;
      &amp;quot;breakSwordDefense&amp;quot;, // 7&lt;br /&gt;
    ],&lt;br /&gt;
    elementBonus: [&lt;br /&gt;
      &amp;quot;fireBonus&amp;quot;, // 0&lt;br /&gt;
      &amp;quot;iceBonus&amp;quot;, // 1&lt;br /&gt;
      &amp;quot;windBonus&amp;quot;, // 2&lt;br /&gt;
      &amp;quot;lightningBonus&amp;quot;, // 3&lt;br /&gt;
      &amp;quot;earthBonus&amp;quot;, // 4&lt;br /&gt;
      &amp;quot;darknessBonus&amp;quot;, // 5&lt;br /&gt;
    ],&lt;br /&gt;
    elementResistance: [&lt;br /&gt;
      &amp;quot;fireResistance&amp;quot;, // 0&lt;br /&gt;
      &amp;quot;iceResistance&amp;quot;, // 1&lt;br /&gt;
      &amp;quot;windResistance&amp;quot;, // 2&lt;br /&gt;
      &amp;quot;lightningResistance&amp;quot;, // 3&lt;br /&gt;
      &amp;quot;earthResistance&amp;quot;, // 4&lt;br /&gt;
      &amp;quot;darknessResistance&amp;quot;, // 5&lt;br /&gt;
    ],&lt;br /&gt;
  };&lt;br /&gt;
  return mapping;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createConstants() {&lt;br /&gt;
  var constants = {&lt;br /&gt;
    polymorphPowerTable: [&lt;br /&gt;
      10, 11, 11, 12, 13, 13, 14, 15, 16, 17, 18, 19, 20, 22, 23, 24, 26, 27,&lt;br /&gt;
      29, 31, 33, 35, 37, 39, 41, 44, 46, 49, 52, 55, 59, 62, 66, 70, 74, 79,&lt;br /&gt;
      84, 89, 94, 100, 0,&lt;br /&gt;
    ],&lt;br /&gt;
    skillPowerTable: [&lt;br /&gt;
      0, 0.05, 0.06, 0.08, 0.1, 0.12, 0.14, 0.16, 0.18, 0.2, 0.22, 0.24, 0.26,&lt;br /&gt;
      0.28, 0.3, 0.32, 0.34, 0.36, 0.38, 0.4, 0.5, 0.52, 0.54, 0.56, 0.58, 0.6,&lt;br /&gt;
      0.63, 0.66, 0.69, 0.72, 0.82, 0.85, 0.88, 0.91, 0.94, 0.98, 1.02, 1.06,&lt;br /&gt;
      1.1, 1.15, 1.25,&lt;br /&gt;
    ],&lt;br /&gt;
    marriageTable: {&lt;br /&gt;
      harmonyEarrings: [4, 5, 6, 8],&lt;br /&gt;
      loveEarrings: [4, 5, 6, 8],&lt;br /&gt;
      harmonyBracelet: [4, 5, 6, 8],&lt;br /&gt;
      loveNecklace: [20, 25, 30, 40],&lt;br /&gt;
      harmonyNecklace: [12, 16, 20, 30],&lt;br /&gt;
    },&lt;br /&gt;
    allowedWeaponsPerRace: {&lt;br /&gt;
      warrior: [0, 3, 8],&lt;br /&gt;
      ninja: [0, 1, 2, 8],&lt;br /&gt;
      sura: [0, 7, 8],&lt;br /&gt;
      shaman: [4, 6, 8],&lt;br /&gt;
      lycan: [5, 8],&lt;br /&gt;
    },&lt;br /&gt;
    translation: {&lt;br /&gt;
      fr: {&lt;br /&gt;
        damage: &amp;quot;Dégâts&amp;quot;,&lt;br /&gt;
        percentage: &amp;quot;Pourcentage&amp;quot;,&lt;br /&gt;
        miss: &amp;quot;Miss&amp;quot;,&lt;br /&gt;
        normalHit: &amp;quot;Coup classique&amp;quot;,&lt;br /&gt;
        criticalHit: &amp;quot;Coup critique&amp;quot;,&lt;br /&gt;
        piercingHit: &amp;quot;Coup perçant&amp;quot;,&lt;br /&gt;
        criticalPiercingHit: &amp;quot;Coup critique perçant&amp;quot;,&lt;br /&gt;
        damageRepartition: &amp;quot;Distribution des dégâts&amp;quot;,&lt;br /&gt;
        averageDamage: &amp;quot;Dégâts moyens&amp;quot;,&lt;br /&gt;
        damageAugmentation: &amp;quot;Augmentation des dégâts&amp;quot;,&lt;br /&gt;
        bonusVariationTitle: [&lt;br /&gt;
          &amp;quot;Évolution des dégâts moyens&amp;quot;,&lt;br /&gt;
          &amp;quot;par rapport à la valeur d'un bonus&amp;quot;,&lt;br /&gt;
        ],&lt;br /&gt;
      },&lt;br /&gt;
      en: {&lt;br /&gt;
        damage: &amp;quot;Damage&amp;quot;,&lt;br /&gt;
        percentage: &amp;quot;Percentage&amp;quot;,&lt;br /&gt;
        miss: &amp;quot;Miss&amp;quot;,&lt;br /&gt;
        normalHit: &amp;quot;Normal Hit&amp;quot;,&lt;br /&gt;
        criticalHit: &amp;quot;Critical Hit&amp;quot;,&lt;br /&gt;
        piercingHit: &amp;quot;Piercing Hit&amp;quot;,&lt;br /&gt;
        criticalPiercingHit: &amp;quot;Critical Piercing Hit&amp;quot;,&lt;br /&gt;
        damageRepartition: &amp;quot;Damage Repartition&amp;quot;,&lt;br /&gt;
        averageDamage: &amp;quot;Average Damage&amp;quot;,&lt;br /&gt;
        damageAugmentation: &amp;quot;Damage Augmentation&amp;quot;,&lt;br /&gt;
        bonusVariationTitle: [&lt;br /&gt;
          &amp;quot;Evolution of Average Damage&amp;quot;,&lt;br /&gt;
          &amp;quot;Relative to a Bonus Value&amp;quot;,&lt;br /&gt;
        ],&lt;br /&gt;
      },&lt;br /&gt;
      tr: {&lt;br /&gt;
        damage: &amp;quot;Hasar&amp;quot;,&lt;br /&gt;
        percentage: &amp;quot;Yüzde&amp;quot;,&lt;br /&gt;
        miss: &amp;quot;Miss Vuruş&amp;quot;,&lt;br /&gt;
        normalHit: &amp;quot;Düz Vuruş&amp;quot;,&lt;br /&gt;
        criticalHit: &amp;quot;Kritik Vuruş&amp;quot;,&lt;br /&gt;
        piercingHit: &amp;quot;Delici Vuruş&amp;quot;,&lt;br /&gt;
        criticalPiercingHit: &amp;quot;Kritikli Delici Vuruş&amp;quot;,&lt;br /&gt;
        damageRepartition: &amp;quot;Hasar Dağılımı&amp;quot;,&lt;br /&gt;
        averageDamage: &amp;quot;Ortalama Hasar&amp;quot;,&lt;br /&gt;
        damageAugmentation: &amp;quot;Ortalama Hasar Artışı&amp;quot;,&lt;br /&gt;
        bonusVariationTitle: [&lt;br /&gt;
          &amp;quot;Bir bonusun değerine kıyasla&amp;quot;,&lt;br /&gt;
          &amp;quot;Ortalama Hasar Çizelgesi&amp;quot;,&lt;br /&gt;
        ],&lt;br /&gt;
      },&lt;br /&gt;
      ro: {&lt;br /&gt;
        damage: &amp;quot;Daune&amp;quot;,&lt;br /&gt;
        percentage: &amp;quot;Procent&amp;quot;,&lt;br /&gt;
        miss: &amp;quot;Miss&amp;quot;,&lt;br /&gt;
        normalHit: &amp;quot;Lovitura normala&amp;quot;,&lt;br /&gt;
        criticalHit: &amp;quot;Lovitura critica&amp;quot;,&lt;br /&gt;
        piercingHit: &amp;quot;Lovitura patrunzatoare&amp;quot;,&lt;br /&gt;
        criticalPiercingHit: &amp;quot;Lovitura critica si patrunzatoare&amp;quot;,&lt;br /&gt;
        damageRepartition: &amp;quot;Distribuția daunelor&amp;quot;,&lt;br /&gt;
        averageDamage: &amp;quot;Media damageului&amp;quot;,&lt;br /&gt;
        damageAugmentation: &amp;quot;Damage imbunatatit&amp;quot;,&lt;br /&gt;
        bonusVariationTitle: [&lt;br /&gt;
          &amp;quot;Evolutia mediei damageului&amp;quot;,&lt;br /&gt;
          &amp;quot;relativ la o valoare bonus&amp;quot;,&lt;br /&gt;
        ],&lt;br /&gt;
      },&lt;br /&gt;
      de: {&lt;br /&gt;
        damage: &amp;quot;Schäden&amp;quot;,&lt;br /&gt;
        percentage: &amp;quot;Prozentsatz&amp;quot;,&lt;br /&gt;
        miss: &amp;quot;Verfehlen&amp;quot;,&lt;br /&gt;
        normalHit: &amp;quot;Normaler Treffer&amp;quot;,&lt;br /&gt;
        criticalHit: &amp;quot;Kritischer Treffer&amp;quot;,&lt;br /&gt;
        piercingHit: &amp;quot;Durchdringender Treffer&amp;quot;,&lt;br /&gt;
        criticalPiercingHit: &amp;quot;Kritischer durchdringender Treffer&amp;quot;,&lt;br /&gt;
        damageRepartition: &amp;quot;Schadensverteilung&amp;quot;,&lt;br /&gt;
        averageDamage: &amp;quot;Durchschnittlicher Schaden&amp;quot;,&lt;br /&gt;
        damageAugmentation: &amp;quot;Schadenserhöhung&amp;quot;,&lt;br /&gt;
        bonusVariationTitle: [&lt;br /&gt;
          &amp;quot;Entwicklung des durchschnittlichen Schadens&amp;quot;,&lt;br /&gt;
          &amp;quot;im Verhältnis zu einem Bonus&amp;quot;,&lt;br /&gt;
        ],&lt;br /&gt;
      },&lt;br /&gt;
      pt: {&lt;br /&gt;
        damage: &amp;quot;Dano&amp;quot;,&lt;br /&gt;
        percentage: &amp;quot;Percentagem&amp;quot;,&lt;br /&gt;
        miss: &amp;quot;Miss&amp;quot;,&lt;br /&gt;
        normalHit: &amp;quot;Dano normal&amp;quot;,&lt;br /&gt;
        criticalHit: &amp;quot;Dano crítico&amp;quot;,&lt;br /&gt;
        piercingHit: &amp;quot;Dano perfurante&amp;quot;,&lt;br /&gt;
        criticalPiercingHit: &amp;quot;Dano crítico perfurante&amp;quot;,&lt;br /&gt;
        damageRepartition: &amp;quot;Repartição de dano&amp;quot;,&lt;br /&gt;
        averageDamage: &amp;quot;Dano médio&amp;quot;,&lt;br /&gt;
        damageAugmentation: &amp;quot;Aumento de dano&amp;quot;,&lt;br /&gt;
        bonusVariationTitle: [&amp;quot;Evolução do dano médio&amp;quot;, &amp;quot;relativo a um bónus&amp;quot;],&lt;br /&gt;
      },&lt;br /&gt;
      // es: {&lt;br /&gt;
      //   damage: &amp;quot;Daño&amp;quot;,&lt;br /&gt;
      //   percentage: &amp;quot;Porcentaje&amp;quot;,&lt;br /&gt;
      //   miss: &amp;quot;Miss&amp;quot;,&lt;br /&gt;
      //   normalHit: &amp;quot;Daño normal&amp;quot;,&lt;br /&gt;
      //   criticalHit: &amp;quot;Daño crítico&amp;quot;,&lt;br /&gt;
      //   piercingHit: &amp;quot;Daño perforante&amp;quot;,&lt;br /&gt;
      //   criticalPiercingHit: &amp;quot;Daño crítico perforante&amp;quot;,&lt;br /&gt;
      //   damageRepartition: &amp;quot;Repartición de daños&amp;quot;,&lt;br /&gt;
      //   averageDamage: &amp;quot;Daño medio&amp;quot;,&lt;br /&gt;
      //   damageAugmentation: &amp;quot;Aumento de daño&amp;quot;,&lt;br /&gt;
      //   bonusVariationTitle: [&amp;quot;Evolución del daño medio&amp;quot;, &amp;quot;Relativo a una bonificación&amp;quot;]&lt;br /&gt;
      // },&lt;br /&gt;
    },&lt;br /&gt;
  };&lt;br /&gt;
  return constants;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initResultTableHistory(battle) {&lt;br /&gt;
  var {&lt;br /&gt;
    tableResultHistory,&lt;br /&gt;
    savedFights,&lt;br /&gt;
    deleteFightTemplate,&lt;br /&gt;
    numberFormats: { default: numberFormat },&lt;br /&gt;
  } = battle;&lt;br /&gt;
  var startIndex = 3;&lt;br /&gt;
&lt;br /&gt;
  if (savedFights.length) {&lt;br /&gt;
    hideElement(tableResultHistory.rows[1]);&lt;br /&gt;
&lt;br /&gt;
    for (var savedFight of savedFights) {&lt;br /&gt;
      addRowToTableResultHistory(&lt;br /&gt;
        tableResultHistory,&lt;br /&gt;
        savedFight,&lt;br /&gt;
        deleteFightTemplate,&lt;br /&gt;
        numberFormat&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  tableResultHistory.addEventListener(&amp;quot;click&amp;quot;, function (event) {&lt;br /&gt;
    var deleteButton = event.target.closest(&amp;quot;.svg-icon-delete&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (deleteButton) {&lt;br /&gt;
      var row = deleteButton.closest(&amp;quot;tr&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
      if (row) {&lt;br /&gt;
        savedFights.splice(row.rowIndex - startIndex, 1);&lt;br /&gt;
        updateSavedFights(savedFights);&lt;br /&gt;
&lt;br /&gt;
        row.remove();&lt;br /&gt;
&lt;br /&gt;
        if (tableResultHistory.rows.length === startIndex) {&lt;br /&gt;
          showElement(tableResultHistory.rows[1]);&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initDamageChart(battle) {&lt;br /&gt;
  var { translation, reduceChartPointsContainer, reduceChartPoints } = battle;&lt;br /&gt;
  var percentFormat = battle.numberFormats.percent;&lt;br /&gt;
  var customPlugins = {&lt;br /&gt;
    id: &amp;quot;customPlugins&amp;quot;,&lt;br /&gt;
    afterDraw(chart) {&lt;br /&gt;
      var missPercentage = chart.data.missPercentage;&lt;br /&gt;
&lt;br /&gt;
      if (!missPercentage) {&lt;br /&gt;
        return;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      var {&lt;br /&gt;
        ctx,&lt;br /&gt;
        chartArea: { top, right },&lt;br /&gt;
      } = chart;&lt;br /&gt;
      ctx.save();&lt;br /&gt;
      var text =&lt;br /&gt;
        translation.miss + &amp;quot; : &amp;quot; + percentFormat.format(missPercentage);&lt;br /&gt;
      var padding = 4;&lt;br /&gt;
      var fontSize = 14;&lt;br /&gt;
&lt;br /&gt;
      ctx.font = fontSize + &amp;quot;px Helvetica Neue&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
      var textWidth = ctx.measureText(text).width;&lt;br /&gt;
      var xPosition = right - textWidth - 5;&lt;br /&gt;
      var yPosition = top + 5;&lt;br /&gt;
&lt;br /&gt;
      ctx.fillStyle = &amp;quot;rgba(255, 0, 0, 0.2)&amp;quot;;&lt;br /&gt;
      ctx.fillRect(&lt;br /&gt;
        xPosition - padding,&lt;br /&gt;
        yPosition - padding,&lt;br /&gt;
        textWidth + 2 * padding,&lt;br /&gt;
        fontSize + 2 * padding&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      ctx.strokeStyle = &amp;quot;red&amp;quot;;&lt;br /&gt;
      ctx.strokeRect(&lt;br /&gt;
        xPosition - padding,&lt;br /&gt;
        yPosition - padding,&lt;br /&gt;
        textWidth + 2 * padding,&lt;br /&gt;
        fontSize + 2 * padding&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      ctx.fillStyle = &amp;quot;#666&amp;quot;;&lt;br /&gt;
      ctx.textBaseline = &amp;quot;top&amp;quot;;&lt;br /&gt;
      ctx.fillText(text, xPosition, yPosition + 1);&lt;br /&gt;
&lt;br /&gt;
      ctx.restore();&lt;br /&gt;
    },&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  Chart.register(customPlugins);&lt;br /&gt;
&lt;br /&gt;
  var ctx = battle.plotDamage.getContext(&amp;quot;2d&amp;quot;);&lt;br /&gt;
  var maxLabelsInTooltip = 10;&lt;br /&gt;
  var nullLabelText = &amp;quot; ...&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  var chart = new Chart(ctx, {&lt;br /&gt;
    type: &amp;quot;scatter&amp;quot;,&lt;br /&gt;
    data: {&lt;br /&gt;
      missPercentage: 0,&lt;br /&gt;
      datasets: [],&lt;br /&gt;
    },&lt;br /&gt;
    options: {&lt;br /&gt;
      responsive: true,&lt;br /&gt;
      maintainAspectRatio: false,&lt;br /&gt;
      plugins: {&lt;br /&gt;
        legend: {&lt;br /&gt;
          display: true,&lt;br /&gt;
          onHover: function (e) {&lt;br /&gt;
            e.native.target.style.cursor = &amp;quot;pointer&amp;quot;;&lt;br /&gt;
          },&lt;br /&gt;
          onLeave: function (e) {&lt;br /&gt;
            e.native.target.style.cursor = &amp;quot;default&amp;quot;;&lt;br /&gt;
          },&lt;br /&gt;
          onClick: function (e, legendItem, legend) {&lt;br /&gt;
            var currentIndex = legendItem.datasetIndex;&lt;br /&gt;
            var ci = legend.chart;&lt;br /&gt;
            var isCurrentDatasetVisible = ci.isDatasetVisible(currentIndex);&lt;br /&gt;
            var datasets = ci.data.datasets;&lt;br /&gt;
            var hideReducePoints = true;&lt;br /&gt;
            var isReducePointsChecked = reduceChartPoints.checked;&lt;br /&gt;
&lt;br /&gt;
            datasets[currentIndex].hidden = isCurrentDatasetVisible;&lt;br /&gt;
            legendItem.hidden = isCurrentDatasetVisible;&lt;br /&gt;
&lt;br /&gt;
            for (var index in datasets) {&lt;br /&gt;
              if (ci.isDatasetVisible(index) &amp;amp;&amp;amp; datasets[index].canBeReduced) {&lt;br /&gt;
                showElement(reduceChartPointsContainer);&lt;br /&gt;
                hideReducePoints = false;&lt;br /&gt;
                break;&lt;br /&gt;
              }&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            if (hideReducePoints) {&lt;br /&gt;
              hideElement(reduceChartPointsContainer);&lt;br /&gt;
              handleChartAnimations(ci, true);&lt;br /&gt;
            } else {&lt;br /&gt;
              handleChartAnimations(ci, isReducePointsChecked);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            ci.update();&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        title: {&lt;br /&gt;
          display: true,&lt;br /&gt;
          text: translation.damageRepartition,&lt;br /&gt;
          font: {&lt;br /&gt;
            size: 20,&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        tooltip: {&lt;br /&gt;
          callbacks: {&lt;br /&gt;
            label: function (context) {&lt;br /&gt;
              if (context.label === null) {&lt;br /&gt;
                return nullLabelText;&lt;br /&gt;
              }&lt;br /&gt;
&lt;br /&gt;
              var xValue = battle.numberFormats.default.format(&lt;br /&gt;
                context.parsed.x&lt;br /&gt;
              );&lt;br /&gt;
              var yValue = battle.numberFormats.percent.format(&lt;br /&gt;
                context.parsed.y&lt;br /&gt;
              );&lt;br /&gt;
              var label =&lt;br /&gt;
                &amp;quot; &amp;quot; +&lt;br /&gt;
                context.dataset.label +&lt;br /&gt;
                &amp;quot; : (&amp;quot; +&lt;br /&gt;
                xValue +&lt;br /&gt;
                &amp;quot;, &amp;quot; +&lt;br /&gt;
                yValue +&lt;br /&gt;
                &amp;quot;)&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
              return label;&lt;br /&gt;
            },&lt;br /&gt;
            beforeBody: function (tooltipItems) {&lt;br /&gt;
              if (tooltipItems.length &amp;gt; maxLabelsInTooltip + 1) {&lt;br /&gt;
                tooltipItems.splice(maxLabelsInTooltip + 1);&lt;br /&gt;
                tooltipItems[maxLabelsInTooltip].label = null;&lt;br /&gt;
              }&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          caretPadding: 10,&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
      scales: {&lt;br /&gt;
        x: {&lt;br /&gt;
          type: &amp;quot;linear&amp;quot;,&lt;br /&gt;
          position: &amp;quot;bottom&amp;quot;,&lt;br /&gt;
          title: {&lt;br /&gt;
            display: true,&lt;br /&gt;
            text: translation.damage,&lt;br /&gt;
            font: {&lt;br /&gt;
              size: 16,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          ticks: {&lt;br /&gt;
            callback: function (value) {&lt;br /&gt;
              return Number.isInteger(value) ? value : &amp;quot;&amp;quot;;&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        y: {&lt;br /&gt;
          title: {&lt;br /&gt;
            display: true,&lt;br /&gt;
            text: translation.percentage,&lt;br /&gt;
            font: {&lt;br /&gt;
              size: 16,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          ticks: {&lt;br /&gt;
            format: {&lt;br /&gt;
              style: &amp;quot;percent&amp;quot;,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
      elements: {&lt;br /&gt;
        point: {&lt;br /&gt;
          borderWidth: 1,&lt;br /&gt;
          radius: 3,&lt;br /&gt;
          hitRadius: 3,&lt;br /&gt;
          hoverRadius: 6,&lt;br /&gt;
          hoverBorderWidth: 2,&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
    },&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  var datasetsStyle = [&lt;br /&gt;
    {&lt;br /&gt;
      name: &amp;quot;normalHit&amp;quot;,&lt;br /&gt;
      canBeReduced: false,&lt;br /&gt;
      label: translation.normalHit,&lt;br /&gt;
      backgroundColor: &amp;quot;rgba(75, 192, 192, 0.2)&amp;quot;,&lt;br /&gt;
      borderColor: &amp;quot;rgba(75, 192, 192, 1)&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      name: &amp;quot;piercingHit&amp;quot;,&lt;br /&gt;
      canBeReduced: false,&lt;br /&gt;
      label: translation.piercingHit,&lt;br /&gt;
      backgroundColor: &amp;quot;rgba(192, 192, 75, 0.2)&amp;quot;,&lt;br /&gt;
      borderColor: &amp;quot;rgba(192, 192, 75, 1)&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      name: &amp;quot;criticalHit&amp;quot;,&lt;br /&gt;
      canBeReduced: false,&lt;br /&gt;
      label: translation.criticalHit,&lt;br /&gt;
      backgroundColor: &amp;quot;rgba(192, 75, 192, 0.2)&amp;quot;,&lt;br /&gt;
      borderColor: &amp;quot;rgba(192, 75, 192, 1)&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      name: &amp;quot;criticalPiercingHit&amp;quot;,&lt;br /&gt;
      canBeReduced: false,&lt;br /&gt;
      label: translation.criticalPiercingHit,&lt;br /&gt;
      backgroundColor: &amp;quot;rgba(75, 75, 192, 0.2)&amp;quot;,&lt;br /&gt;
      borderColor: &amp;quot;rgba(75, 75, 192, 1)&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
  ];&lt;br /&gt;
  battle.damageChart = {&lt;br /&gt;
    chart: chart,&lt;br /&gt;
    datasetsStyle: datasetsStyle,&lt;br /&gt;
    maxPoints: 500,&lt;br /&gt;
    reduceChartPointsContainer: reduceChartPointsContainer,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initBonusVariationChart(battle) {&lt;br /&gt;
  var translation = battle.translation;&lt;br /&gt;
&lt;br /&gt;
  var ctx = battle.plotBonusVariation.getContext(&amp;quot;2d&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  var chart = new Chart(ctx, {&lt;br /&gt;
    type: &amp;quot;line&amp;quot;,&lt;br /&gt;
    data: {&lt;br /&gt;
      datasets: [&lt;br /&gt;
        {&lt;br /&gt;
          label: translation.averageDamage,&lt;br /&gt;
          backgroundColor: &amp;quot;rgba(75, 192, 192, 0.2)&amp;quot;,&lt;br /&gt;
          borderColor: &amp;quot;rgba(75, 192, 192, 1)&amp;quot;,&lt;br /&gt;
          fill: true,&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          label: translation.damageAugmentation,&lt;br /&gt;
          backgroundColor: &amp;quot;rgba(192, 192, 75, 0.2)&amp;quot;,&lt;br /&gt;
          borderColor: &amp;quot;rgba(192, 192, 75, 1)&amp;quot;,&lt;br /&gt;
          hidden: true,&lt;br /&gt;
          yTicksFormat: { style: &amp;quot;percent&amp;quot; },&lt;br /&gt;
          fill: true,&lt;br /&gt;
        },&lt;br /&gt;
      ],&lt;br /&gt;
    },&lt;br /&gt;
    options: {&lt;br /&gt;
      responsive: true,&lt;br /&gt;
      maintainAspectRatio: false,&lt;br /&gt;
      plugins: {&lt;br /&gt;
        legend: {&lt;br /&gt;
          display: true,&lt;br /&gt;
          onHover: function (e) {&lt;br /&gt;
            e.native.target.style.cursor = &amp;quot;pointer&amp;quot;;&lt;br /&gt;
          },&lt;br /&gt;
          onLeave: function (e) {&lt;br /&gt;
            e.native.target.style.cursor = &amp;quot;default&amp;quot;;&lt;br /&gt;
          },&lt;br /&gt;
          onClick: function (e, legendItem, legend) {&lt;br /&gt;
            var currentIndex = legendItem.datasetIndex;&lt;br /&gt;
            var ci = legend.chart;&lt;br /&gt;
            var datasets = ci.data.datasets;&lt;br /&gt;
            var isCurrentDatasetVisible = ci.isDatasetVisible(currentIndex);&lt;br /&gt;
            var yAxis = ci.options.scales.y;&lt;br /&gt;
&lt;br /&gt;
            var otherIndex = currentIndex === 0 ? 1 : 0;&lt;br /&gt;
            var visibleDataset = isCurrentDatasetVisible&lt;br /&gt;
              ? datasets[otherIndex]&lt;br /&gt;
              : datasets[currentIndex];&lt;br /&gt;
&lt;br /&gt;
            datasets[currentIndex].hidden = isCurrentDatasetVisible;&lt;br /&gt;
            datasets[otherIndex].hidden = !isCurrentDatasetVisible;&lt;br /&gt;
&lt;br /&gt;
            yAxis.title.text = visibleDataset.label;&lt;br /&gt;
            yAxis.ticks.format = visibleDataset.yTicksFormat;&lt;br /&gt;
&lt;br /&gt;
            ci.update();&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        title: {&lt;br /&gt;
          display: true,&lt;br /&gt;
          text: translation.bonusVariationTitle,&lt;br /&gt;
          font: {&lt;br /&gt;
            size: 18,&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        tooltip: {&lt;br /&gt;
          caretPadding: 10,&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
      scales: {&lt;br /&gt;
        x: {&lt;br /&gt;
          type: &amp;quot;linear&amp;quot;,&lt;br /&gt;
          position: &amp;quot;bottom&amp;quot;,&lt;br /&gt;
          title: {&lt;br /&gt;
            display: true,&lt;br /&gt;
            text: &amp;quot;Bonus&amp;quot;,&lt;br /&gt;
            font: {&lt;br /&gt;
              size: 16,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          ticks: {&lt;br /&gt;
            callback: function (value) {&lt;br /&gt;
              if (Number.isInteger(value)) {&lt;br /&gt;
                return Number(value);&lt;br /&gt;
              }&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        y: {&lt;br /&gt;
          title: {&lt;br /&gt;
            display: true,&lt;br /&gt;
            text: translation.averageDamage,&lt;br /&gt;
            font: {&lt;br /&gt;
              size: 16,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
      elements: {&lt;br /&gt;
        point: {&lt;br /&gt;
          borderWidth: 1,&lt;br /&gt;
          radius: 3,&lt;br /&gt;
          hitRadius: 3,&lt;br /&gt;
          hoverRadius: 6,&lt;br /&gt;
          hoverBorderWidth: 2,&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
    },&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  battle.bonusVariationChart = chart;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterAttackTypeSelection(characters, battleChoice, targetValue) {&lt;br /&gt;
  var { nameOrVnum: attackerNameOrVnum, isCharacter: isAttackerPlayer } =&lt;br /&gt;
    parseTypeAndName(targetValue);&lt;br /&gt;
&lt;br /&gt;
  if (isAttackerPlayer) {&lt;br /&gt;
    var attacker = characters.savedCharacters[attackerNameOrVnum];&lt;br /&gt;
    filterAttackTypeSelectionCharacter(attacker, battleChoice.attackType);&lt;br /&gt;
  } else {&lt;br /&gt;
    filterAttackTypeSelectionMonster(battleChoice.attackType);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getTranslation(translation) {&lt;br /&gt;
  var userLanguage = navigator.language;&lt;br /&gt;
  var langToUse = &amp;quot;en&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  for (var lang in translation) {&lt;br /&gt;
    if (userLanguage.startsWith(lang)) {&lt;br /&gt;
      langToUse = lang;&lt;br /&gt;
      break;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return translation[langToUse];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addBattleData(battle) {&lt;br /&gt;
  var errorElements = document.querySelectorAll(&amp;quot;[data-error]&amp;quot;);&lt;br /&gt;
  var { elements: attackTypeElements, container: attackTypeContainer } =&lt;br /&gt;
    battle.battleChoice.attackType;&lt;br /&gt;
  var attackTypeChilds = attackTypeContainer.children;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; errorElements.length; index++) {&lt;br /&gt;
    var errorElement = errorElements[index];&lt;br /&gt;
    battle.errorInformation[errorElement.dataset.error] = errorElement;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (var index = 1; index &amp;lt; attackTypeChilds.length - 1; index++) {&lt;br /&gt;
    var attackTypeChild = attackTypeChilds[index];&lt;br /&gt;
    var input = attackTypeChild.querySelector(&amp;quot;input&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    attackTypeElements.push({&lt;br /&gt;
      container: attackTypeChild,&lt;br /&gt;
      input: input,&lt;br /&gt;
      inputClass: input.dataset.class,&lt;br /&gt;
      inputValue: input.value,&lt;br /&gt;
    });&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createDamageCalculatorInformation(chartSource) {&lt;br /&gt;
  var characters = {&lt;br /&gt;
    unsavedChanges: false,&lt;br /&gt;
    savedCharacters: {},&lt;br /&gt;
    currentCharacter: null,&lt;br /&gt;
    savedMonsters: getSavedMonsters(),&lt;br /&gt;
    monsterElements: {},&lt;br /&gt;
    characterCreation: document.getElementById(&amp;quot;character-creation&amp;quot;),&lt;br /&gt;
    addNewCharacterButton: document.getElementById(&amp;quot;add-new-character&amp;quot;),&lt;br /&gt;
    dropZone: document.getElementById(&amp;quot;character-drop-zone&amp;quot;),&lt;br /&gt;
    characterInput: document.getElementById(&amp;quot;character-input&amp;quot;),&lt;br /&gt;
    newCharacterTemplate: document.getElementById(&amp;quot;new-character-template&amp;quot;)&lt;br /&gt;
      .children[0],&lt;br /&gt;
    charactersContainer: document.getElementById(&amp;quot;characters-container&amp;quot;),&lt;br /&gt;
    monsterButtonTemplates: document.getElementById(&amp;quot;monster-button-templates&amp;quot;),&lt;br /&gt;
    monsterTemplate: document.getElementById(&amp;quot;new-monster-template&amp;quot;)&lt;br /&gt;
      .children[0],&lt;br /&gt;
    monstersContainer: document.getElementById(&amp;quot;monsters-container&amp;quot;),&lt;br /&gt;
    monsteriFrame: document.getElementById(&amp;quot;monster-iframe&amp;quot;),&lt;br /&gt;
    stoneiFrame: document.getElementById(&amp;quot;stone-iframe&amp;quot;),&lt;br /&gt;
    saveButton: document.getElementById(&amp;quot;save-character&amp;quot;),&lt;br /&gt;
    weaponCategory: document.getElementById(&amp;quot;weapon-category&amp;quot;),&lt;br /&gt;
    weaponDisplay: document.getElementById(&amp;quot;weapon-display&amp;quot;),&lt;br /&gt;
    randomAttackValue: document.getElementById(&amp;quot;random-attack-value&amp;quot;),&lt;br /&gt;
    randomMagicAttackValue: document.getElementById(&lt;br /&gt;
      &amp;quot;random-magic-attack-value&amp;quot;&lt;br /&gt;
    ),&lt;br /&gt;
    toggleSiblings: {},&lt;br /&gt;
    polymorphDisplay: document.getElementById(&amp;quot;polymorph-display&amp;quot;),&lt;br /&gt;
    bonusVariation: {&lt;br /&gt;
      tabButton: document.getElementById(&amp;quot;Variation&amp;quot;),&lt;br /&gt;
      checkbox: document.getElementById(&amp;quot;use-bonus-variation&amp;quot;),&lt;br /&gt;
      input: document.getElementById(&amp;quot;bonus-variation&amp;quot;),&lt;br /&gt;
      inputName: document.getElementById(&amp;quot;bonus-variation-name&amp;quot;),&lt;br /&gt;
      container: document.getElementById(&amp;quot;bonus-variation-creation&amp;quot;),&lt;br /&gt;
      minValue: document.getElementById(&amp;quot;bonus-variation-min-value&amp;quot;),&lt;br /&gt;
      maxValue: document.getElementById(&amp;quot;bonus-variation-max-value&amp;quot;),&lt;br /&gt;
      disabledText: document.getElementById(&amp;quot;bonus-variation-disabled&amp;quot;),&lt;br /&gt;
      selectedText: document.getElementById(&amp;quot;bonus-variation-selected&amp;quot;),&lt;br /&gt;
      displaySpan: document.getElementById(&amp;quot;bonus-variation-display&amp;quot;),&lt;br /&gt;
    },&lt;br /&gt;
    skillElementsToFilter: document.querySelectorAll(&lt;br /&gt;
      &amp;quot;#skill-container [data-class]&amp;quot;&lt;br /&gt;
    ),&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  for (var [pseudo, character] of Object.entries(getSavedCharacters())) {&lt;br /&gt;
    characters.savedCharacters[pseudo] = character;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  document.querySelectorAll(&amp;quot;.toggle-sibling&amp;quot;).forEach(function (element) {&lt;br /&gt;
    var target = element.dataset.target;&lt;br /&gt;
    var sibling = document.getElementById(target);&lt;br /&gt;
    characters.toggleSiblings[element.name] = sibling;&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  var constants = createConstants();&lt;br /&gt;
&lt;br /&gt;
  var battle = {&lt;br /&gt;
    savedFights: getSavedFights(),&lt;br /&gt;
    battleChoice: {&lt;br /&gt;
      resetAttackType: false,&lt;br /&gt;
      form: document.getElementById(&amp;quot;create-battle&amp;quot;),&lt;br /&gt;
      template: document.getElementById(&amp;quot;battle-selection-template&amp;quot;)&lt;br /&gt;
        .children[0],&lt;br /&gt;
      raceToImage: {&lt;br /&gt;
        warrior: &amp;quot;/images/0/0f/Bandeaurougehomme.png&amp;quot;,&lt;br /&gt;
        ninja: &amp;quot;/images/0/0e/Queuedechevalclair.png&amp;quot;,&lt;br /&gt;
        sura: &amp;quot;/images/3/37/Couperespectablerouge.png&amp;quot;,&lt;br /&gt;
        shaman: &amp;quot;/images/6/6a/Coupeeleganteclairfemme.png&amp;quot;,&lt;br /&gt;
        lycan: &amp;quot;/images/4/4e/Protectionfrontalerouge.png&amp;quot;,&lt;br /&gt;
      },&lt;br /&gt;
      categories: [&amp;quot;attacker&amp;quot;, &amp;quot;victim&amp;quot;],&lt;br /&gt;
      attacker: {&lt;br /&gt;
        character: {&lt;br /&gt;
          count: 0,&lt;br /&gt;
          container: document.getElementById(&amp;quot;attacker-selection-characters&amp;quot;),&lt;br /&gt;
          elements: {},&lt;br /&gt;
        },&lt;br /&gt;
        monster: {&lt;br /&gt;
          count: 0,&lt;br /&gt;
          container: document.getElementById(&amp;quot;attacker-selection-monsters&amp;quot;),&lt;br /&gt;
          elements: {},&lt;br /&gt;
        },&lt;br /&gt;
        button: document.getElementById(&amp;quot;attacker-trigger&amp;quot;),&lt;br /&gt;
        defaultButtonContent: document.getElementById(&lt;br /&gt;
          &amp;quot;attacker-default-button-content&amp;quot;&lt;br /&gt;
        ),&lt;br /&gt;
        buttonContent: document.getElementById(&amp;quot;attacker-button-content&amp;quot;),&lt;br /&gt;
        container: document.getElementById(&amp;quot;attacker-selection&amp;quot;),&lt;br /&gt;
        selected: null,&lt;br /&gt;
      },&lt;br /&gt;
      victim: {&lt;br /&gt;
        character: {&lt;br /&gt;
          count: 0,&lt;br /&gt;
          container: document.getElementById(&amp;quot;victim-selection-characters&amp;quot;),&lt;br /&gt;
          elements: {},&lt;br /&gt;
        },&lt;br /&gt;
        monster: {&lt;br /&gt;
          count: 0,&lt;br /&gt;
          container: document.getElementById(&amp;quot;victim-selection-monsters&amp;quot;),&lt;br /&gt;
          elements: {},&lt;br /&gt;
        },&lt;br /&gt;
        stone: {&lt;br /&gt;
          count: 0,&lt;br /&gt;
          container: document.getElementById(&amp;quot;victim-selection-stones&amp;quot;),&lt;br /&gt;
          elements: {},&lt;br /&gt;
        },&lt;br /&gt;
        button: document.getElementById(&amp;quot;victim-trigger&amp;quot;),&lt;br /&gt;
        defaultButtonContent: document.getElementById(&lt;br /&gt;
          &amp;quot;victim-default-button-content&amp;quot;&lt;br /&gt;
        ),&lt;br /&gt;
        buttonContent: document.getElementById(&amp;quot;victim-button-content&amp;quot;),&lt;br /&gt;
        selected: null,&lt;br /&gt;
      },&lt;br /&gt;
      attackType: {&lt;br /&gt;
        container: document.getElementById(&amp;quot;attack-type-selection&amp;quot;),&lt;br /&gt;
        elements: [],&lt;br /&gt;
        defaultInput: document.getElementById(&amp;quot;physical-attack&amp;quot;),&lt;br /&gt;
        selectedText: &amp;quot;&amp;quot;,&lt;br /&gt;
      },&lt;br /&gt;
    },&lt;br /&gt;
    damageWeightedByType: {},&lt;br /&gt;
    scatterDataByType: {},&lt;br /&gt;
    damageByBonus: [],&lt;br /&gt;
    tableResultFight: document.getElementById(&amp;quot;result-table-fight&amp;quot;),&lt;br /&gt;
    tableResultHistory: document.getElementById(&amp;quot;result-table-history&amp;quot;),&lt;br /&gt;
    deleteFightTemplate: document.getElementById(&amp;quot;delete-fight-template&amp;quot;)&lt;br /&gt;
      .children[0],&lt;br /&gt;
    errorInformation: {},&lt;br /&gt;
    fightResultTitle: document.getElementById(&amp;quot;fight-result-title&amp;quot;),&lt;br /&gt;
    fightResultContainer: document.getElementById(&amp;quot;fight-result-container&amp;quot;),&lt;br /&gt;
    downLoadRawData: document.getElementById(&amp;quot;download-raw-data&amp;quot;),&lt;br /&gt;
    downLoadRawDataVariation: document.getElementById(&lt;br /&gt;
      &amp;quot;download-raw-data-variation&amp;quot;&lt;br /&gt;
    ),&lt;br /&gt;
    bonusVariationResultContainer: document.getElementById(&lt;br /&gt;
      &amp;quot;bonus-variation-result-container&amp;quot;&lt;br /&gt;
    ),&lt;br /&gt;
    reduceChartPointsContainer: document.getElementById(&lt;br /&gt;
      &amp;quot;reduce-chart-points-container&amp;quot;&lt;br /&gt;
    ),&lt;br /&gt;
    reduceChartPoints: document.getElementById(&amp;quot;reduce-chart-points&amp;quot;),&lt;br /&gt;
    plotDamage: document.getElementById(&amp;quot;plot-damage&amp;quot;),&lt;br /&gt;
    plotBonusVariation: document.getElementById(&amp;quot;plot-bonus-variation&amp;quot;),&lt;br /&gt;
    uniqueDamageCounters: document.querySelectorAll(&amp;quot;.unique-damage-counter&amp;quot;),&lt;br /&gt;
    possibleDamageCounter: document.getElementById(&amp;quot;possible-damage-counter&amp;quot;),&lt;br /&gt;
    damageTime: document.getElementById(&amp;quot;damage-time&amp;quot;),&lt;br /&gt;
    displayTime: document.getElementById(&amp;quot;display-time&amp;quot;),&lt;br /&gt;
    simulationCounter: document.getElementById(&amp;quot;simulation-counter&amp;quot;),&lt;br /&gt;
    simulationTime: document.getElementById(&amp;quot;simulation-time&amp;quot;),&lt;br /&gt;
    numberFormats: {&lt;br /&gt;
      default: new Intl.NumberFormat(undefined, {&lt;br /&gt;
        minimumFractionDigits: 0,&lt;br /&gt;
        maximumFractionDigits: 1,&lt;br /&gt;
      }),&lt;br /&gt;
      percent: new Intl.NumberFormat(undefined, {&lt;br /&gt;
        style: &amp;quot;percent&amp;quot;,&lt;br /&gt;
        maximumFractionDigits: 3,&lt;br /&gt;
      }),&lt;br /&gt;
      second: new Intl.NumberFormat(undefined, {&lt;br /&gt;
        style: &amp;quot;unit&amp;quot;,&lt;br /&gt;
        unit: &amp;quot;second&amp;quot;,&lt;br /&gt;
        unitDisplay: &amp;quot;long&amp;quot;,&lt;br /&gt;
        maximumFractionDigits: 3,&lt;br /&gt;
      }),&lt;br /&gt;
    },&lt;br /&gt;
    mapping: createMapping(),&lt;br /&gt;
    constants: constants,&lt;br /&gt;
    translation: getTranslation(constants.translation),&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  addBattleData(battle);&lt;br /&gt;
  initResultTableHistory(battle);&lt;br /&gt;
  addScript(chartSource, function () {&lt;br /&gt;
    initDamageChart(battle);&lt;br /&gt;
    initBonusVariationChart(battle);&lt;br /&gt;
  });&lt;br /&gt;
  reduceChartPointsListener(battle);&lt;br /&gt;
  downloadRawDataListener(battle);&lt;br /&gt;
&lt;br /&gt;
  return [characters, battle];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadStyle(src) {&lt;br /&gt;
  var link = document.createElement(&amp;quot;link&amp;quot;);&lt;br /&gt;
  link.href = src;&lt;br /&gt;
  link.rel = &amp;quot;stylesheet&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  document.head.appendChild(link);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
(function () {&lt;br /&gt;
  var javascriptSource =&lt;br /&gt;
    &amp;quot;/index.php?title=Utilisateur:Ankhseram/Calculator.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&amp;quot;;&lt;br /&gt;
  var cssSource =&lt;br /&gt;
    &amp;quot;/index.php?title=Utilisateur:Ankhseram/Style.css&amp;amp;action=raw&amp;amp;ctype=text/css&amp;quot;;&lt;br /&gt;
  var chartSource = &amp;quot;https://cdn.jsdelivr.net/npm/chart.js&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  loadStyle(cssSource);&lt;br /&gt;
&lt;br /&gt;
  function main() {&lt;br /&gt;
    var [characters, battle] = createDamageCalculatorInformation(chartSource);&lt;br /&gt;
&lt;br /&gt;
    characterManagement(characters, battle);&lt;br /&gt;
    monsterManagement(characters, battle);&lt;br /&gt;
&lt;br /&gt;
    updateBattleChoice(characters, battle.battleChoice);&lt;br /&gt;
    createBattle(characters, battle);&lt;br /&gt;
  }&lt;br /&gt;
  addScript(javascriptSource, main);&lt;br /&gt;
})();&lt;/div&gt;</summary>
		<author><name>Dexter</name></author>
		
	</entry>
	<entry>
		<id>https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Script/Modal.js&amp;diff=106296</id>
		<title>MediaWiki:Script/Modal.js</title>
		<link rel="alternate" type="text/html" href="https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Script/Modal.js&amp;diff=106296"/>
		<updated>2025-01-23T15:21:52Z</updated>

		<summary type="html">&lt;p&gt;Dexter : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;function handleModal(button) {&lt;br /&gt;
  const modalName = button.dataset.modal;&lt;br /&gt;
  let modalContainer;&lt;br /&gt;
&lt;br /&gt;
  if (modalName) {&lt;br /&gt;
    modalContainer = document.querySelector(&lt;br /&gt;
      `.modal[data-modal=&amp;quot;${modalName}&amp;quot;]`&lt;br /&gt;
    );&lt;br /&gt;
  } else {&lt;br /&gt;
    modalContainer = button.nextElementSibling;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  const closeButton = modalContainer.querySelector(&amp;quot;.close-button&amp;quot;);&lt;br /&gt;
  const { autoCloseChange, autoCloseLink, addEvent } = modalContainer.dataset;&lt;br /&gt;
&lt;br /&gt;
  button.addEventListener(&amp;quot;click&amp;quot;, openModal);&lt;br /&gt;
  closeButton.addEventListener(&amp;quot;click&amp;quot;, closeModal);&lt;br /&gt;
&lt;br /&gt;
  if (autoCloseChange === &amp;quot;1&amp;quot;) {&lt;br /&gt;
    modalContainer.addEventListener(&amp;quot;change&amp;quot;, closeModal);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (autoCloseLink === &amp;quot;1&amp;quot;) {&lt;br /&gt;
    const links = modalContainer.querySelectorAll(&amp;quot;a&amp;quot;);&lt;br /&gt;
    links.forEach((link) =&amp;gt; {&lt;br /&gt;
      link.addEventListener(&amp;quot;click&amp;quot;, closeModal);&lt;br /&gt;
    });&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function openModal() {&lt;br /&gt;
    button.classList.add(&amp;quot;tabber-active&amp;quot;);&lt;br /&gt;
    modalContainer.classList.add(&amp;quot;show-modal&amp;quot;);&lt;br /&gt;
    window.addEventListener(&amp;quot;click&amp;quot;, handleClickOutside);&lt;br /&gt;
    window.addEventListener(&amp;quot;keydown&amp;quot;, handleEscape);&lt;br /&gt;
&lt;br /&gt;
    if (addEvent === &amp;quot;1&amp;quot;) {&lt;br /&gt;
      const modalOpenEvent = new CustomEvent('modalOpen', {&lt;br /&gt;
        bubbles: true,&lt;br /&gt;
        detail: { modal: modalContainer, name: modalName }&lt;br /&gt;
      });&lt;br /&gt;
      button.dispatchEvent(modalOpenEvent);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function closeModal() {&lt;br /&gt;
    button.classList.remove(&amp;quot;tabber-active&amp;quot;);&lt;br /&gt;
    modalContainer.classList.remove(&amp;quot;show-modal&amp;quot;);&lt;br /&gt;
    window.removeEventListener(&amp;quot;click&amp;quot;, handleClickOutside);&lt;br /&gt;
    window.removeEventListener(&amp;quot;keydown&amp;quot;, handleEscape);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function handleClickOutside(event) {&lt;br /&gt;
    if (event.target === modalContainer) {&lt;br /&gt;
      closeModal();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function handleEscape(event) {&lt;br /&gt;
    if (event.key === &amp;quot;Escape&amp;quot;) {&lt;br /&gt;
      closeModal();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function mainModal() {&lt;br /&gt;
  const modalButtons = document.querySelectorAll(&amp;quot;.modal-trigger&amp;quot;);&lt;br /&gt;
  modalButtons.forEach(handleModal);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
mainModal();&lt;/div&gt;</summary>
		<author><name>Dexter</name></author>
		
	</entry>
	<entry>
		<id>https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Script/Calculator.js&amp;diff=106295</id>
		<title>MediaWiki:Script/Calculator.js</title>
		<link rel="alternate" type="text/html" href="https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Script/Calculator.js&amp;diff=106295"/>
		<updated>2025-01-23T15:19:11Z</updated>

		<summary type="html">&lt;p&gt;Dexter : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;function removeAccent(str) {&lt;br /&gt;
  return str.normalize(&amp;quot;NFD&amp;quot;).replace(/[\u0300-\u036f]/g, &amp;quot;&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function pseudoFormat(str) {&lt;br /&gt;
  return removeAccent(str).replace(/[^A-Za-z0-9 \(\)\+_-]+/g, &amp;quot;&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isValueInArray(value, array) {&lt;br /&gt;
  return array.indexOf(value) !== -1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function splitFirst(value, delimiter) {&lt;br /&gt;
  var parts = value.split(delimiter);&lt;br /&gt;
  var first = parts[0];&lt;br /&gt;
  var rest = parts.slice(1).join(delimiter);&lt;br /&gt;
  return [first, rest];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function copyObject(object) {&lt;br /&gt;
  var copy = {};&lt;br /&gt;
  for (var key in object) {&lt;br /&gt;
    copy[key] = object[key];&lt;br /&gt;
  }&lt;br /&gt;
  return copy;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function compareNumbers(a, b) {&lt;br /&gt;
  return b - a;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isChecked(attribute) {&lt;br /&gt;
  return attribute === &amp;quot;on&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function floorMultiplication(firstFactor, secondFactor) {&lt;br /&gt;
  // @ts-ignore&lt;br /&gt;
  return Math.floor((firstFactor * secondFactor).toFixed(8));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function truncateNumber(number, precision) {&lt;br /&gt;
  return Math.floor(number * 10 ** precision) / 10 ** precision;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function newChangeEvent() {&lt;br /&gt;
  return new Event(&amp;quot;change&amp;quot;, { bubbles: true });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addKeyValue(object, key, value) {&lt;br /&gt;
  if (object.hasOwnProperty(key)) {&lt;br /&gt;
    object[key] += value;&lt;br /&gt;
  } else {&lt;br /&gt;
    object[key] = value;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function openTargetTab(target) {&lt;br /&gt;
  var tabberContainer = target.closest(&amp;quot;.tabber-container&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (!tabberContainer) {&lt;br /&gt;
    return;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var [buttonsContainer, tabsContainer] = tabberContainer.children;&lt;br /&gt;
  var buttons = buttonsContainer.children;&lt;br /&gt;
  var tabs = tabsContainer.children;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; tabs.length; index++) {&lt;br /&gt;
    var tab = tabs[index];&lt;br /&gt;
    if (tab.contains(target) &amp;amp;&amp;amp; !tab.checkVisibility()) {&lt;br /&gt;
      buttons[index].click();&lt;br /&gt;
      break;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function openTargetCollapsible(target) {&lt;br /&gt;
  var collapsible = target.closest(&amp;quot;.improved-collapsible&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (!collapsible) {&lt;br /&gt;
    return;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var span = collapsible.firstElementChild;&lt;br /&gt;
&lt;br /&gt;
  if (!span.classList.contains(&amp;quot;mw-collapsible-toggle-expanded&amp;quot;)) {&lt;br /&gt;
    span.click();&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function editTableResultRow(row, valuesToDisplay, numberFormat) {&lt;br /&gt;
  row.innerHTML = &amp;quot;&amp;quot;;&lt;br /&gt;
  for (var index = 0; index &amp;lt; valuesToDisplay.length; index++) {&lt;br /&gt;
    var cell = row.insertCell();&lt;br /&gt;
    var textContent;&lt;br /&gt;
&lt;br /&gt;
    if (index &amp;gt;= 3) {&lt;br /&gt;
      textContent = numberFormat.format(valuesToDisplay[index]);&lt;br /&gt;
    } else {&lt;br /&gt;
      textContent = valuesToDisplay[index];&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    cell.textContent = textContent;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return row;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addRowToTableResultHistory(&lt;br /&gt;
  tableResultHistory,&lt;br /&gt;
  valuesToDisplay,&lt;br /&gt;
  deleteFightTemplate,&lt;br /&gt;
  numberFormat&lt;br /&gt;
) {&lt;br /&gt;
  var row = tableResultHistory.insertRow();&lt;br /&gt;
  editTableResultRow(row, valuesToDisplay, numberFormat);&lt;br /&gt;
  var cell = row.insertCell();&lt;br /&gt;
  cell.appendChild(deleteFightTemplate.cloneNode(true));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcMeanDamage(damageWeightedByType, totalCardinal) {&lt;br /&gt;
  var sumDamage = 0;&lt;br /&gt;
&lt;br /&gt;
  for (var damageTypeName in damageWeightedByType) {&lt;br /&gt;
    if (damageTypeName === &amp;quot;miss&amp;quot;) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var damageWeighted = damageWeightedByType[damageTypeName];&lt;br /&gt;
&lt;br /&gt;
    for (var damage in damageWeighted) {&lt;br /&gt;
      sumDamage += damage * damageWeighted[damage];&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return sumDamage / totalCardinal;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function prepareDamageData(&lt;br /&gt;
  damageWeightedByType,&lt;br /&gt;
  possibleDamageCountTemp,&lt;br /&gt;
  totalCardinal&lt;br /&gt;
) {&lt;br /&gt;
  var minDamage = Infinity;&lt;br /&gt;
  var maxDamage = 0;&lt;br /&gt;
  var scatterDataByType = {};&lt;br /&gt;
  var sumDamage = 0;&lt;br /&gt;
  var possibleDamageCount = 0;&lt;br /&gt;
  var uniqueDamageCount = 0;&lt;br /&gt;
&lt;br /&gt;
  for (var damageTypeName in damageWeightedByType) {&lt;br /&gt;
    if (damageTypeName === &amp;quot;miss&amp;quot;) {&lt;br /&gt;
      scatterDataByType.miss = damageWeightedByType.miss;&lt;br /&gt;
      possibleDamageCount++;&lt;br /&gt;
      uniqueDamageCount++;&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var firstIteration = true;&lt;br /&gt;
    var damageWeighted = damageWeightedByType[damageTypeName];&lt;br /&gt;
    var scatterData = [];&lt;br /&gt;
    scatterDataByType[damageTypeName] = scatterData;&lt;br /&gt;
&lt;br /&gt;
    for (var damage in damageWeighted) {&lt;br /&gt;
      damage = +damage;&lt;br /&gt;
&lt;br /&gt;
      if (firstIteration) {&lt;br /&gt;
        if (damage &amp;lt; minDamage) {&lt;br /&gt;
          minDamage = damage;&lt;br /&gt;
        }&lt;br /&gt;
        firstIteration = false;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      var weight = damageWeighted[damage];&lt;br /&gt;
      var probability = weight / totalCardinal;&lt;br /&gt;
&lt;br /&gt;
      sumDamage += damage * weight;&lt;br /&gt;
      damageWeighted[damage] = probability;&lt;br /&gt;
      scatterData.push({ x: damage, y: probability });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var scatterDataLength = scatterData.length;&lt;br /&gt;
&lt;br /&gt;
    possibleDamageCount += possibleDamageCountTemp;&lt;br /&gt;
    uniqueDamageCount += scatterDataLength;&lt;br /&gt;
&lt;br /&gt;
    if (damage &amp;gt; maxDamage) {&lt;br /&gt;
      maxDamage = damage;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (minDamage === Infinity) {&lt;br /&gt;
    minDamage = 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return [&lt;br /&gt;
    sumDamage / totalCardinal,&lt;br /&gt;
    minDamage,&lt;br /&gt;
    maxDamage,&lt;br /&gt;
    scatterDataByType,&lt;br /&gt;
    possibleDamageCount,&lt;br /&gt;
    uniqueDamageCount,&lt;br /&gt;
  ];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function aggregateDamage(scatterData, maxPoints) {&lt;br /&gt;
  var dataLength = scatterData.length;&lt;br /&gt;
  var remainingData = dataLength;&lt;br /&gt;
  var aggregateScatterData = [];&lt;br /&gt;
&lt;br /&gt;
  for (var groupIndex = 0; groupIndex &amp;lt; maxPoints; groupIndex++) {&lt;br /&gt;
    var groupLength = Math.floor(remainingData / (maxPoints - groupIndex));&lt;br /&gt;
    var startIndex = dataLength - remainingData;&lt;br /&gt;
    var aggregateDamage = 0;&lt;br /&gt;
    var aggregateProbability = 0;&lt;br /&gt;
&lt;br /&gt;
    for (var index = startIndex; index &amp;lt; startIndex + groupLength; index++) {&lt;br /&gt;
      var { x: damage, y: probability } = scatterData[index];&lt;br /&gt;
      aggregateDamage += damage * probability;&lt;br /&gt;
      aggregateProbability += probability;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    aggregateScatterData.push({&lt;br /&gt;
      x: aggregateDamage / aggregateProbability,&lt;br /&gt;
      y: aggregateProbability,&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    remainingData -= groupLength;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return aggregateScatterData;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addToDamageChart(&lt;br /&gt;
  scatterDataByType,&lt;br /&gt;
  damageChart,&lt;br /&gt;
  isReducePointsChecked&lt;br /&gt;
) {&lt;br /&gt;
  var { chart, datasetsStyle, maxPoints, reduceChartPointsContainer } =&lt;br /&gt;
    damageChart;&lt;br /&gt;
  var isFirstDataset = true;&lt;br /&gt;
  var datasets = chart.data.datasets;&lt;br /&gt;
&lt;br /&gt;
  datasets.length = 0;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; datasetsStyle.length; index++) {&lt;br /&gt;
    var dataset = copyObject(datasetsStyle[index]);&lt;br /&gt;
&lt;br /&gt;
    if (!scatterDataByType.hasOwnProperty(dataset.name)) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var scatterData = scatterDataByType[dataset.name];&lt;br /&gt;
    var canBeReduced = scatterData.length &amp;gt; 2 * maxPoints;&lt;br /&gt;
&lt;br /&gt;
    dataset.hidden = !isFirstDataset;&lt;br /&gt;
    dataset.canBeReduced = canBeReduced;&lt;br /&gt;
&lt;br /&gt;
    if (canBeReduced &amp;amp;&amp;amp; isReducePointsChecked) {&lt;br /&gt;
      dataset.data = aggregateDamage(scatterData, maxPoints);&lt;br /&gt;
    } else {&lt;br /&gt;
      dataset.data = scatterData;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isFirstDataset) {&lt;br /&gt;
      isFirstDataset = false;&lt;br /&gt;
&lt;br /&gt;
      if (canBeReduced) {&lt;br /&gt;
        showElement(reduceChartPointsContainer);&lt;br /&gt;
&lt;br /&gt;
        if (!isReducePointsChecked) {&lt;br /&gt;
          handleChartAnimations(chart, false);&lt;br /&gt;
        }&lt;br /&gt;
      } else {&lt;br /&gt;
        hideElement(reduceChartPointsContainer);&lt;br /&gt;
        handleChartAnimations(chart, true);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    datasets.push(dataset);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  chart.data.missPercentage = scatterDataByType.miss;&lt;br /&gt;
  chart.update();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addToBonusVariationChart(&lt;br /&gt;
  damageByBonus,&lt;br /&gt;
  augmentationByBonus,&lt;br /&gt;
  xLabel,&lt;br /&gt;
  chart&lt;br /&gt;
) {&lt;br /&gt;
  chart.data.datasets[0].data = damageByBonus;&lt;br /&gt;
  chart.data.datasets[1].data = augmentationByBonus;&lt;br /&gt;
  chart.options.scales.x.title.text = xLabel;&lt;br /&gt;
  chart.update();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleChartAnimations(chart, addAnimations) {&lt;br /&gt;
  chart.options.animation = addAnimations;&lt;br /&gt;
  chart.options.animations.colors = addAnimations;&lt;br /&gt;
  chart.options.animations.x = addAnimations;&lt;br /&gt;
  chart.options.transitions.active.animation.duration = addAnimations * 1000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateDamageChartDescription(&lt;br /&gt;
  uniqueDamageCounters,&lt;br /&gt;
  uniqueDamageCount,&lt;br /&gt;
  formatNumber&lt;br /&gt;
) {&lt;br /&gt;
  uniqueDamageCounters.forEach(function (element) {&lt;br /&gt;
    if (uniqueDamageCount &amp;lt;= 1) {&lt;br /&gt;
      hideElement(element.parentElement);&lt;br /&gt;
    } else {&lt;br /&gt;
      showElement(element.parentElement);&lt;br /&gt;
      element.textContent = formatNumber.format(uniqueDamageCount);&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getMonsterName(monsterVnum) {&lt;br /&gt;
  var monsterAttributes = monsterData[monsterVnum];&lt;br /&gt;
  return monsterAttributes[monsterAttributes.length - 1];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterClass(selectedRace, classChoice, selectValueIsChanged = false) {&lt;br /&gt;
  for (var radioNode of classChoice) {&lt;br /&gt;
    var radioGrandParent = radioNode.parentElement.parentElement;&lt;br /&gt;
&lt;br /&gt;
    if (radioNode.getAttribute(&amp;quot;data-race&amp;quot;) === selectedRace) {&lt;br /&gt;
      if (!selectValueIsChanged) {&lt;br /&gt;
        radioNode.checked = true;&lt;br /&gt;
        selectValueIsChanged = true;&lt;br /&gt;
      }&lt;br /&gt;
      showElement(radioGrandParent);&lt;br /&gt;
    } else {&lt;br /&gt;
      hideElement(radioGrandParent);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterWeapon(&lt;br /&gt;
  selectedRace,&lt;br /&gt;
  weaponElement,&lt;br /&gt;
  weaponCategory,&lt;br /&gt;
  allowedWeaponsPerRace,&lt;br /&gt;
  selectValueIsChanged = false&lt;br /&gt;
) {&lt;br /&gt;
  var allowedWeapons = allowedWeaponsPerRace[selectedRace];&lt;br /&gt;
&lt;br /&gt;
  if (!selectValueIsChanged) {&lt;br /&gt;
    var weaponType = createWeapon(weaponElement.value).type;&lt;br /&gt;
&lt;br /&gt;
    if (!isValueInArray(weaponType, allowedWeapons)) {&lt;br /&gt;
      weaponElement.value = 0;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var children = weaponCategory.children;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; children.length; index++) {&lt;br /&gt;
    var child = children[index];&lt;br /&gt;
&lt;br /&gt;
    if (isValueInArray(index, allowedWeapons)) {&lt;br /&gt;
      showElement(child);&lt;br /&gt;
    } else {&lt;br /&gt;
      hideElement(child);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function changePolymorphValues(characterCreation, monsterVnum, monsterImage) {&lt;br /&gt;
  var { polymorphMonster, polymorphMonsterImage } = characterCreation;&lt;br /&gt;
&lt;br /&gt;
  polymorphMonster.value = monsterVnum;&lt;br /&gt;
  polymorphMonsterImage.value = monsterImage;&lt;br /&gt;
&lt;br /&gt;
  polymorphMonster.dispatchEvent(newChangeEvent());&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function resetImageFromWiki(image) {&lt;br /&gt;
  image.removeAttribute(&amp;quot;srcset&amp;quot;);&lt;br /&gt;
  image.removeAttribute(&amp;quot;data-file-width&amp;quot;);&lt;br /&gt;
  image.removeAttribute(&amp;quot;data-file-height&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleImageFromWiki(image, newSrc) {&lt;br /&gt;
  image.src = newSrc;&lt;br /&gt;
  image.alt = newSrc.split(&amp;quot;/&amp;quot;).pop();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handlePolymorphDisplay(polymorphDisplay, monsterVnum, monsterSrc) {&lt;br /&gt;
  var oldImage = polymorphDisplay.firstChild;&lt;br /&gt;
  var oldLink = oldImage.nextElementSibling;&lt;br /&gt;
  var monsterName = getMonsterName(monsterVnum);&lt;br /&gt;
  var newLink = createWikiLink(monsterName);&lt;br /&gt;
&lt;br /&gt;
  resetImageFromWiki(oldImage);&lt;br /&gt;
  handleImageFromWiki(oldImage, monsterSrc);&lt;br /&gt;
&lt;br /&gt;
  polymorphDisplay.replaceChild(newLink, oldLink);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createWikiLink(pageName) {&lt;br /&gt;
  var wikiLink = document.createElement(&amp;quot;a&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  wikiLink.href = mw.util.getUrl(pageName);&lt;br /&gt;
  wikiLink.title = pageName;&lt;br /&gt;
  wikiLink.textContent = pageName;&lt;br /&gt;
&lt;br /&gt;
  return wikiLink;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSelectedWeapon(weaponCategory) {&lt;br /&gt;
  return weaponCategory.querySelector(&amp;quot;input[type='radio']:checked&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleWeaponDisplay(&lt;br /&gt;
  weaponCategory,&lt;br /&gt;
  weaponDisplay,&lt;br /&gt;
  weaponVnum,&lt;br /&gt;
  newWeapon&lt;br /&gt;
) {&lt;br /&gt;
  var newWeapon = newWeapon || getSelectedWeapon(weaponCategory);&lt;br /&gt;
&lt;br /&gt;
  var newImage = newWeapon.nextElementSibling;&lt;br /&gt;
  var newText = document.createElement(&amp;quot;span&amp;quot;);&lt;br /&gt;
  var oldImage = weaponDisplay.firstChild;&lt;br /&gt;
  var oldText = oldImage.nextElementSibling;&lt;br /&gt;
  var weaponName = newImage.nextElementSibling.dataset.o;&lt;br /&gt;
&lt;br /&gt;
  if (weaponVnum == 0) {&lt;br /&gt;
    newText.textContent = weaponName;&lt;br /&gt;
  } else {&lt;br /&gt;
    var weaponLink = createWikiLink(weaponName);&lt;br /&gt;
    newText.appendChild(weaponLink);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  weaponDisplay.replaceChild(newImage.cloneNode(), oldImage);&lt;br /&gt;
  weaponDisplay.replaceChild(newText, oldText);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterUpgrade(&lt;br /&gt;
  weaponUpgrade,&lt;br /&gt;
  weaponVnum,&lt;br /&gt;
  randomAttackValue,&lt;br /&gt;
  randomMagicAttackValue&lt;br /&gt;
) {&lt;br /&gt;
  var weapon = createWeapon(weaponVnum);&lt;br /&gt;
  var currentUpgrade = Number(weaponUpgrade.value);&lt;br /&gt;
  var weaponUpgradeChildren = weaponUpgrade.children;&lt;br /&gt;
&lt;br /&gt;
  if (weapon.isSerpent) {&lt;br /&gt;
    showElement(randomAttackValue);&lt;br /&gt;
&lt;br /&gt;
    if (weapon.isMagic) {&lt;br /&gt;
      showElement(randomMagicAttackValue);&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    hideElement(randomAttackValue);&lt;br /&gt;
    hideElement(randomMagicAttackValue);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (weapon.maxUpgrade &amp;lt; 1) {&lt;br /&gt;
    hideElement(weaponUpgrade.parentElement);&lt;br /&gt;
  } else {&lt;br /&gt;
    showElement(weaponUpgrade.parentElement);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (var upgrade = 0; upgrade &amp;lt;= weapon.maxUpgrade; upgrade++) {&lt;br /&gt;
    showElement(weaponUpgradeChildren[upgrade]);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (&lt;br /&gt;
    var upgrade = weapon.maxUpgrade + 1;&lt;br /&gt;
    upgrade &amp;lt; weaponUpgradeChildren.length;&lt;br /&gt;
    upgrade++&lt;br /&gt;
  ) {&lt;br /&gt;
    hideElement(weaponUpgradeChildren[upgrade]);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (currentUpgrade &amp;gt; weapon.maxUpgrade) {&lt;br /&gt;
    weaponUpgrade.value = weapon.maxUpgrade;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterCheckbox(checkbox, element) {&lt;br /&gt;
  if (checkbox.checked) {&lt;br /&gt;
    showElement(element);&lt;br /&gt;
  } else {&lt;br /&gt;
    hideElement(element);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterSkills(selectedClass, skillElementsToFilter) {&lt;br /&gt;
  for (var element of skillElementsToFilter) {&lt;br /&gt;
    if (isValueInArray(selectedClass, element.dataset.class)) {&lt;br /&gt;
      showElement(element);&lt;br /&gt;
    } else {&lt;br /&gt;
      hideElement(element);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterForm(characters, battle) {&lt;br /&gt;
  var { saveButton, characterCreation } = characters;&lt;br /&gt;
  var allowedWeaponsPerRace = battle.constants.allowedWeaponsPerRace;&lt;br /&gt;
  var battleChoice = battle.battleChoice;&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;change&amp;quot;, function (event) {&lt;br /&gt;
    var target = event.target;&lt;br /&gt;
    var targetName = target.name;&lt;br /&gt;
&lt;br /&gt;
    saveButtonOrange(saveButton);&lt;br /&gt;
    characters.unsavedChanges = true;&lt;br /&gt;
&lt;br /&gt;
    switch (targetName) {&lt;br /&gt;
      case &amp;quot;race&amp;quot;:&lt;br /&gt;
        var selectedRace = target.value;&lt;br /&gt;
        var classChoice = characterCreation.class;&lt;br /&gt;
        var weaponElement = characterCreation.weapon;&lt;br /&gt;
&lt;br /&gt;
        filterClass(selectedRace, classChoice);&lt;br /&gt;
        filterWeapon(&lt;br /&gt;
          selectedRace,&lt;br /&gt;
          weaponElement,&lt;br /&gt;
          characters.weaponCategory,&lt;br /&gt;
          allowedWeaponsPerRace&lt;br /&gt;
        );&lt;br /&gt;
        handleWeaponDisplay(&lt;br /&gt;
          characters.weaponCategory,&lt;br /&gt;
          characters.weaponDisplay,&lt;br /&gt;
          weaponElement.value&lt;br /&gt;
        );&lt;br /&gt;
        filterUpgrade(&lt;br /&gt;
          characterCreation.weaponUpgrade,&lt;br /&gt;
          weaponElement.value,&lt;br /&gt;
          characters.randomAttackValue,&lt;br /&gt;
          characters.randomMagicAttackValue&lt;br /&gt;
        );&lt;br /&gt;
        filterSkills(classChoice.value, characters.skillElementsToFilter);&lt;br /&gt;
        handleBonusVariationUpdate(&lt;br /&gt;
          characterCreation,&lt;br /&gt;
          characters.bonusVariation,&lt;br /&gt;
          true&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        battleChoice.resetAttackType = true;&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;class&amp;quot;:&lt;br /&gt;
        filterSkills(target.value, characters.skillElementsToFilter);&lt;br /&gt;
        handleBonusVariationUpdate(&lt;br /&gt;
          characterCreation,&lt;br /&gt;
          characters.bonusVariation,&lt;br /&gt;
          true&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        battleChoice.resetAttackType = true;&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;weapon&amp;quot;:&lt;br /&gt;
        var weaponElement = characterCreation.weapon;&lt;br /&gt;
&lt;br /&gt;
        handleWeaponDisplay(&lt;br /&gt;
          characters.weaponCategory,&lt;br /&gt;
          characters.weaponDisplay,&lt;br /&gt;
          weaponElement.value,&lt;br /&gt;
          target&lt;br /&gt;
        );&lt;br /&gt;
        filterUpgrade(&lt;br /&gt;
          characterCreation.weaponUpgrade,&lt;br /&gt;
          target.value,&lt;br /&gt;
          characters.randomAttackValue,&lt;br /&gt;
          characters.randomMagicAttackValue&lt;br /&gt;
        );&lt;br /&gt;
        handleBonusVariationUpdate(&lt;br /&gt;
          characterCreation,&lt;br /&gt;
          characters.bonusVariation&lt;br /&gt;
        );&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;isRiding&amp;quot;:&lt;br /&gt;
        battleChoice.resetAttackType = true;&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;isPolymorph&amp;quot;:&lt;br /&gt;
        filterCheckbox(target, characters.polymorphCreation);&lt;br /&gt;
        battleChoice.resetAttackType = true;&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;lowRank&amp;quot;:&lt;br /&gt;
        filterCheckbox(target, characters.rankSelection);&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;isBlessed&amp;quot;:&lt;br /&gt;
        filterCheckbox(target, characters.blessingCreation);&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;onYohara&amp;quot;:&lt;br /&gt;
        filterCheckbox(target, characters.yoharaCreation);&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;isMarried&amp;quot;:&lt;br /&gt;
        filterCheckbox(target, characters.marriageCreation);&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;useBonusVariation&amp;quot;:&lt;br /&gt;
        filterCheckbox(target, characters.bonusVariation.container);&lt;br /&gt;
        break;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      targetName.startsWith(&amp;quot;attackSkill&amp;quot;) ||&lt;br /&gt;
      targetName.startsWith(&amp;quot;horseSkill&amp;quot;)&lt;br /&gt;
    ) {&lt;br /&gt;
      battleChoice.resetAttackType = true;&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addUniquePseudo(characterDataObject, savedCharactersPseudo) {&lt;br /&gt;
  var characterPseudo = String(characterDataObject.name);&lt;br /&gt;
  var originalPseudo = characterPseudo;&lt;br /&gt;
  var count = 0;&lt;br /&gt;
&lt;br /&gt;
  var regex = /(.*)(\d)$/;&lt;br /&gt;
  var match = characterPseudo.match(regex);&lt;br /&gt;
&lt;br /&gt;
  if (match) {&lt;br /&gt;
    originalPseudo = match[1];&lt;br /&gt;
    count = match[2];&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  while (isValueInArray(characterPseudo, savedCharactersPseudo)) {&lt;br /&gt;
    characterPseudo = originalPseudo + count;&lt;br /&gt;
    count++;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  characterDataObject.name = characterPseudo;&lt;br /&gt;
  return [characterDataObject, characterPseudo];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function convertToNumber(value) {&lt;br /&gt;
  var valueNumber = Number(value);&lt;br /&gt;
  return isNaN(valueNumber) ? value : valueNumber;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getLocalStorageValue(key, defaultValue) {&lt;br /&gt;
  var storedValue = localStorage.getItem(key);&lt;br /&gt;
&lt;br /&gt;
  if (storedValue) {&lt;br /&gt;
    return JSON.parse(storedValue);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return defaultValue;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSavedCharacters() {&lt;br /&gt;
  return getLocalStorageValue(&amp;quot;savedCharactersCalculator&amp;quot;, {});&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSavedMonsters() {&lt;br /&gt;
  var savedMonsters = getLocalStorageValue(&amp;quot;savedMonstersCalculator&amp;quot;, {});&lt;br /&gt;
&lt;br /&gt;
  if (Array.isArray(savedMonsters)) {&lt;br /&gt;
    return {};&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var filteredMonsters = {};&lt;br /&gt;
&lt;br /&gt;
  for (var vnum in savedMonsters) {&lt;br /&gt;
    if (&lt;br /&gt;
      String(Number(vnum)) === vnum &amp;amp;&amp;amp;&lt;br /&gt;
      savedMonsters[vnum].hasOwnProperty(&amp;quot;category&amp;quot;)&lt;br /&gt;
    ) {&lt;br /&gt;
      filteredMonsters[vnum] = savedMonsters[vnum];&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  updateSavedMonsters(filteredMonsters);&lt;br /&gt;
&lt;br /&gt;
  return filteredMonsters;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSavedFights() {&lt;br /&gt;
  return getLocalStorageValue(&amp;quot;savedFightsCalculator&amp;quot;, []);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveToLocalStorage(key, value) {&lt;br /&gt;
  localStorage.setItem(key, JSON.stringify(value));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateSavedCharacters(savedCharacters) {&lt;br /&gt;
  saveToLocalStorage(&amp;quot;savedCharactersCalculator&amp;quot;, savedCharacters);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateSavedMonsters(savedMonsters) {&lt;br /&gt;
  saveToLocalStorage(&amp;quot;savedMonstersCalculator&amp;quot;, savedMonsters);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateSavedFights(savedFights) {&lt;br /&gt;
  saveToLocalStorage(&amp;quot;savedFightsCalculator&amp;quot;, savedFights);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveCharacter(&lt;br /&gt;
  savedCharacters,&lt;br /&gt;
  characterCreation,&lt;br /&gt;
  battle,&lt;br /&gt;
  newCharacter,&lt;br /&gt;
  characterDataObject&lt;br /&gt;
) {&lt;br /&gt;
  if (!characterDataObject) {&lt;br /&gt;
    var characterData = new FormData(characterCreation);&lt;br /&gt;
    var characterDataObject = {};&lt;br /&gt;
&lt;br /&gt;
    characterData.forEach(function (value, key) {&lt;br /&gt;
      characterDataObject[key] = convertToNumber(value);&lt;br /&gt;
    });&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var characterPseudo = characterDataObject.name;&lt;br /&gt;
  var { battleChoice } = battle;&lt;br /&gt;
&lt;br /&gt;
  savedCharacters[characterPseudo] = characterDataObject;&lt;br /&gt;
  updateSavedCharacters(savedCharacters);&lt;br /&gt;
&lt;br /&gt;
  if (newCharacter) {&lt;br /&gt;
    addBattleChoice(battleChoice, characterPseudo, characterDataObject);&lt;br /&gt;
  } else {&lt;br /&gt;
    updateBattleChoiceImage(&lt;br /&gt;
      battleChoice,&lt;br /&gt;
      characterPseudo,&lt;br /&gt;
      characterDataObject.race&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (battleChoice.resetAttackType) {&lt;br /&gt;
    if (isCharacterSelected(characterPseudo, battleChoice.attacker.selected)) {&lt;br /&gt;
      filterAttackTypeSelectionCharacter(&lt;br /&gt;
        characterDataObject,&lt;br /&gt;
        battleChoice.attackType&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
    battleChoice.resetAttackType = false;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveButtonGreen(saveButton) {&lt;br /&gt;
  saveButton.classList.remove(&amp;quot;unsaved-character&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveButtonOrange(saveButton) {&lt;br /&gt;
  saveButton.classList.add(&amp;quot;unsaved-character&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function characterCreationListener(characters, battle) {&lt;br /&gt;
  var { characterCreation, saveButton, weaponCategory } = characters;&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;submit&amp;quot;, handleSubmitForm);&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;invalid&amp;quot;, handleInvalidInput, true);&lt;br /&gt;
  document.addEventListener(&amp;quot;keydown&amp;quot;, handleSaveShortcut);&lt;br /&gt;
  weaponCategory.addEventListener(&amp;quot;mouseover&amp;quot;, handleTooltipOverflow);&lt;br /&gt;
&lt;br /&gt;
  function handleSubmitForm(event) {&lt;br /&gt;
    event.preventDefault();&lt;br /&gt;
&lt;br /&gt;
    if (characters.unsavedChanges) {&lt;br /&gt;
      saveCharacter(characters.savedCharacters, characterCreation, battle);&lt;br /&gt;
      saveButtonGreen(saveButton);&lt;br /&gt;
      characters.unsavedChanges = false;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function handleInvalidInput(event) {&lt;br /&gt;
    var target = event.target;&lt;br /&gt;
&lt;br /&gt;
    if (target.checkVisibility()) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var autoCorrectInput = target.closest(&amp;quot;.auto-correct-input&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      autoCorrectInput &amp;amp;&amp;amp;&lt;br /&gt;
      autoCorrectInput.classList.contains(&amp;quot;tabber-noactive&amp;quot;)&lt;br /&gt;
    ) {&lt;br /&gt;
      target.value = target.defaultValue;&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    openTargetTab(target);&lt;br /&gt;
    openTargetCollapsible(target);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function handleSaveShortcut(event) {&lt;br /&gt;
    if (event.ctrlKey &amp;amp;&amp;amp; event.key === &amp;quot;s&amp;quot;) {&lt;br /&gt;
      event.preventDefault();&lt;br /&gt;
      saveButton.click();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function handleTooltipOverflow(event) {&lt;br /&gt;
    var label = event.target.closest(&amp;quot;label&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (label) {&lt;br /&gt;
      var tooltip = label.lastChild;&lt;br /&gt;
&lt;br /&gt;
      if (tooltip.classList.contains(&amp;quot;popContenu&amp;quot;)) {&lt;br /&gt;
        var tooltipRect = tooltip.getBoundingClientRect();&lt;br /&gt;
        var modalRect = weaponCategory.getBoundingClientRect();&lt;br /&gt;
&lt;br /&gt;
        if (tooltipRect.right &amp;gt; modalRect.right) {&lt;br /&gt;
          tooltip.style.left = &amp;quot;-100%&amp;quot;;&lt;br /&gt;
        } else if (tooltipRect.left &amp;lt; modalRect.left) {&lt;br /&gt;
          tooltip.style.left = &amp;quot;200%&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function downloadData(content, type, filename) {&lt;br /&gt;
  var link = document.createElement(&amp;quot;a&amp;quot;);&lt;br /&gt;
  var blob = new Blob([content], { type: type });&lt;br /&gt;
  var blobURL = URL.createObjectURL(blob);&lt;br /&gt;
&lt;br /&gt;
  link.href = blobURL;&lt;br /&gt;
  link.download = filename;&lt;br /&gt;
  document.body.appendChild(link);&lt;br /&gt;
&lt;br /&gt;
  link.click();&lt;br /&gt;
  document.body.removeChild(link);&lt;br /&gt;
  URL.revokeObjectURL(blobURL);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function uploadCharacter(&lt;br /&gt;
  selectedFiles,&lt;br /&gt;
  characters,&lt;br /&gt;
  characterTemplate,&lt;br /&gt;
  charactersContainer,&lt;br /&gt;
  battle&lt;br /&gt;
) {&lt;br /&gt;
  var selectFilesLength = selectedFiles.length;&lt;br /&gt;
&lt;br /&gt;
  for (var fileIndex = 0; fileIndex &amp;lt; selectFilesLength; fileIndex++) {&lt;br /&gt;
    var selectedFile = selectedFiles[fileIndex];&lt;br /&gt;
&lt;br /&gt;
    if (selectedFile.type === &amp;quot;text/plain&amp;quot;) {&lt;br /&gt;
      var reader = new FileReader();&lt;br /&gt;
      reader.onload = function (e) {&lt;br /&gt;
        var fileContent = e.target.result;&lt;br /&gt;
        try {&lt;br /&gt;
          var characterDataObject = JSON.parse(fileContent);&lt;br /&gt;
&lt;br /&gt;
          if (characterDataObject.hasOwnProperty(&amp;quot;name&amp;quot;)) {&lt;br /&gt;
            var characterPseudo = String(characterDataObject.name);&lt;br /&gt;
&lt;br /&gt;
            hideElement(characters.characterCreation);&lt;br /&gt;
            characterPseudo = validPseudo(characterPseudo);&lt;br /&gt;
&lt;br /&gt;
            [characterDataObject, characterPseudo] = addUniquePseudo(&lt;br /&gt;
              characterDataObject,&lt;br /&gt;
              Object.keys(characters.savedCharacters)&lt;br /&gt;
            );&lt;br /&gt;
            var selectedCharacter = handleNewCharacter(&lt;br /&gt;
              characters,&lt;br /&gt;
              characterTemplate,&lt;br /&gt;
              charactersContainer,&lt;br /&gt;
              battle,&lt;br /&gt;
              characterPseudo&lt;br /&gt;
            )[0];&lt;br /&gt;
&lt;br /&gt;
            if (selectFilesLength === 1) {&lt;br /&gt;
              updateForm(&lt;br /&gt;
                characterDataObject,&lt;br /&gt;
                characters.characterCreation,&lt;br /&gt;
                characters,&lt;br /&gt;
                selectedCharacter,&lt;br /&gt;
                battle&lt;br /&gt;
              );&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            saveCharacter(&lt;br /&gt;
              characters.savedCharacters,&lt;br /&gt;
              characters.characterCreation,&lt;br /&gt;
              battle,&lt;br /&gt;
              true,&lt;br /&gt;
              characterDataObject&lt;br /&gt;
            );&lt;br /&gt;
          }&lt;br /&gt;
        } catch (error) {&lt;br /&gt;
          console.log(error);&lt;br /&gt;
          if (error.name === &amp;quot;TypeError&amp;quot;) {&lt;br /&gt;
            // delete the character&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
      };&lt;br /&gt;
      reader.readAsText(selectedFile);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleUploadCharacter(&lt;br /&gt;
  characters,&lt;br /&gt;
  characterTemplate,&lt;br /&gt;
  charactersContainer,&lt;br /&gt;
  battle&lt;br /&gt;
) {&lt;br /&gt;
  var characterInput = characters.characterInput;&lt;br /&gt;
  var dropZone = characters.dropZone;&lt;br /&gt;
&lt;br /&gt;
  characterInput.accept = &amp;quot;.txt&amp;quot;;&lt;br /&gt;
  characterInput.multiple = true;&lt;br /&gt;
  dropZone.setAttribute(&amp;quot;tabindex&amp;quot;, &amp;quot;0&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  dropZone.addEventListener(&amp;quot;click&amp;quot;, function () {&lt;br /&gt;
    characterInput.click();&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  dropZone.addEventListener(&amp;quot;dragover&amp;quot;, function (event) {&lt;br /&gt;
    event.preventDefault();&lt;br /&gt;
    dropZone.classList.add(&amp;quot;drop-zone--dragover&amp;quot;);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  [&amp;quot;dragleave&amp;quot;, &amp;quot;dragend&amp;quot;].forEach(function (type) {&lt;br /&gt;
    dropZone.addEventListener(type, function () {&lt;br /&gt;
      dropZone.classList.remove(&amp;quot;drop-zone--dragover&amp;quot;);&lt;br /&gt;
    });&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  dropZone.addEventListener(&amp;quot;drop&amp;quot;, function (event) {&lt;br /&gt;
    event.preventDefault();&lt;br /&gt;
    uploadCharacter(&lt;br /&gt;
      event.dataTransfer.files,&lt;br /&gt;
      characters,&lt;br /&gt;
      characterTemplate,&lt;br /&gt;
      charactersContainer,&lt;br /&gt;
      battle&lt;br /&gt;
    );&lt;br /&gt;
    dropZone.classList.remove(&amp;quot;drop-zone--dragover&amp;quot;);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  characterInput.addEventListener(&amp;quot;change&amp;quot;, function (event) {&lt;br /&gt;
    uploadCharacter(&lt;br /&gt;
      event.target.files,&lt;br /&gt;
      characters,&lt;br /&gt;
      characterTemplate,&lt;br /&gt;
      charactersContainer,&lt;br /&gt;
      battle&lt;br /&gt;
    );&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function deleteCharacter(characters, pseudo, element, battle) {&lt;br /&gt;
  delete characters.savedCharacters[pseudo];&lt;br /&gt;
  element.remove();&lt;br /&gt;
&lt;br /&gt;
  updateSavedCharacters(characters.savedCharacters);&lt;br /&gt;
  removeBattleChoice(battle.battleChoice, pseudo, &amp;quot;character&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (&lt;br /&gt;
    !Object.keys(characters.savedCharacters).length ||&lt;br /&gt;
    characters.characterCreation.name.value === pseudo&lt;br /&gt;
  ) {&lt;br /&gt;
    saveButtonGreen(characters.saveButton);&lt;br /&gt;
    characters.unsavedChanges = false;&lt;br /&gt;
    hideElement(characters.characterCreation);&lt;br /&gt;
    showElement(characters.characterCreation.previousElementSibling);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function deleteMonster(characters, battle, monsterVnum) {&lt;br /&gt;
  var monsterElements = characters.monsterElements;&lt;br /&gt;
  var monsterType = characters.savedMonsters[monsterVnum].category;&lt;br /&gt;
&lt;br /&gt;
  if (monsterElements.hasOwnProperty(monsterVnum)) {&lt;br /&gt;
    monsterElements[monsterVnum].remove();&lt;br /&gt;
    delete monsterElements[monsterVnum];&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  delete characters.savedMonsters[monsterVnum];&lt;br /&gt;
&lt;br /&gt;
  updateSavedMonsters(characters.savedMonsters);&lt;br /&gt;
  removeBattleChoice(battle.battleChoice, monsterVnum, monsterType);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleStyle(characters, selectedElement) {&lt;br /&gt;
  var currentCharacter = characters.currentCharacter;&lt;br /&gt;
&lt;br /&gt;
  if (currentCharacter) {&lt;br /&gt;
    currentCharacter.classList.remove(&amp;quot;selected-character&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  selectedElement.classList.add(&amp;quot;selected-character&amp;quot;);&lt;br /&gt;
  characters.currentCharacter = selectedElement;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateForm(&lt;br /&gt;
  formData,&lt;br /&gt;
  characterCreation,&lt;br /&gt;
  characters,&lt;br /&gt;
  selectedElement,&lt;br /&gt;
  battle&lt;br /&gt;
) {&lt;br /&gt;
  saveButtonGreen(characters.saveButton);&lt;br /&gt;
  hideElement(characterCreation.previousElementSibling);&lt;br /&gt;
  showElement(characterCreation);&lt;br /&gt;
  handleStyle(characters, selectedElement);&lt;br /&gt;
&lt;br /&gt;
  characterCreation.reset();&lt;br /&gt;
&lt;br /&gt;
  for (var [name, value] of Object.entries(formData)) {&lt;br /&gt;
    var formElement = characterCreation[name];&lt;br /&gt;
&lt;br /&gt;
    if (!formElement) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (formElement.type === &amp;quot;checkbox&amp;quot;) {&lt;br /&gt;
      if (isChecked(value)) {&lt;br /&gt;
        formElement.checked = true;&lt;br /&gt;
      }&lt;br /&gt;
    } else {&lt;br /&gt;
      formElement.value = value;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  var selectedRace = characterCreation.race.value;&lt;br /&gt;
  var classChoice = characterCreation.class;&lt;br /&gt;
  var weaponElement = characterCreation.weapon;&lt;br /&gt;
&lt;br /&gt;
  filterClass(selectedRace, classChoice, true);&lt;br /&gt;
  filterWeapon(&lt;br /&gt;
    selectedRace,&lt;br /&gt;
    weaponElement,&lt;br /&gt;
    characters.weaponCategory,&lt;br /&gt;
    battle.constants.allowedWeaponsPerRace,&lt;br /&gt;
    true&lt;br /&gt;
  );&lt;br /&gt;
  handlePolymorphDisplay(&lt;br /&gt;
    characters.polymorphDisplay,&lt;br /&gt;
    characterCreation.polymorphMonster.value,&lt;br /&gt;
    characterCreation.polymorphMonsterImage.value&lt;br /&gt;
  );&lt;br /&gt;
  handleWeaponDisplay(&lt;br /&gt;
    characters.weaponCategory,&lt;br /&gt;
    characters.weaponDisplay,&lt;br /&gt;
    weaponElement.value&lt;br /&gt;
  );&lt;br /&gt;
  filterUpgrade(&lt;br /&gt;
    characterCreation.weaponUpgrade,&lt;br /&gt;
    weaponElement.value,&lt;br /&gt;
    characters.randomAttackValue,&lt;br /&gt;
    characters.randomMagicAttackValue&lt;br /&gt;
  );&lt;br /&gt;
  filterCheckbox(characterCreation.isPolymorph, characters.polymorphCreation);&lt;br /&gt;
  filterCheckbox(characterCreation.lowRank, characters.rankSelection);&lt;br /&gt;
  filterCheckbox(characterCreation.onYohara, characters.yoharaCreation);&lt;br /&gt;
  filterCheckbox(characterCreation.isBlessed, characters.blessingCreation);&lt;br /&gt;
  filterCheckbox(characterCreation.isMarried, characters.marriageCreation);&lt;br /&gt;
  filterCheckbox(&lt;br /&gt;
    characterCreation.useBonusVariation,&lt;br /&gt;
    characters.bonusVariation.container&lt;br /&gt;
  );&lt;br /&gt;
  filterSkills(classChoice.value, characters.skillElementsToFilter);&lt;br /&gt;
  handleBonusVariationUpdate(characterCreation, characters.bonusVariation);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleClickOnCharacter(&lt;br /&gt;
  spanInput,&lt;br /&gt;
  target,&lt;br /&gt;
  characters,&lt;br /&gt;
  characterElement,&lt;br /&gt;
  battle,&lt;br /&gt;
  edition&lt;br /&gt;
) {&lt;br /&gt;
  var displayedPseudo = characters.characterCreation.name.value;&lt;br /&gt;
  var pseudo = spanInput.dataset.name;&lt;br /&gt;
&lt;br /&gt;
  if (edition) {&lt;br /&gt;
    if (!characters.unsavedChanges) {&lt;br /&gt;
      updateForm(&lt;br /&gt;
        characters.savedCharacters[pseudo],&lt;br /&gt;
        characters.characterCreation,&lt;br /&gt;
        characters,&lt;br /&gt;
        characterElement,&lt;br /&gt;
        battle&lt;br /&gt;
      );&lt;br /&gt;
    } else if (displayedPseudo === pseudo) {&lt;br /&gt;
      // pass&lt;br /&gt;
    } else {&lt;br /&gt;
      var result = confirm(&lt;br /&gt;
        &amp;quot;Voulez-vous continuer ? Les dernières modifications ne seront pas sauvegardées.&amp;quot;&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      if (result) {&lt;br /&gt;
        updateForm(&lt;br /&gt;
          characters.savedCharacters[pseudo],&lt;br /&gt;
          characters.characterCreation,&lt;br /&gt;
          characters,&lt;br /&gt;
          characterElement,&lt;br /&gt;
          battle&lt;br /&gt;
        );&lt;br /&gt;
        characters.unsavedChanges = false;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    if (target.tagName === &amp;quot;path&amp;quot;) {&lt;br /&gt;
      target = target.parentElement;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    switch (target.dataset.icon) {&lt;br /&gt;
      case &amp;quot;duplicate&amp;quot;:&lt;br /&gt;
        if (!characters.unsavedChanges) {&lt;br /&gt;
          addNewCharacter(&lt;br /&gt;
            characters,&lt;br /&gt;
            characters.newCharacterTemplate,&lt;br /&gt;
            characters.charactersContainer,&lt;br /&gt;
            battle,&lt;br /&gt;
            pseudo&lt;br /&gt;
          );&lt;br /&gt;
        } else {&lt;br /&gt;
          var result = confirm(&lt;br /&gt;
            &amp;quot;Voulez-vous continuer ? Les dernières modifications ne seront pas sauvegardées.&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
&lt;br /&gt;
          if (result) {&lt;br /&gt;
            addNewCharacter(&lt;br /&gt;
              characters,&lt;br /&gt;
              characters.newCharacterTemplate,&lt;br /&gt;
              characters.charactersContainer,&lt;br /&gt;
              battle,&lt;br /&gt;
              pseudo&lt;br /&gt;
            );&lt;br /&gt;
            saveButtonGreen(characters.saveButton);&lt;br /&gt;
            characters.unsavedChanges = false;&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
        break;&lt;br /&gt;
&lt;br /&gt;
      case &amp;quot;download&amp;quot;:&lt;br /&gt;
        var character = characters.savedCharacters[pseudo];&lt;br /&gt;
        downloadData(&lt;br /&gt;
          JSON.stringify(character),&lt;br /&gt;
          &amp;quot;text/plain&amp;quot;,&lt;br /&gt;
          character.name + &amp;quot;.txt&amp;quot;&lt;br /&gt;
        );&lt;br /&gt;
        break;&lt;br /&gt;
&lt;br /&gt;
      case &amp;quot;delete&amp;quot;:&lt;br /&gt;
        var result = confirm(&lt;br /&gt;
          &amp;quot;Voulez-vous vraiment supprimer définitivement le personnage &amp;quot; +&lt;br /&gt;
            pseudo +&lt;br /&gt;
            &amp;quot; ?&amp;quot;&lt;br /&gt;
        );&lt;br /&gt;
        if (result) {&lt;br /&gt;
          deleteCharacter(characters, pseudo, characterElement, battle);&lt;br /&gt;
        }&lt;br /&gt;
        break;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleNewCharacter(&lt;br /&gt;
  characters,&lt;br /&gt;
  characterTemplate,&lt;br /&gt;
  charactersContainer,&lt;br /&gt;
  battle,&lt;br /&gt;
  pseudo&lt;br /&gt;
) {&lt;br /&gt;
  var newCharacterTemplate = characterTemplate.cloneNode(true);&lt;br /&gt;
  var spanInput = newCharacterTemplate.querySelector(&amp;quot;span.input&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  newCharacterTemplate.setAttribute(&amp;quot;tabindex&amp;quot;, &amp;quot;0&amp;quot;);&lt;br /&gt;
  charactersContainer.appendChild(newCharacterTemplate);&lt;br /&gt;
&lt;br /&gt;
  if (pseudo) {&lt;br /&gt;
    spanInput.textContent = pseudo;&lt;br /&gt;
    spanInput.setAttribute(&amp;quot;data-name&amp;quot;, pseudo);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  newCharacterTemplate.addEventListener(&amp;quot;click&amp;quot;, function (event) {&lt;br /&gt;
    var target = event.target;&lt;br /&gt;
&lt;br /&gt;
    if (target.tagName === &amp;quot;path&amp;quot; || target.tagName === &amp;quot;svg&amp;quot;) {&lt;br /&gt;
      handleClickOnCharacter(&lt;br /&gt;
        spanInput,&lt;br /&gt;
        target,&lt;br /&gt;
        characters,&lt;br /&gt;
        newCharacterTemplate,&lt;br /&gt;
        battle&lt;br /&gt;
      );&lt;br /&gt;
    } else {&lt;br /&gt;
      handleClickOnCharacter(&lt;br /&gt;
        spanInput,&lt;br /&gt;
        null,&lt;br /&gt;
        characters,&lt;br /&gt;
        newCharacterTemplate,&lt;br /&gt;
        battle,&lt;br /&gt;
        true&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  newCharacterTemplate.addEventListener(&amp;quot;keydown&amp;quot;, function (event) {&lt;br /&gt;
    if (event.keyCode === 13) {&lt;br /&gt;
      event.target.click();&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  return [newCharacterTemplate, spanInput];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function validPseudo(pseudo) {&lt;br /&gt;
  var newPseudo = pseudoFormat(pseudo);&lt;br /&gt;
&lt;br /&gt;
  if (!newPseudo) {&lt;br /&gt;
    return &amp;quot;Pseudo&amp;quot;;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return newPseudo;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addNewCharacter(&lt;br /&gt;
  characters,&lt;br /&gt;
  characterTemplate,&lt;br /&gt;
  charactersContainer,&lt;br /&gt;
  battle,&lt;br /&gt;
  pseudoToDuplicate&lt;br /&gt;
) {&lt;br /&gt;
  function editAndSetCharacterPseudoInput(selectedCharacter, spanInput) {&lt;br /&gt;
    var maxPseudoLength = 20;&lt;br /&gt;
&lt;br /&gt;
    var selection = window.getSelection();&lt;br /&gt;
    var range = document.createRange();&lt;br /&gt;
&lt;br /&gt;
    if (pseudoToDuplicate) {&lt;br /&gt;
      spanInput.textContent = pseudoToDuplicate;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    spanInput.contentEditable = true;&lt;br /&gt;
    spanInput.focus();&lt;br /&gt;
    range.selectNodeContents(spanInput);&lt;br /&gt;
    selection.removeAllRanges();&lt;br /&gt;
    selection.addRange(range);&lt;br /&gt;
&lt;br /&gt;
    function pseudoValidation() {&lt;br /&gt;
      var characterPseudo = validPseudo(spanInput.textContent);&lt;br /&gt;
      var characterDataObject = { name: characterPseudo };&lt;br /&gt;
&lt;br /&gt;
      if (pseudoToDuplicate) {&lt;br /&gt;
        characterDataObject = copyObject(&lt;br /&gt;
          characters.savedCharacters[pseudoToDuplicate]&lt;br /&gt;
        );&lt;br /&gt;
        characterDataObject.name = characterPseudo;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      [characterDataObject, characterPseudo] = addUniquePseudo(&lt;br /&gt;
        characterDataObject,&lt;br /&gt;
        Object.keys(characters.savedCharacters)&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      selection.removeAllRanges();&lt;br /&gt;
      spanInput.contentEditable = false;&lt;br /&gt;
      spanInput.textContent = characterPseudo;&lt;br /&gt;
      spanInput.setAttribute(&amp;quot;data-name&amp;quot;, characterPseudo);&lt;br /&gt;
&lt;br /&gt;
      updateForm(&lt;br /&gt;
        characterDataObject,&lt;br /&gt;
        characters.characterCreation,&lt;br /&gt;
        characters,&lt;br /&gt;
        selectedCharacter,&lt;br /&gt;
        battle&lt;br /&gt;
      );&lt;br /&gt;
      saveCharacter(&lt;br /&gt;
        characters.savedCharacters,&lt;br /&gt;
        characters.characterCreation,&lt;br /&gt;
        battle,&lt;br /&gt;
        true&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handleMaxLength(event) {&lt;br /&gt;
      if (spanInput.textContent.length &amp;gt; maxPseudoLength) {&lt;br /&gt;
        spanInput.textContent = spanInput.textContent.slice(0, maxPseudoLength);&lt;br /&gt;
        range.setStart(spanInput.childNodes[0], maxPseudoLength);&lt;br /&gt;
        selection.removeAllRanges();&lt;br /&gt;
        selection.addRange(range);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handleBlur() {&lt;br /&gt;
      spanInput.removeEventListener(&amp;quot;blur&amp;quot;, handleBlur);&lt;br /&gt;
      spanInput.removeEventListener(&amp;quot;input&amp;quot;, handleMaxLength);&lt;br /&gt;
      pseudoValidation();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handleKeyDown(event) {&lt;br /&gt;
      if (event.key === &amp;quot;Enter&amp;quot;) {&lt;br /&gt;
        event.preventDefault();&lt;br /&gt;
&lt;br /&gt;
        spanInput.removeEventListener(&amp;quot;keydown&amp;quot;, handleKeyDown);&lt;br /&gt;
        spanInput.removeEventListener(&amp;quot;blur&amp;quot;, handleBlur);&lt;br /&gt;
        spanInput.removeEventListener(&amp;quot;input&amp;quot;, handleMaxLength);&lt;br /&gt;
&lt;br /&gt;
        pseudoValidation();&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    spanInput.addEventListener(&amp;quot;input&amp;quot;, handleMaxLength);&lt;br /&gt;
    spanInput.addEventListener(&amp;quot;keydown&amp;quot;, handleKeyDown);&lt;br /&gt;
    spanInput.addEventListener(&amp;quot;blur&amp;quot;, handleBlur);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  hideElement(characters.characterCreation);&lt;br /&gt;
  var [selectedCharacter, spanInput] = handleNewCharacter(&lt;br /&gt;
    characters,&lt;br /&gt;
    characterTemplate,&lt;br /&gt;
    charactersContainer,&lt;br /&gt;
    battle&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  editAndSetCharacterPseudoInput(selectedCharacter, spanInput);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleFocus() {&lt;br /&gt;
  var tooltipLinks = document.querySelectorAll(&amp;quot;div.tooltip a&amp;quot;);&lt;br /&gt;
  tooltipLinks.forEach(function (link) {&lt;br /&gt;
    link.setAttribute(&amp;quot;tabindex&amp;quot;, -1);&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function resetBonusVariation(bonusVariation) {&lt;br /&gt;
  function resetInput(input) {&lt;br /&gt;
    input.removeAttribute(&amp;quot;min&amp;quot;);&lt;br /&gt;
    input.removeAttribute(&amp;quot;max&amp;quot;);&lt;br /&gt;
    input.defaultValue = 0;&lt;br /&gt;
    input.value = input.defaultValue;&lt;br /&gt;
  }&lt;br /&gt;
  var { minValue, maxValue, checkbox, container, disabledText, selectedText } =&lt;br /&gt;
    bonusVariation;&lt;br /&gt;
&lt;br /&gt;
  resetInput(minValue);&lt;br /&gt;
  resetInput(maxValue);&lt;br /&gt;
  showElement(disabledText);&lt;br /&gt;
  hideElement(selectedText);&lt;br /&gt;
  hideElement(container);&lt;br /&gt;
  checkbox.checked = false;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleBonusVariationUpdate(&lt;br /&gt;
  characterCreation,&lt;br /&gt;
  bonusVariation,&lt;br /&gt;
  resetSkill&lt;br /&gt;
) {&lt;br /&gt;
  var selectedBonus = characterCreation.bonusVariation.value;&lt;br /&gt;
  var displayName = characterCreation.bonusVariationName.value;&lt;br /&gt;
&lt;br /&gt;
  if (&lt;br /&gt;
    resetSkill &amp;amp;&amp;amp;&lt;br /&gt;
    (selectedBonus.startsWith(&amp;quot;attackSkill&amp;quot;) ||&lt;br /&gt;
      selectedBonus.startsWith(&amp;quot;horseSkill&amp;quot;) ||&lt;br /&gt;
      selectedBonus.startsWith(&amp;quot;skillBonus&amp;quot;))&lt;br /&gt;
  ) {&lt;br /&gt;
    resetBonusVariation(bonusVariation);&lt;br /&gt;
    return;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (&lt;br /&gt;
    characterCreation.hasOwnProperty(selectedBonus) &amp;amp;&amp;amp;&lt;br /&gt;
    selectedBonus != 0 &amp;amp;&amp;amp;&lt;br /&gt;
    displayName != 0&lt;br /&gt;
  ) {&lt;br /&gt;
    handleBonusVariation(&lt;br /&gt;
      characterCreation[selectedBonus],&lt;br /&gt;
      bonusVariation,&lt;br /&gt;
      displayName&lt;br /&gt;
    );&lt;br /&gt;
  } else {&lt;br /&gt;
    resetBonusVariation(bonusVariation);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getTargetContent(targetParent, targetName, isSkill) {&lt;br /&gt;
  var targetContent = &amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  if (targetParent.children.length &amp;lt;= 1) {&lt;br /&gt;
    targetContent = targetParent.textContent;&lt;br /&gt;
  } else if (targetName === &amp;quot;weaponUpgrade&amp;quot;) {&lt;br /&gt;
    targetContent = targetParent.children[1].textContent;&lt;br /&gt;
  } else if (targetName === &amp;quot;level&amp;quot;) {&lt;br /&gt;
    targetContent = targetParent.textContent.replace(&amp;quot;Lv&amp;quot;, &amp;quot;&amp;quot;).trim();&lt;br /&gt;
  } else if (isSkill) {&lt;br /&gt;
    var container = targetParent.children[1];&lt;br /&gt;
&lt;br /&gt;
    for (var index = 0; index &amp;lt; container.children.length; index++) {&lt;br /&gt;
      var element = container.children[index];&lt;br /&gt;
&lt;br /&gt;
      if (element.checkVisibility()) {&lt;br /&gt;
        targetContent += element.textContent;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    for (var index = 1; index &amp;lt; targetParent.children.length; index++) {&lt;br /&gt;
      var element = targetParent.children[index];&lt;br /&gt;
&lt;br /&gt;
      if (element.checkVisibility()) {&lt;br /&gt;
        targetContent += element.textContent;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return targetContent.trim();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleBonusVariation(target, bonusVariation, displayName) {&lt;br /&gt;
  var {&lt;br /&gt;
    minValue,&lt;br /&gt;
    maxValue,&lt;br /&gt;
    checkbox,&lt;br /&gt;
    container,&lt;br /&gt;
    disabledText,&lt;br /&gt;
    selectedText,&lt;br /&gt;
    displaySpan,&lt;br /&gt;
  } = bonusVariation;&lt;br /&gt;
&lt;br /&gt;
  var {&lt;br /&gt;
    min: targetMin,&lt;br /&gt;
    max: targetMax,&lt;br /&gt;
    name: targetName,&lt;br /&gt;
    value: targetValue,&lt;br /&gt;
    parentElement: targetParent,&lt;br /&gt;
    tagName,&lt;br /&gt;
  } = target;&lt;br /&gt;
&lt;br /&gt;
  targetMin = Number(targetMin);&lt;br /&gt;
  targetMax = Number(targetMax);&lt;br /&gt;
  targetValue = Number(targetValue);&lt;br /&gt;
&lt;br /&gt;
  var isSkill = tagName === &amp;quot;SELECT&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  if (isSkill) {&lt;br /&gt;
    var options = target.options;&lt;br /&gt;
&lt;br /&gt;
    targetMin = options[0].value;&lt;br /&gt;
    targetMax = options[options.length - 1].value;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  minValue.min = targetMin;&lt;br /&gt;
  minValue.max = targetMax;&lt;br /&gt;
  minValue.defaultValue = targetMin;&lt;br /&gt;
&lt;br /&gt;
  maxValue.min = targetMin;&lt;br /&gt;
  maxValue.max = targetMax;&lt;br /&gt;
  maxValue.defaultValue = targetMin;&lt;br /&gt;
&lt;br /&gt;
  hideElement(disabledText);&lt;br /&gt;
  showElement(selectedText);&lt;br /&gt;
&lt;br /&gt;
  if (displayName) {&lt;br /&gt;
    minValue.value = Math.min(Math.max(minValue.value, targetMin), targetMax);&lt;br /&gt;
    maxValue.value = Math.max(Math.min(maxValue.value, targetMax), targetMin);&lt;br /&gt;
&lt;br /&gt;
    displaySpan.textContent = displayName;&lt;br /&gt;
  } else {&lt;br /&gt;
    var { input, inputName, tabButton } = bonusVariation;&lt;br /&gt;
    var targetContent = getTargetContent(targetParent, targetName, isSkill);&lt;br /&gt;
&lt;br /&gt;
    input.value = targetName;&lt;br /&gt;
    inputName.value = targetContent;&lt;br /&gt;
    displaySpan.textContent = targetContent;&lt;br /&gt;
&lt;br /&gt;
    minValue.value = Math.max(targetValue - 10, targetMin);&lt;br /&gt;
    maxValue.value = Math.min(targetValue + 10, targetMax);&lt;br /&gt;
&lt;br /&gt;
    showElement(container);&lt;br /&gt;
    checkbox.checked = true;&lt;br /&gt;
&lt;br /&gt;
    tabButton.click();&lt;br /&gt;
    tabButton.scrollIntoView(true);&lt;br /&gt;
&lt;br /&gt;
    input.dispatchEvent(newChangeEvent());&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function characterManagement(characters, battle) {&lt;br /&gt;
  var {&lt;br /&gt;
    newCharacterTemplate: characterTemplate,&lt;br /&gt;
    charactersContainer,&lt;br /&gt;
    addNewCharacterButton,&lt;br /&gt;
    saveButton,&lt;br /&gt;
    characterCreation,&lt;br /&gt;
    bonusVariation,&lt;br /&gt;
  } = characters;&lt;br /&gt;
&lt;br /&gt;
  Object.keys(characters.savedCharacters).forEach(function (pseudo) {&lt;br /&gt;
    handleNewCharacter(&lt;br /&gt;
      characters,&lt;br /&gt;
      characterTemplate,&lt;br /&gt;
      charactersContainer,&lt;br /&gt;
      battle,&lt;br /&gt;
      pseudo&lt;br /&gt;
    );&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  addNewCharacterButton.addEventListener(&amp;quot;click&amp;quot;, function (event) {&lt;br /&gt;
    if (!characters.unsavedChanges) {&lt;br /&gt;
      addNewCharacter(&lt;br /&gt;
        characters,&lt;br /&gt;
        characterTemplate,&lt;br /&gt;
        charactersContainer,&lt;br /&gt;
        battle&lt;br /&gt;
      );&lt;br /&gt;
    } else {&lt;br /&gt;
      var result = confirm(&lt;br /&gt;
        &amp;quot;Voulez-vous continuer ? Les dernières modifications ne seront pas sauvegardées.&amp;quot;&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      if (result) {&lt;br /&gt;
        addNewCharacter(&lt;br /&gt;
          characters,&lt;br /&gt;
          characterTemplate,&lt;br /&gt;
          charactersContainer,&lt;br /&gt;
          battle&lt;br /&gt;
        );&lt;br /&gt;
        saveButtonGreen(saveButton);&lt;br /&gt;
        characters.unsavedChanges = false;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  handleUploadCharacter(&lt;br /&gt;
    characters,&lt;br /&gt;
    characterTemplate,&lt;br /&gt;
    charactersContainer,&lt;br /&gt;
    battle&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  function handleLongPress(target) {&lt;br /&gt;
    if (target.tagName !== &amp;quot;INPUT&amp;quot; &amp;amp;&amp;amp; target.tagName !== &amp;quot;SELECT&amp;quot;) {&lt;br /&gt;
      target = target.querySelector(&amp;quot;input&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      !target ||&lt;br /&gt;
      (target.type !== &amp;quot;number&amp;quot; &amp;amp;&amp;amp;&lt;br /&gt;
        !target.classList.contains(&amp;quot;skill-select&amp;quot;) &amp;amp;&amp;amp;&lt;br /&gt;
        target.name !== &amp;quot;weaponUpgrade&amp;quot;) ||&lt;br /&gt;
      target.classList.contains(&amp;quot;disabled-variation&amp;quot;)&lt;br /&gt;
    ) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    handleBonusVariation(target, bonusVariation, null);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;click&amp;quot;, function (event) {&lt;br /&gt;
    if (event.shiftKey || event.ctrlKey) {&lt;br /&gt;
      handleLongPress(event.target);&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  var longPressTimer;&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;touchstart&amp;quot;, function (event) {&lt;br /&gt;
    longPressTimer = setTimeout(function () {&lt;br /&gt;
      handleLongPress(event.target);&lt;br /&gt;
    }, 800);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;touchend&amp;quot;, function () {&lt;br /&gt;
    clearTimeout(longPressTimer);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;touchmove&amp;quot;, function () {&lt;br /&gt;
    clearTimeout(longPressTimer);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  filterForm(characters, battle);&lt;br /&gt;
  characterCreationListener(characters, battle);&lt;br /&gt;
  handleFocus();&lt;br /&gt;
&lt;br /&gt;
  window.addEventListener(&amp;quot;beforeunload&amp;quot;, function (event) {&lt;br /&gt;
    if (characters.unsavedChanges) {&lt;br /&gt;
      event.preventDefault();&lt;br /&gt;
      return &amp;quot;&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addMonsterElement(characters, battle, monsterVnum, iframeInfo) {&lt;br /&gt;
  var { monsterTemplate, monstersContainer } = characters;&lt;br /&gt;
  var monsterElement = monsterTemplate.cloneNode(true);&lt;br /&gt;
  var spanInput = monsterElement.querySelector(&amp;quot;span.input&amp;quot;);&lt;br /&gt;
  var deleteSvg = monsterElement.querySelector(&amp;quot;svg&amp;quot;);&lt;br /&gt;
  var monsterName = getMonsterName(monsterVnum);&lt;br /&gt;
  var link = createWikiLink(monsterName);&lt;br /&gt;
&lt;br /&gt;
  monsterElement.setAttribute(&amp;quot;tabindex&amp;quot;, &amp;quot;0&amp;quot;);&lt;br /&gt;
  spanInput.appendChild(link);&lt;br /&gt;
  monstersContainer.appendChild(monsterElement);&lt;br /&gt;
  characters.monsterElements[monsterVnum] = monsterElement;&lt;br /&gt;
&lt;br /&gt;
  deleteSvg.addEventListener(&amp;quot;click&amp;quot;, function () {&lt;br /&gt;
    var monster = characters.savedMonsters[monsterVnum];&lt;br /&gt;
    iframeInfo[monster.category].shouldBeUpdated = true;&lt;br /&gt;
&lt;br /&gt;
    deleteMonster(characters, battle, monsterVnum);&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addNewMonster(&lt;br /&gt;
  characters,&lt;br /&gt;
  battle,&lt;br /&gt;
  monsterVnum,&lt;br /&gt;
  monsterImage,&lt;br /&gt;
  iframeInfo,&lt;br /&gt;
  category&lt;br /&gt;
) {&lt;br /&gt;
  if (isValueInArray(monsterVnum, Object.keys(characters.savedMonsters)))&lt;br /&gt;
    return;&lt;br /&gt;
&lt;br /&gt;
  var newMonster = {&lt;br /&gt;
    image: monsterImage,&lt;br /&gt;
    category: category,&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  characters.savedMonsters[monsterVnum] = newMonster;&lt;br /&gt;
&lt;br /&gt;
  addMonsterElement(characters, battle, monsterVnum, iframeInfo);&lt;br /&gt;
  updateSavedMonsters(characters.savedMonsters);&lt;br /&gt;
  addBattleChoice(battle.battleChoice, monsterVnum, newMonster, true);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addButtonsToCards(characters, iframeDoc, iframeInfo, category) {&lt;br /&gt;
  var buttonTemplates = characters.monsterButtonTemplates.children[0];&lt;br /&gt;
  var cardToEdit = iframeDoc.getElementById(&amp;quot;cards-container&amp;quot;).children;&lt;br /&gt;
  var { nameToVnum } = iframeInfo;&lt;br /&gt;
  var vnumToButtons = iframeInfo[category].vnumToButtons;&lt;br /&gt;
&lt;br /&gt;
  for (var cardIndex = 0; cardIndex &amp;lt; cardToEdit.length; cardIndex++) {&lt;br /&gt;
    var card = cardToEdit[cardIndex];&lt;br /&gt;
    var cardName = card.querySelector(&amp;quot;[data-name]&amp;quot;).firstChild.title;&lt;br /&gt;
    var buttonTemplatesClone = buttonTemplates.cloneNode(true);&lt;br /&gt;
&lt;br /&gt;
    cardName = cardName.replace(/\s/g, &amp;quot; &amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (!nameToVnum.hasOwnProperty(cardName)) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var monsterVnum = nameToVnum[cardName];&lt;br /&gt;
&lt;br /&gt;
    buttonTemplatesClone.dataset.monsterId = monsterVnum;&lt;br /&gt;
    card.lastElementChild.appendChild(buttonTemplatesClone);&lt;br /&gt;
    vnumToButtons[monsterVnum] = buttonTemplatesClone.children;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateiFrameButtons(characters, iframeInfo, category) {&lt;br /&gt;
  var addedMonsters = Object.keys(characters.savedMonsters);&lt;br /&gt;
  var { currentiFrameIsMonster } = iframeInfo;&lt;br /&gt;
  var vnumToButtons = iframeInfo[category].vnumToButtons;&lt;br /&gt;
  var isPolymorphModal = category === &amp;quot;monster&amp;quot; &amp;amp;&amp;amp; !currentiFrameIsMonster;&lt;br /&gt;
&lt;br /&gt;
  for (var monsterVnum in vnumToButtons) {&lt;br /&gt;
    var [addButton, deleteButton, selectButton] = vnumToButtons[monsterVnum];&lt;br /&gt;
&lt;br /&gt;
    if (isPolymorphModal) {&lt;br /&gt;
      hideElement(addButton);&lt;br /&gt;
      hideElement(deleteButton);&lt;br /&gt;
      showElement(selectButton);&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isValueInArray(monsterVnum, addedMonsters)) {&lt;br /&gt;
      hideElement(addButton);&lt;br /&gt;
      showElement(deleteButton);&lt;br /&gt;
      hideElement(selectButton);&lt;br /&gt;
    } else {&lt;br /&gt;
      showElement(addButton);&lt;br /&gt;
      hideElement(deleteButton);&lt;br /&gt;
      hideElement(selectButton);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  iframeInfo.lastiFrameIsMonster = currentiFrameIsMonster;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getMonsterImage(buttonsContainer) {&lt;br /&gt;
  var elder = buttonsContainer.parentElement.firstElementChild;&lt;br /&gt;
  var image = elder.querySelector(&amp;quot;img&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (image) {&lt;br /&gt;
    return image.getAttribute(&amp;quot;src&amp;quot;) || &amp;quot;&amp;quot;;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return &amp;quot;&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleiFrame(iframeInfo, category) {&lt;br /&gt;
  var { characters, battle } = iframeInfo;&lt;br /&gt;
  var iframeInfoCategory = iframeInfo[category];&lt;br /&gt;
  var { iframe, pageName, vnumToButtons } = iframeInfoCategory;&lt;br /&gt;
  var loadingAnimation = iframeInfoCategory.iframe.previousElementSibling;&lt;br /&gt;
&lt;br /&gt;
  iframe.src = mw.util.getUrl(pageName);&lt;br /&gt;
&lt;br /&gt;
  iframe.addEventListener(&amp;quot;load&amp;quot;, function () {&lt;br /&gt;
    var iframeDoc = this.contentDocument || this.contentWindow.document;&lt;br /&gt;
    var iframeBody = iframeDoc.body;&lt;br /&gt;
    var content = iframeDoc.getElementById(&amp;quot;show-after-loading&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    iframeBody.firstElementChild.replaceWith(content);&lt;br /&gt;
&lt;br /&gt;
    iframeBody.style.background = &amp;quot;transparent&amp;quot;;&lt;br /&gt;
    iframeBody.style.paddingRight = &amp;quot;10px&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    addButtonsToCards(characters, iframeDoc, iframeInfo, category);&lt;br /&gt;
    updateiFrameButtons(characters, iframeInfo, category);&lt;br /&gt;
&lt;br /&gt;
    iframeInfoCategory.loadIsFinished = true;&lt;br /&gt;
&lt;br /&gt;
    hideElement(loadingAnimation);&lt;br /&gt;
    showElement(iframe);&lt;br /&gt;
&lt;br /&gt;
    iframeDoc.addEventListener(&amp;quot;click&amp;quot;, handleButtonClick);&lt;br /&gt;
&lt;br /&gt;
    function handleButtonClick(event) {&lt;br /&gt;
      var target = event.target;&lt;br /&gt;
      var link = target.closest(&amp;quot;a&amp;quot;);&lt;br /&gt;
      var buttonsContainer = target.closest(&amp;quot;.handle-monster&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
      if (link) {&lt;br /&gt;
        event.preventDefault();&lt;br /&gt;
        window.open(link.href, &amp;quot;_blank&amp;quot;);&lt;br /&gt;
      } else if (buttonsContainer) {&lt;br /&gt;
        var { monsterId: monsterVnum } = buttonsContainer.dataset;&lt;br /&gt;
&lt;br /&gt;
        // polymorph iframe&lt;br /&gt;
        if (category === &amp;quot;monster&amp;quot; &amp;amp;&amp;amp; !iframeInfo.currentiFrameIsMonster) {&lt;br /&gt;
          var monsterImage = getMonsterImage(buttonsContainer);&lt;br /&gt;
          changePolymorphValues(&lt;br /&gt;
            characters.characterCreation,&lt;br /&gt;
            monsterVnum,&lt;br /&gt;
            monsterImage&lt;br /&gt;
          );&lt;br /&gt;
          handlePolymorphDisplay(&lt;br /&gt;
            characters.polymorphDisplay,&lt;br /&gt;
            monsterVnum,&lt;br /&gt;
            monsterImage&lt;br /&gt;
          );&lt;br /&gt;
          iframe.dispatchEvent(newChangeEvent());&lt;br /&gt;
        } else {&lt;br /&gt;
          var addedMonsters = Object.keys(characters.savedMonsters);&lt;br /&gt;
          var [addButton, deleteButton] = vnumToButtons[monsterVnum];&lt;br /&gt;
&lt;br /&gt;
          if (isValueInArray(monsterVnum, addedMonsters)) {&lt;br /&gt;
            deleteMonster(characters, battle, monsterVnum);&lt;br /&gt;
            showElement(addButton);&lt;br /&gt;
            hideElement(deleteButton);&lt;br /&gt;
          } else {&lt;br /&gt;
            var monsterImage = getMonsterImage(buttonsContainer);&lt;br /&gt;
            addNewMonster(&lt;br /&gt;
              characters,&lt;br /&gt;
              battle,&lt;br /&gt;
              monsterVnum,&lt;br /&gt;
              monsterImage,&lt;br /&gt;
              iframeInfo,&lt;br /&gt;
              category&lt;br /&gt;
            );&lt;br /&gt;
            hideElement(addButton);&lt;br /&gt;
            showElement(deleteButton);&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getNameToVnumMapping() {&lt;br /&gt;
  var nameToVnum = {};&lt;br /&gt;
&lt;br /&gt;
  for (var monsterVnum in monsterData) {&lt;br /&gt;
    nameToVnum[monsterData[monsterVnum][monsterData[monsterVnum].length - 1]] =&lt;br /&gt;
      monsterVnum;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return nameToVnum;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function monsterManagement(characters, battle) {&lt;br /&gt;
  var { monsteriFrame, stoneiFrame } = characters;&lt;br /&gt;
  var monsterVnums = Object.keys(monsterData);&lt;br /&gt;
&lt;br /&gt;
  var iframeInfo = {&lt;br /&gt;
    lastiFrameIsMonster: false,&lt;br /&gt;
    currentiFrameIsMonster: false,&lt;br /&gt;
    characters: characters,&lt;br /&gt;
    battle: battle,&lt;br /&gt;
    nameToVnum: getNameToVnumMapping(),&lt;br /&gt;
    monster: {&lt;br /&gt;
      isLoaded: false,&lt;br /&gt;
      loadIsFinished: false,&lt;br /&gt;
      shouldBeUpdated: false,&lt;br /&gt;
      vnumToButtons: {},&lt;br /&gt;
      pageName: &amp;quot;Monstres&amp;quot;,&lt;br /&gt;
      iframe: monsteriFrame,&lt;br /&gt;
    },&lt;br /&gt;
    stone: {&lt;br /&gt;
      isLoaded: false,&lt;br /&gt;
      loadIsFinished: false,&lt;br /&gt;
      shouldBeUpdated: false,&lt;br /&gt;
      vnumToButtons: {},&lt;br /&gt;
      pageName: &amp;quot;Pierres Metin&amp;quot;,&lt;br /&gt;
      iframe: stoneiFrame,&lt;br /&gt;
    },&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  document.addEventListener(&amp;quot;modalOpen&amp;quot;, function (event) {&lt;br /&gt;
    var modalName = event.detail.name;&lt;br /&gt;
&lt;br /&gt;
    if (modalName === &amp;quot;monster&amp;quot; || modalName === &amp;quot;stone&amp;quot;) {&lt;br /&gt;
      handleModal(event.target, modalName);&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  function handleModal(target, modalName) {&lt;br /&gt;
    var iframeInfoCategory = iframeInfo[modalName];&lt;br /&gt;
&lt;br /&gt;
    if (modalName === &amp;quot;monster&amp;quot;) {&lt;br /&gt;
      var isMonsteriFrame = target.id === &amp;quot;add-new-monster&amp;quot;;&lt;br /&gt;
      iframeInfo.currentiFrameIsMonster = isMonsteriFrame;&lt;br /&gt;
&lt;br /&gt;
      if (&lt;br /&gt;
        iframeInfoCategory.loadIsFinished &amp;amp;&amp;amp;&lt;br /&gt;
        ((isMonsteriFrame &amp;amp;&amp;amp; !iframeInfo.lastiFrameIsMonster) ||&lt;br /&gt;
          (!isMonsteriFrame &amp;amp;&amp;amp; iframeInfo.lastiFrameIsMonster))&lt;br /&gt;
      ) {&lt;br /&gt;
        iframeInfoCategory.shouldBeUpdated = true;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!iframeInfoCategory.isLoaded) {&lt;br /&gt;
      handleiFrame(iframeInfo, modalName);&lt;br /&gt;
      iframeInfoCategory.isLoaded = true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      iframeInfoCategory.loadIsFinished &amp;amp;&amp;amp;&lt;br /&gt;
      iframeInfoCategory.shouldBeUpdated&lt;br /&gt;
    ) {&lt;br /&gt;
      updateiFrameButtons(characters, iframeInfo, modalName);&lt;br /&gt;
      iframeInfoCategory.shouldBeUpdated = false;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  Object.keys(characters.savedMonsters)&lt;br /&gt;
    .slice()&lt;br /&gt;
    .forEach(function (monsterVnum) {&lt;br /&gt;
      if (isValueInArray(monsterVnum, monsterVnums)) {&lt;br /&gt;
        addMonsterElement(characters, battle, monsterVnum, iframeInfo);&lt;br /&gt;
      } else {&lt;br /&gt;
        deleteMonster(characters, battle, monsterVnum);&lt;br /&gt;
      }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function hideAttackType(container, input, attackType) {&lt;br /&gt;
  hideElement(container);&lt;br /&gt;
&lt;br /&gt;
  if (input.checked) {&lt;br /&gt;
    var defaultInput = attackType.defaultInput;&lt;br /&gt;
&lt;br /&gt;
    input.checked = false;&lt;br /&gt;
    defaultInput.checked = true;&lt;br /&gt;
    defaultInput.dispatchEvent(newChangeEvent());&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterAttackTypeSelectionCharacter(attacker, attackType) {&lt;br /&gt;
  var attackerClass = attacker.class;&lt;br /&gt;
  var attackerIsNotPolymorph = !isPolymorph(attacker);&lt;br /&gt;
  var { elements: attackTypeElements } = attackType;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; attackTypeElements.length; index++) {&lt;br /&gt;
    var { container, input, inputClass, inputValue } =&lt;br /&gt;
      attackTypeElements[index];&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      attackerIsNotPolymorph &amp;amp;&amp;amp;&lt;br /&gt;
      attacker[inputValue] &amp;amp;&amp;amp;&lt;br /&gt;
      (attackerClass === inputClass ||&lt;br /&gt;
        (inputValue.startsWith(&amp;quot;horseSkill&amp;quot;) &amp;amp;&amp;amp;&lt;br /&gt;
          isRiding(attacker) &amp;amp;&amp;amp;&lt;br /&gt;
          (!inputClass || isValueInArray(attackerClass, inputClass))))&lt;br /&gt;
    ) {&lt;br /&gt;
      showElement(container);&lt;br /&gt;
    } else {&lt;br /&gt;
      hideAttackType(container, input, attackType);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterAttackTypeSelectionMonster(attackType) {&lt;br /&gt;
  var attackTypeElements = attackType.elements;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; attackTypeElements.length; index++) {&lt;br /&gt;
    var { container, input } = attackTypeElements[index];&lt;br /&gt;
    hideAttackType(container, input, attackType);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function removeBattleElement(battleChoice, nameOrVnum, category, type) {&lt;br /&gt;
  var elements = battleChoice[category][type].elements;&lt;br /&gt;
&lt;br /&gt;
  if (elements.hasOwnProperty(nameOrVnum)) {&lt;br /&gt;
    elements[nameOrVnum].container.remove();&lt;br /&gt;
    delete elements[nameOrVnum];&lt;br /&gt;
    battleChoice[category][type].count--;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function removeBattleChoice(battleChoice, nameOrVnum, type) {&lt;br /&gt;
  battleChoice.categories.forEach(function (category) {&lt;br /&gt;
    if (category === &amp;quot;attacker&amp;quot; &amp;amp;&amp;amp; type === &amp;quot;stone&amp;quot;) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
    var selected = battleChoice[category].selected;&lt;br /&gt;
&lt;br /&gt;
    if (selected) {&lt;br /&gt;
      var { type: selectedType, nameOrVnum: selectedNameOrVnum } =&lt;br /&gt;
        parseTypeAndName(selected);&lt;br /&gt;
&lt;br /&gt;
      if (nameOrVnum === selectedNameOrVnum &amp;amp;&amp;amp; type === selectedType) {&lt;br /&gt;
        resetBattleChoiceButton(battleChoice, category);&lt;br /&gt;
        battleChoice[category].selected = null;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    removeBattleElement(battleChoice, nameOrVnum, category, type);&lt;br /&gt;
    updateBattleChoiceText(battleChoice, category, type);&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addBattleElement(&lt;br /&gt;
  battleChoice,&lt;br /&gt;
  pseudoOrVnum,&lt;br /&gt;
  characterOrMonster,&lt;br /&gt;
  category,&lt;br /&gt;
  isMonster&lt;br /&gt;
) {&lt;br /&gt;
  var { template, raceToImage } = battleChoice;&lt;br /&gt;
  var battleChoiceCategory = battleChoice[category];&lt;br /&gt;
  var templateClone = template.cloneNode(true);&lt;br /&gt;
  var label = templateClone.firstElementChild;&lt;br /&gt;
  var [input, image, span] = label.children;&lt;br /&gt;
  var imageSrc;&lt;br /&gt;
  var name;&lt;br /&gt;
  var type;&lt;br /&gt;
&lt;br /&gt;
  if (isMonster) {&lt;br /&gt;
    type = characterOrMonster.category;&lt;br /&gt;
&lt;br /&gt;
    if (type === &amp;quot;stone&amp;quot; &amp;amp;&amp;amp; category === &amp;quot;attacker&amp;quot;) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
    imageSrc = characterOrMonster.image;&lt;br /&gt;
    name = getMonsterName(pseudoOrVnum);&lt;br /&gt;
  } else {&lt;br /&gt;
    type = &amp;quot;character&amp;quot;;&lt;br /&gt;
    imageSrc = raceToImage[characterOrMonster.race];&lt;br /&gt;
    name = pseudoOrVnum;&lt;br /&gt;
    label.classList.add(&amp;quot;notranslate&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var value = type + &amp;quot;-&amp;quot; + pseudoOrVnum;&lt;br /&gt;
  var id = category + &amp;quot;-&amp;quot; + value;&lt;br /&gt;
  var currentBattleChoice = battleChoiceCategory[type];&lt;br /&gt;
&lt;br /&gt;
  label.setAttribute(&amp;quot;for&amp;quot;, id);&lt;br /&gt;
  input.value = value;&lt;br /&gt;
  input.id = id;&lt;br /&gt;
  input.name = category;&lt;br /&gt;
  span.textContent = name;&lt;br /&gt;
&lt;br /&gt;
  handleImageFromWiki(image, imageSrc);&lt;br /&gt;
&lt;br /&gt;
  currentBattleChoice.container.appendChild(templateClone);&lt;br /&gt;
  currentBattleChoice.count++;&lt;br /&gt;
  currentBattleChoice.elements[pseudoOrVnum] = {&lt;br /&gt;
    container: templateClone,&lt;br /&gt;
    image: image,&lt;br /&gt;
    name: name,&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  updateBattleChoiceText(battleChoice, category, type);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addBattleChoice(&lt;br /&gt;
  battleChoice,&lt;br /&gt;
  pseudoOrVnum,&lt;br /&gt;
  characterOrMonster,&lt;br /&gt;
  isMonster = false&lt;br /&gt;
) {&lt;br /&gt;
  addBattleElement(&lt;br /&gt;
    battleChoice,&lt;br /&gt;
    pseudoOrVnum,&lt;br /&gt;
    characterOrMonster,&lt;br /&gt;
    &amp;quot;attacker&amp;quot;,&lt;br /&gt;
    isMonster&lt;br /&gt;
  );&lt;br /&gt;
  addBattleElement(&lt;br /&gt;
    battleChoice,&lt;br /&gt;
    pseudoOrVnum,&lt;br /&gt;
    characterOrMonster,&lt;br /&gt;
    &amp;quot;victim&amp;quot;,&lt;br /&gt;
    isMonster&lt;br /&gt;
  );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateBattleChoiceImage(battleChoice, characterName, newRace) {&lt;br /&gt;
  var imageSrc = battleChoice.raceToImage[newRace];&lt;br /&gt;
&lt;br /&gt;
  battleChoice.categories.forEach(function (category) {&lt;br /&gt;
    handleImageFromWiki(&lt;br /&gt;
      battleChoice[category].character.elements[characterName].image,&lt;br /&gt;
      imageSrc&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    var selected = battleChoice[category].selected;&lt;br /&gt;
&lt;br /&gt;
    if (isCharacterSelected(characterName, selected)) {&lt;br /&gt;
      updateBattleChoiceButton(battleChoice, category, selected);&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateBattleChoiceText(battleChoice, category, type) {&lt;br /&gt;
  var { count, container } = battleChoice[category][type];&lt;br /&gt;
  var parentContainer = container.parentElement;&lt;br /&gt;
&lt;br /&gt;
  if (count === 0) {&lt;br /&gt;
    hideElement(parentContainer);&lt;br /&gt;
    showElement(parentContainer.nextElementSibling);&lt;br /&gt;
  } else if (count === 1) {&lt;br /&gt;
    showElement(parentContainer);&lt;br /&gt;
    hideElement(parentContainer.nextElementSibling);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateBattleChoice(characters, battleChoice) {&lt;br /&gt;
  var templateImage = battleChoice.template.querySelector(&amp;quot;img&amp;quot;);&lt;br /&gt;
  var attackerImage = battleChoice.attacker.buttonContent.querySelector(&amp;quot;img&amp;quot;);&lt;br /&gt;
  var victimImage = battleChoice.victim.buttonContent.querySelector(&amp;quot;img&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  resetImageFromWiki(templateImage);&lt;br /&gt;
  resetImageFromWiki(attackerImage);&lt;br /&gt;
  resetImageFromWiki(victimImage);&lt;br /&gt;
&lt;br /&gt;
  for (var [pseudo, character] of Object.entries(characters.savedCharacters)) {&lt;br /&gt;
    addBattleChoice(battleChoice, pseudo, character);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (var [vnum, monster] of Object.entries(characters.savedMonsters)) {&lt;br /&gt;
    addBattleChoice(battleChoice, vnum, monster, true);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateBattleChoiceButton(battleChoice, category, data) {&lt;br /&gt;
  var battleChoiceCategory = battleChoice[category];&lt;br /&gt;
  var { defaultButtonContent, buttonContent } = battleChoiceCategory;&lt;br /&gt;
  var [buttonImage, buttonSpan] = buttonContent.firstElementChild.children;&lt;br /&gt;
  var { type, nameOrVnum } = parseTypeAndName(data);&lt;br /&gt;
  var { name, image } = battleChoiceCategory[type].elements[nameOrVnum];&lt;br /&gt;
&lt;br /&gt;
  hideElement(defaultButtonContent);&lt;br /&gt;
  showElement(buttonContent);&lt;br /&gt;
&lt;br /&gt;
  buttonSpan.textContent = name;&lt;br /&gt;
  buttonImage.src = image.src;&lt;br /&gt;
  battleChoiceCategory.selected = data;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function resetBattleChoiceButton(battleChoice, category) {&lt;br /&gt;
  var { defaultButtonContent, buttonContent } = battleChoice[category];&lt;br /&gt;
&lt;br /&gt;
  showElement(defaultButtonContent);&lt;br /&gt;
  hideElement(buttonContent);&lt;br /&gt;
&lt;br /&gt;
  if (category === &amp;quot;attacker&amp;quot;) {&lt;br /&gt;
    filterAttackTypeSelectionMonster(battleChoice.attackType);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isPC(character) {&lt;br /&gt;
  if (character.race === 0 || character.race === 1) {&lt;br /&gt;
    return false;&lt;br /&gt;
  }&lt;br /&gt;
  return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isBoss(character) {&lt;br /&gt;
  return character.race === 0 &amp;amp;&amp;amp; character.rank &amp;gt;= 5;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isStone(character) {&lt;br /&gt;
  return character.race === 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isMeleeAttacker(monster) {&lt;br /&gt;
  return monster.attack == 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isRangeAttacker(monster) {&lt;br /&gt;
  return monster.attack == 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isMagicAttacker(monster) {&lt;br /&gt;
  return monster.attack == 2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isMagicClass(character) {&lt;br /&gt;
  return character.race === &amp;quot;shaman&amp;quot; || character.class === &amp;quot;black_magic&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isDispell(character, skillId) {&lt;br /&gt;
  return character.class === &amp;quot;weaponary&amp;quot; &amp;amp;&amp;amp; skillId === 6;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isPolymorph(character) {&lt;br /&gt;
  return isChecked(character.isPolymorph);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isRiding(character) {&lt;br /&gt;
  return isChecked(character.isRiding);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isBow(weaponType) {&lt;br /&gt;
  return weaponType === 2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcAttackFactor(attacker, victim) {&lt;br /&gt;
  function calcCoeffK(dex, level) {&lt;br /&gt;
    return Math.min(90, Math.floor((2 * dex + level) / 3));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var K1 = calcCoeffK(attacker.polymorphDex, attacker.level);&lt;br /&gt;
  var K2 = calcCoeffK(victim.polymorphDex, attacker.level);&lt;br /&gt;
&lt;br /&gt;
  var AR = (K1 + 210) / 300;&lt;br /&gt;
  var ER = (((2 * K2 + 5) / (K2 + 95)) * 3) / 10;&lt;br /&gt;
&lt;br /&gt;
  return truncateNumber(AR - ER, 8);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcMainAttackValue(attacker) {&lt;br /&gt;
  var leadership = 0;&lt;br /&gt;
  var weaponGrowth = 0;&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker)) {&lt;br /&gt;
    weaponGrowth = attacker.weapon.growth;&lt;br /&gt;
    leadership = attacker.leadership;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return 2 * (attacker.level + weaponGrowth) + leadership;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcStatAttackValue(character) {&lt;br /&gt;
  switch (character.race) {&lt;br /&gt;
    case &amp;quot;warrior&amp;quot;:&lt;br /&gt;
    case &amp;quot;sura&amp;quot;:&lt;br /&gt;
      return 2 * character.str;&lt;br /&gt;
    case &amp;quot;ninja&amp;quot;:&lt;br /&gt;
      return Math.floor((1 / 4) * (character.str + 7 * character.dex));&lt;br /&gt;
    case &amp;quot;shaman&amp;quot;:&lt;br /&gt;
      return Math.floor((1 / 3) * (5 * character.int + character.dex));&lt;br /&gt;
    case &amp;quot;lycan&amp;quot;:&lt;br /&gt;
      return character.vit + 2 * character.dex;&lt;br /&gt;
    default:&lt;br /&gt;
      return 2 * character.str;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcSecondaryAttackValue(attacker) {&lt;br /&gt;
  var attackValueOther = 0;&lt;br /&gt;
&lt;br /&gt;
  var minAttackValue = 0;&lt;br /&gt;
  var maxAttackValue = 0;&lt;br /&gt;
&lt;br /&gt;
  var minAttackValueSlash = 0;&lt;br /&gt;
  var maxAttackValueSlash = 0;&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker)) {&lt;br /&gt;
    var { type, isSerpent, minAttackValue, maxAttackValue, growth } =&lt;br /&gt;
      attacker.weapon;&lt;br /&gt;
&lt;br /&gt;
    if (isSerpent) {&lt;br /&gt;
      minAttackValue = Math.max(0, attacker.minAttackValueRandom - growth);&lt;br /&gt;
      maxAttackValue = Math.max(&lt;br /&gt;
        minAttackValue,&lt;br /&gt;
        attacker.maxAttackValueRandom - growth&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    minAttackValueSlash = Math.min(&lt;br /&gt;
      attacker.minAttackValueSlash,&lt;br /&gt;
      attacker.maxAttackValueSlash&lt;br /&gt;
    );&lt;br /&gt;
    maxAttackValueSlash = Math.max(&lt;br /&gt;
      attacker.minAttackValueSlash,&lt;br /&gt;
      attacker.maxAttackValueSlash&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    attackValueOther += attacker.attackValue;&lt;br /&gt;
&lt;br /&gt;
    if (isBow(type) &amp;amp;&amp;amp; !isPolymorph(attacker)) {&lt;br /&gt;
      attackValueOther += 25;&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    minAttackValue = attacker.minAttackValue;&lt;br /&gt;
    maxAttackValue = attacker.maxAttackValue;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  minAttackValue += attacker.minAttackValuePolymorph;&lt;br /&gt;
  maxAttackValue += attacker.maxAttackValuePolymorph;&lt;br /&gt;
&lt;br /&gt;
  attackValueOther += attacker.statAttackValue;&lt;br /&gt;
  attackValueOther += attacker.horseAttackValue;&lt;br /&gt;
&lt;br /&gt;
  var weaponInterval = maxAttackValue - minAttackValue + 1;&lt;br /&gt;
  var slashInterval = maxAttackValueSlash - minAttackValueSlash + 1;&lt;br /&gt;
&lt;br /&gt;
  var totalCardinal = weaponInterval * slashInterval * 1_000_000;&lt;br /&gt;
  var minInterval = Math.min(weaponInterval, slashInterval);&lt;br /&gt;
&lt;br /&gt;
  minAttackValue += minAttackValueSlash;&lt;br /&gt;
  maxAttackValue += maxAttackValueSlash;&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    minAttackValue: minAttackValue,&lt;br /&gt;
    maxAttackValue: maxAttackValue,&lt;br /&gt;
    attackValueOther: attackValueOther,&lt;br /&gt;
    totalCardinal: totalCardinal,&lt;br /&gt;
    weights: calcWeights(minAttackValue, maxAttackValue, minInterval),&lt;br /&gt;
    possibleDamageCount: maxAttackValue - minAttackValue + 1,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcMagicAttackValue(attacker) {&lt;br /&gt;
  var minMagicAttackValueSlash = 0;&lt;br /&gt;
  var maxMagicAttackValueSlash = 0;&lt;br /&gt;
&lt;br /&gt;
  var { isSerpent, minMagicAttackValue, maxMagicAttackValue, growth } =&lt;br /&gt;
    attacker.weapon;&lt;br /&gt;
&lt;br /&gt;
  if (isSerpent) {&lt;br /&gt;
    minMagicAttackValue = Math.max(0, attacker.minMagicAttackValueRandom);&lt;br /&gt;
    maxMagicAttackValue = Math.max(&lt;br /&gt;
      minMagicAttackValue,&lt;br /&gt;
      attacker.maxMagicAttackValueRandom&lt;br /&gt;
    );&lt;br /&gt;
  } else {&lt;br /&gt;
    minMagicAttackValue += growth;&lt;br /&gt;
    maxMagicAttackValue += growth;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  minMagicAttackValueSlash = Math.min(&lt;br /&gt;
    attacker.minMagicAttackValueSlash,&lt;br /&gt;
    attacker.maxMagicAttackValueSlash&lt;br /&gt;
  );&lt;br /&gt;
  maxMagicAttackValueSlash = Math.max(&lt;br /&gt;
    attacker.minMagicAttackValueSlash,&lt;br /&gt;
    attacker.maxMagicAttackValueSlash&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  var weaponInterval = maxMagicAttackValue - minMagicAttackValue + 1;&lt;br /&gt;
  var slashInterval = maxMagicAttackValueSlash - minMagicAttackValueSlash + 1;&lt;br /&gt;
&lt;br /&gt;
  var totalCardinal = weaponInterval * slashInterval * 1_000_000;&lt;br /&gt;
  var minInterval = Math.min(weaponInterval, slashInterval);&lt;br /&gt;
&lt;br /&gt;
  minMagicAttackValue += minMagicAttackValueSlash;&lt;br /&gt;
  maxMagicAttackValue += maxMagicAttackValueSlash;&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    minMagicAttackValue: minMagicAttackValue,&lt;br /&gt;
    maxMagicAttackValue: maxMagicAttackValue,&lt;br /&gt;
    magicAttackValueAugmentation: getMagicAttackValueAugmentation(&lt;br /&gt;
      minMagicAttackValue,&lt;br /&gt;
      maxMagicAttackValue,&lt;br /&gt;
      attacker.magicAttackValue&lt;br /&gt;
    ),&lt;br /&gt;
    totalCardinal: totalCardinal,&lt;br /&gt;
    weights: calcWeights(minMagicAttackValue, maxMagicAttackValue, minInterval),&lt;br /&gt;
    possibleDamageCount: maxMagicAttackValue - minMagicAttackValue + 1,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getPolymorphPower(polymorphPoint, polymorphPowerTable) {&lt;br /&gt;
  return polymorphPowerTable[polymorphPoint];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSkillPower(skillPoint, skillPowerTable) {&lt;br /&gt;
  return skillPowerTable[skillPoint];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getMarriageBonusValue(character, marriageTable, itemName) {&lt;br /&gt;
  var index;&lt;br /&gt;
  var lovePoint = character.lovePoint;&lt;br /&gt;
&lt;br /&gt;
  if (lovePoint &amp;lt; 65) {&lt;br /&gt;
    index = 0;&lt;br /&gt;
  } else if (lovePoint &amp;lt; 80) {&lt;br /&gt;
    index = 1;&lt;br /&gt;
  } else if (lovePoint &amp;lt; 100) {&lt;br /&gt;
    index = 2;&lt;br /&gt;
  } else {&lt;br /&gt;
    index = 3;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return marriageTable[itemName][index];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcDamageWithPrimaryBonuses(damage, bonusValues) {&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.attackValueCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  damage += bonusValues.attackValueMarriage;&lt;br /&gt;
&lt;br /&gt;
  damage = Math.floor(&lt;br /&gt;
    (damage * bonusValues.monsterResistanceMarriageCoeff) / 100&lt;br /&gt;
  );&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.monsterResistanceCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  damage += Math.floor((damage * bonusValues.typeBonusCoeff) / 100);&lt;br /&gt;
  damage +=&lt;br /&gt;
    Math.floor((damage * bonusValues.raceBonusCoeff) / 100) -&lt;br /&gt;
    Math.floor((damage * bonusValues.raceResistanceCoeff) / 100);&lt;br /&gt;
  damage += Math.floor((damage * bonusValues.stoneBonusCoeff) / 100);&lt;br /&gt;
  damage += Math.floor((damage * bonusValues.monsterBonusCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  var elementBonusCoeff = bonusValues.elementBonusCoeff;&lt;br /&gt;
&lt;br /&gt;
  damage +=&lt;br /&gt;
    Math.trunc((damage * elementBonusCoeff[0]) / 10000) +&lt;br /&gt;
    Math.trunc((damage * elementBonusCoeff[1]) / 10000) +&lt;br /&gt;
    Math.trunc((damage * elementBonusCoeff[2]) / 10000) +&lt;br /&gt;
    Math.trunc((damage * elementBonusCoeff[3]) / 10000) +&lt;br /&gt;
    Math.trunc((damage * elementBonusCoeff[4]) / 10000) +&lt;br /&gt;
    Math.trunc((damage * elementBonusCoeff[5]) / 10000);&lt;br /&gt;
&lt;br /&gt;
    damage = Math.floor(damage * bonusValues.damageMultiplier);&lt;br /&gt;
&lt;br /&gt;
  return damage;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcDamageWithSecondaryBonuses(&lt;br /&gt;
  damage,&lt;br /&gt;
  bonusValues,&lt;br /&gt;
  damageType,&lt;br /&gt;
  minPiercingDamage,&lt;br /&gt;
  damageWithPrimaryBonuses&lt;br /&gt;
) {&lt;br /&gt;
  damage = Math.floor(damage * bonusValues.magicResistanceCoeff);&lt;br /&gt;
  damage = Math.trunc((damage * bonusValues.weaponDefenseCoeff) / 100);&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.tigerStrengthCoeff) / 100);&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.berserkBonusCoeff) / 100);&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.blessingBonusCoeff) / 100);&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.fearBonusCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  if (damageType.criticalHit) {&lt;br /&gt;
    damage *= 2;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (damageType.piercingHit) {&lt;br /&gt;
    damage += bonusValues.defenseBoost + Math.min(0, minPiercingDamage);&lt;br /&gt;
    damage += Math.floor(&lt;br /&gt;
      (damageWithPrimaryBonuses * bonusValues.extraPiercingHitCoeff) / 1000&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.averageDamageCoeff) / 100);&lt;br /&gt;
  damage = Math.floor(&lt;br /&gt;
    (damage * bonusValues.averageDamageResistanceCoeff) / 100&lt;br /&gt;
  );&lt;br /&gt;
  damage = Math.floor(&lt;br /&gt;
    (damage * bonusValues.skillDamageResistanceCoeff) / 100&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.rankBonusCoeff) / 100);&lt;br /&gt;
  damage = Math.max(0, damage + bonusValues.defensePercent);&lt;br /&gt;
  damage += Math.min(&lt;br /&gt;
    300,&lt;br /&gt;
    Math.floor((damage * bonusValues.damageBonusCoeff) / 100)&lt;br /&gt;
  );&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.empireMalusCoeff) / 10);&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.sungMaStrBonusCoeff) / 10000);&lt;br /&gt;
  damage -= Math.floor(damage * bonusValues.sungmaStrMalusCoeff);&lt;br /&gt;
&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.whiteDragonElixirCoeff) / 100);&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.steelDragonElixirCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  return damage;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcSkillDamageWithSecondaryBonuses(&lt;br /&gt;
  damage,&lt;br /&gt;
  bonusValues,&lt;br /&gt;
  damageType,&lt;br /&gt;
  minPiercingDamage&lt;br /&gt;
) {&lt;br /&gt;
  damage = Math.floor(damage * bonusValues.magicResistanceCoeff);&lt;br /&gt;
  damage = Math.trunc((damage * bonusValues.weaponDefenseCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  damage -= bonusValues.defense;&lt;br /&gt;
&lt;br /&gt;
  damage = floorMultiplication(damage, bonusValues.skillWardCoeff);&lt;br /&gt;
  damage = floorMultiplication(damage, bonusValues.skillBonusCoeff);&lt;br /&gt;
&lt;br /&gt;
  if (bonusValues.useDarkProtection) {&lt;br /&gt;
    // pass&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var tempDamage = Math.floor(&lt;br /&gt;
    (damage * bonusValues.skillBonusByBonusCoeff) / 100&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  damage = Math.floor(&lt;br /&gt;
    (tempDamage * bonusValues.magicAttackValueCoeff) / 100 + 0.5&lt;br /&gt;
  );&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.tigerStrengthCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  if (damageType.criticalHit) {&lt;br /&gt;
    damage *= 2;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (damageType.piercingHit) {&lt;br /&gt;
    damage += bonusValues.defenseBoost + Math.min(0, minPiercingDamage);&lt;br /&gt;
    damage += Math.floor(&lt;br /&gt;
      (tempDamage * bonusValues.extraPiercingHitCoeff) / 1000&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.skillDamageCoeff) / 100);&lt;br /&gt;
  damage = Math.floor(&lt;br /&gt;
    (damage * bonusValues.skillDamageResistanceCoeff) / 100&lt;br /&gt;
  );&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.rankBonusCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  damage = Math.max(0, damage + bonusValues.defensePercent);&lt;br /&gt;
  damage += Math.min(&lt;br /&gt;
    300,&lt;br /&gt;
    Math.floor((damage * bonusValues.damageBonusCoeff) / 100)&lt;br /&gt;
  );&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.empireMalusCoeff) / 10);&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.sungMaStrBonusCoeff) / 10000);&lt;br /&gt;
  damage -= Math.floor(damage * bonusValues.sungmaStrMalusCoeff);&lt;br /&gt;
&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.whiteDragonElixirCoeff) / 100);&lt;br /&gt;
  damage = Math.floor((damage * bonusValues.steelDragonElixirCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  return damage;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function computePolymorphPoint(attacker, victim, polymorphPowerTable) {&lt;br /&gt;
  attacker.polymorphDex = attacker.dex;&lt;br /&gt;
  victim.polymorphDex = victim.dex;&lt;br /&gt;
&lt;br /&gt;
  attacker.minAttackValuePolymorph = 0;&lt;br /&gt;
  attacker.maxAttackValuePolymorph = 0;&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker) &amp;amp;&amp;amp; isPolymorph(attacker)) {&lt;br /&gt;
    var polymorphPowerPct =&lt;br /&gt;
      getPolymorphPower(attacker.polymorphPoint, polymorphPowerTable) / 100;&lt;br /&gt;
    var polymorphMonster = createMonster(attacker.polymorphMonster, null, true);&lt;br /&gt;
&lt;br /&gt;
    var polymorphStr = floorMultiplication(&lt;br /&gt;
      polymorphPowerPct,&lt;br /&gt;
      polymorphMonster.str&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    attacker.polymorphDex += floorMultiplication(&lt;br /&gt;
      polymorphPowerPct,&lt;br /&gt;
      polymorphMonster.dex&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    attacker.minAttackValuePolymorph = floorMultiplication(&lt;br /&gt;
      polymorphPowerPct,&lt;br /&gt;
      polymorphMonster.minAttackValue&lt;br /&gt;
    );&lt;br /&gt;
    attacker.maxAttackValuePolymorph = floorMultiplication(&lt;br /&gt;
      polymorphPowerPct,&lt;br /&gt;
      polymorphMonster.maxAttackValue&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    if (!attacker.weapon) {&lt;br /&gt;
      attacker.maxAttackValuePolymorph += 1;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    attacker.attackValue = 0;&lt;br /&gt;
&lt;br /&gt;
    if (isMagicClass(attacker)) {&lt;br /&gt;
      attacker.statAttackValue = 2 * (polymorphStr + attacker.int);&lt;br /&gt;
    } else {&lt;br /&gt;
      attacker.statAttackValue = 2 * (polymorphStr + attacker.str);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function computeHorse(attacker) {&lt;br /&gt;
  attacker.horseAttackValue = 0;&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker) &amp;amp;&amp;amp; isRiding(attacker) &amp;amp;&amp;amp; !isPolymorph(attacker)) {&lt;br /&gt;
    var horseConstant = 30;&lt;br /&gt;
&lt;br /&gt;
    if (attacker.class === &amp;quot;weaponary&amp;quot;) {&lt;br /&gt;
      horseConstant = 60;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    attacker.horseAttackValue = floorMultiplication(&lt;br /&gt;
      2 * attacker.level + attacker.statAttackValue,&lt;br /&gt;
      attacker.horsePoint / horseConstant&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getRankBonus(attacker) {&lt;br /&gt;
  if (!isChecked(attacker.lowRank)) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  switch (attacker.rank) {&lt;br /&gt;
    case &amp;quot;aggressive&amp;quot;:&lt;br /&gt;
      return 1;&lt;br /&gt;
    case &amp;quot;fraudulent&amp;quot;:&lt;br /&gt;
      return 2;&lt;br /&gt;
    case &amp;quot;malicious&amp;quot;:&lt;br /&gt;
      return 3;&lt;br /&gt;
    case &amp;quot;cruel&amp;quot;:&lt;br /&gt;
      return 5;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcElementCoeffPvP(elementBonus, mapping, attacker, victim) {&lt;br /&gt;
  var minElementMalus = 0;&lt;br /&gt;
  var maxDifference = 0;&lt;br /&gt;
  var savedElementDifferences = [];&lt;br /&gt;
  var elementBonusIndex = 0;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; elementBonus.length; index++) {&lt;br /&gt;
    if (!attacker[mapping.elementBonus[index]]) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var elementDifference =&lt;br /&gt;
      attacker[mapping.elementBonus[index]] -&lt;br /&gt;
      victim[mapping.elementResistance[index]];&lt;br /&gt;
&lt;br /&gt;
    if (elementDifference &amp;gt;= 0) {&lt;br /&gt;
      elementBonus[elementBonusIndex] = 10 * elementDifference;&lt;br /&gt;
      minElementMalus -= elementDifference;&lt;br /&gt;
      maxDifference = Math.max(maxDifference, elementDifference);&lt;br /&gt;
      elementBonusIndex++;&lt;br /&gt;
    } else {&lt;br /&gt;
      savedElementDifferences.push(elementDifference);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (!savedElementDifferences.length) {&lt;br /&gt;
    return;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  minElementMalus += maxDifference;&lt;br /&gt;
  savedElementDifferences.sort(compareNumbers);&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; savedElementDifferences.length; index++) {&lt;br /&gt;
    var elementDifference = savedElementDifferences[index];&lt;br /&gt;
&lt;br /&gt;
    elementBonus[elementBonusIndex + index] =&lt;br /&gt;
      10 * Math.max(minElementMalus, elementDifference);&lt;br /&gt;
&lt;br /&gt;
    minElementMalus = Math.min(&lt;br /&gt;
      0,&lt;br /&gt;
      Math.max(minElementMalus, minElementMalus - elementDifference)&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function skillChanceReduction(value) {&lt;br /&gt;
  if (value &amp;lt;= 9) {&lt;br /&gt;
    return Math.floor(value / 2);&lt;br /&gt;
  }&lt;br /&gt;
  return 5 + Math.floor((value - 10) / 4);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function magicResistanceToCoeff(magicResistance) {&lt;br /&gt;
  if (magicResistance) {&lt;br /&gt;
    return 2000 / (6 * magicResistance + 1000) - 1;&lt;br /&gt;
  }&lt;br /&gt;
  return 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createBattleValues(attacker, victim, battle, skillType) {&lt;br /&gt;
  var { mapping, constants } = battle;&lt;br /&gt;
  var calcAttackValues;&lt;br /&gt;
&lt;br /&gt;
  var missPercentage = 0;&lt;br /&gt;
  var attackValueMeleeMagic = 0;&lt;br /&gt;
  var attackValueMarriage = 0;&lt;br /&gt;
  var monsterResistanceMarriage = 0;&lt;br /&gt;
  var monsterResistance = 0;&lt;br /&gt;
  var typeBonus = 0;&lt;br /&gt;
  var raceBonus = 0;&lt;br /&gt;
  var raceResistance = 0;&lt;br /&gt;
  var stoneBonus = 0;&lt;br /&gt;
  var monsterBonus = 0;&lt;br /&gt;
  var elementBonus = [0, 0, 0, 0, 0, 0]; // fire, ice, lightning, earth, darkness, wind, order doesn't matter&lt;br /&gt;
  var defenseMarriage = 0;&lt;br /&gt;
  var damageMultiplier = 1;&lt;br /&gt;
  var useDamage = 1;&lt;br /&gt;
  var defense = victim.defense;&lt;br /&gt;
  var defenseBoost = defense;&lt;br /&gt;
  var magicResistance = 0;&lt;br /&gt;
  var weaponDefense = 0;&lt;br /&gt;
  var tigerStrength = 0;&lt;br /&gt;
  var berserkBonus = 0;&lt;br /&gt;
  var blessingBonus = 0;&lt;br /&gt;
  var fearBonus = 0;&lt;br /&gt;
  var magicAttackValueMeleeMagic = 0;&lt;br /&gt;
  var criticalHitPercentage = attacker.criticalHit;&lt;br /&gt;
  var piercingHitPercentage = attacker.piercingHit;&lt;br /&gt;
  var extraPiercingHitPercentage = Math.max(0, piercingHitPercentage - 100);&lt;br /&gt;
  var averageDamage = 0;&lt;br /&gt;
  var averageDamageResistance = 0;&lt;br /&gt;
  var skillDamage = 0;&lt;br /&gt;
  var skillDamageResistance = 0;&lt;br /&gt;
  var rankBonus = 0;&lt;br /&gt;
  var defensePercent = 0;&lt;br /&gt;
  var damageBonus = 0;&lt;br /&gt;
  var empireMalus = 0;&lt;br /&gt;
  var sungMaStrBonus = 0;&lt;br /&gt;
  var sungmaStrMalus = 0;&lt;br /&gt;
  var whiteDragonElixir = 0;&lt;br /&gt;
  var steelDragonElixir = 0;&lt;br /&gt;
&lt;br /&gt;
  attacker.statAttackValue = calcStatAttackValue(attacker);&lt;br /&gt;
&lt;br /&gt;
  computePolymorphPoint(attacker, victim, constants.polymorphPowerTable);&lt;br /&gt;
  computeHorse(attacker);&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker)) {&lt;br /&gt;
    if (weaponData.hasOwnProperty(attacker.weapon)) {&lt;br /&gt;
      attacker.weapon = createWeapon(attacker.weapon);&lt;br /&gt;
    } else {&lt;br /&gt;
      attacker.weapon = createWeapon(0);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    attacker.weapon.getValues(attacker.weaponUpgrade);&lt;br /&gt;
&lt;br /&gt;
    attackValueMeleeMagic =&lt;br /&gt;
      attacker.attackValuePercent + Math.min(100, attacker.attackMeleeMagic);&lt;br /&gt;
&lt;br /&gt;
    var weaponType = attacker.weapon.type;&lt;br /&gt;
&lt;br /&gt;
    if (skillType &amp;amp;&amp;amp; attacker.class === &amp;quot;archery&amp;quot;) {&lt;br /&gt;
      if (weaponType !== 2) {&lt;br /&gt;
        useDamage = 0;&lt;br /&gt;
        weaponType = 2;&lt;br /&gt;
      }&lt;br /&gt;
      defense = 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var weaponDefenseName = mapping.defenseWeapon[weaponType];&lt;br /&gt;
    var weaponDefenseBreakName = mapping.breakWeapon[weaponType];&lt;br /&gt;
&lt;br /&gt;
    if (victim.hasOwnProperty(weaponDefenseName)) {&lt;br /&gt;
      weaponDefense = victim[weaponDefenseName];&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isChecked(attacker.whiteDragonElixir)) {&lt;br /&gt;
      whiteDragonElixir = 10;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isPC(victim)) {&lt;br /&gt;
      if (!skillType) {&lt;br /&gt;
        if (weaponType === 2 &amp;amp;&amp;amp; !isPolymorph(attacker)) {&lt;br /&gt;
          missPercentage = victim.arrowBlock;&lt;br /&gt;
        } else {&lt;br /&gt;
          missPercentage = victim.meleeBlock;&lt;br /&gt;
        }&lt;br /&gt;
        missPercentage +=&lt;br /&gt;
          victim.meleeArrowBlock -&lt;br /&gt;
          (missPercentage * victim.meleeArrowBlock) / 100;&lt;br /&gt;
&lt;br /&gt;
        berserkBonus = calcBerserkBonus(constants.skillPowerTable, victim);&lt;br /&gt;
        blessingBonus = calcBlessingBonus(constants.skillPowerTable, victim);&lt;br /&gt;
        fearBonus = calcFearBonus(constants.skillPowerTable, victim);&lt;br /&gt;
        averageDamageResistance = victim.averageDamageResistance;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      typeBonus = Math.max(1, attacker.humanBonus - victim.humanResistance);&lt;br /&gt;
      raceBonus = attacker[mapping.raceBonus[victim.race]];&lt;br /&gt;
      raceResistance = victim[mapping.raceResistance[attacker.race]];&lt;br /&gt;
&lt;br /&gt;
      calcElementCoeffPvP(elementBonus, mapping, attacker, victim);&lt;br /&gt;
&lt;br /&gt;
      if (weaponType !== 2 &amp;amp;&amp;amp; attacker.hasOwnProperty(weaponDefenseBreakName)) {&lt;br /&gt;
        weaponDefense -= attacker[weaponDefenseBreakName];&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      criticalHitPercentage = 0;&lt;br /&gt;
    } else {&lt;br /&gt;
      if (isChecked(attacker.isMarried)) {&lt;br /&gt;
        if (isChecked(attacker.loveNecklace)) {&lt;br /&gt;
          attackValueMarriage = getMarriageBonusValue(&lt;br /&gt;
            attacker,&lt;br /&gt;
            constants.marriageTable,&lt;br /&gt;
            &amp;quot;loveNecklace&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isChecked(attacker.loveEarrings)) {&lt;br /&gt;
          criticalHitPercentage += getMarriageBonusValue(&lt;br /&gt;
            attacker,&lt;br /&gt;
            constants.marriageTable,&lt;br /&gt;
            &amp;quot;loveEarrings&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isChecked(attacker.harmonyEarrings)) {&lt;br /&gt;
          piercingHitPercentage += getMarriageBonusValue(&lt;br /&gt;
            attacker,&lt;br /&gt;
            constants.marriageTable,&lt;br /&gt;
            &amp;quot;harmonyEarrings&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (isChecked(attacker.tigerStrength)) {&lt;br /&gt;
        tigerStrength = 40;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      for (var index = 0; index &amp;lt; elementBonus.length; index++) {&lt;br /&gt;
        var elementBonusName = mapping.elementBonus[index];&lt;br /&gt;
        var elementResistanceName = mapping.elementResistance[index];&lt;br /&gt;
&lt;br /&gt;
        if (attacker[elementBonusName] &amp;amp;&amp;amp; victim[elementBonusName]) {&lt;br /&gt;
          elementBonus[index] =&lt;br /&gt;
            50 * (attacker[elementBonusName] - victim[elementResistanceName]);&lt;br /&gt;
        } else {&lt;br /&gt;
          elementBonus[index] = 5 * attacker[elementBonusName];&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      var victimType = victim.type;&lt;br /&gt;
&lt;br /&gt;
      if (victimType !== -1) {&lt;br /&gt;
        typeBonus = attacker[mapping.typeFlag[victimType]];&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      monsterBonus = attacker.monsterBonus;&lt;br /&gt;
&lt;br /&gt;
      if (isStone(victim)) {&lt;br /&gt;
        stoneBonus = attacker.stoneBonus;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (isBoss(victim)) {&lt;br /&gt;
        if (skillType) {&lt;br /&gt;
          skillDamage += attacker.skillBossDamage;&lt;br /&gt;
        } else {&lt;br /&gt;
          averageDamage += attacker.bossDamage;&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (isChecked(attacker.onYohara)) {&lt;br /&gt;
        var sungmaStrDifference = attacker.sungmaStr - attacker.sungmaStrMalus;&lt;br /&gt;
&lt;br /&gt;
        if (sungmaStrDifference &amp;gt;= 0) {&lt;br /&gt;
          sungMaStrBonus = sungmaStrDifference;&lt;br /&gt;
        } else {&lt;br /&gt;
          sungmaStrMalus = 0.5;&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (skillType) {&lt;br /&gt;
      skillDamage += attacker.skillDamage;&lt;br /&gt;
    } else {&lt;br /&gt;
      averageDamage += attacker.averageDamage;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    rankBonus = getRankBonus(attacker);&lt;br /&gt;
    damageBonus = attacker.damageBonus;&lt;br /&gt;
&lt;br /&gt;
    if (isChecked(attacker.empireMalus)) {&lt;br /&gt;
      empireMalus = 1;&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    if (isPC(victim)) {&lt;br /&gt;
      if (isChecked(victim.isMarried)) {&lt;br /&gt;
        if (isChecked(victim.harmonyBracelet)) {&lt;br /&gt;
          monsterResistanceMarriage = getMarriageBonusValue(&lt;br /&gt;
            victim,&lt;br /&gt;
            constants.marriageTable,&lt;br /&gt;
            &amp;quot;harmonyBracelet&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isChecked(victim.harmonyNecklace) &amp;amp;&amp;amp; !skillType) {&lt;br /&gt;
          defenseMarriage = getMarriageBonusValue(&lt;br /&gt;
            victim,&lt;br /&gt;
            constants.marriageTable,&lt;br /&gt;
            &amp;quot;harmonyNecklace&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      monsterResistance = victim.monsterResistance;&lt;br /&gt;
&lt;br /&gt;
      for (var index = 0; index &amp;lt; elementBonus.length; index++) {&lt;br /&gt;
        var elementBonusName = mapping.elementBonus[index];&lt;br /&gt;
        var elementResistanceName = mapping.elementResistance[index];&lt;br /&gt;
&lt;br /&gt;
        if (attacker[elementBonusName]) {&lt;br /&gt;
          elementBonus[index] =&lt;br /&gt;
            80 * (attacker[elementBonusName] - victim[elementResistanceName]);&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (!skillType) {&lt;br /&gt;
        if (isMeleeAttacker(attacker)) {&lt;br /&gt;
          missPercentage = victim.meleeBlock;&lt;br /&gt;
          averageDamageResistance = victim.averageDamageResistance;&lt;br /&gt;
          berserkBonus = calcBerserkBonus(constants.skillPowerTable, victim);&lt;br /&gt;
          blessingBonus = calcBlessingBonus(constants.skillPowerTable, victim);&lt;br /&gt;
          fearBonus = calcFearBonus(constants.skillPowerTable, victim);&lt;br /&gt;
        } else if (isRangeAttacker(attacker)) {&lt;br /&gt;
          missPercentage = victim.arrowBlock;&lt;br /&gt;
          weaponDefense = victim.arrowDefense;&lt;br /&gt;
          averageDamageResistance = victim.averageDamageResistance;&lt;br /&gt;
          berserkBonus = calcBerserkBonus(constants.skillPowerTable, victim);&lt;br /&gt;
          blessingBonus = calcBlessingBonus(constants.skillPowerTable, victim);&lt;br /&gt;
          fearBonus = calcFearBonus(constants.skillPowerTable, victim);&lt;br /&gt;
        } else if (isMagicAttacker(attacker)) {&lt;br /&gt;
          missPercentage = victim.arrowBlock;&lt;br /&gt;
          skillDamageResistance = victim.skillDamageResistance;&lt;br /&gt;
          magicResistance = victim.magicResistance;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        missPercentage +=&lt;br /&gt;
          victim.meleeArrowBlock -&lt;br /&gt;
          (missPercentage * victim.meleeArrowBlock) / 100;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    typeBonus = 1;&lt;br /&gt;
    damageMultiplier = attacker.damageMultiplier;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillType) {&lt;br /&gt;
    criticalHitPercentage = skillChanceReduction(criticalHitPercentage);&lt;br /&gt;
    piercingHitPercentage = skillChanceReduction(piercingHitPercentage);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (isPC(victim)) {&lt;br /&gt;
    if (!skillType &amp;amp;&amp;amp; isChecked(victim.biologist70)) {&lt;br /&gt;
      defenseBoost = Math.floor((defenseBoost * 110) / 100);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    criticalHitPercentage = Math.max(&lt;br /&gt;
      0,&lt;br /&gt;
      criticalHitPercentage - victim.criticalHitResistance&lt;br /&gt;
    );&lt;br /&gt;
    piercingHitPercentage = Math.max(&lt;br /&gt;
      0,&lt;br /&gt;
      piercingHitPercentage - victim.piercingHitResistance&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    if (skillType) {&lt;br /&gt;
      skillDamageResistance = victim.skillDamageResistance;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isMagicClass(victim)) {&lt;br /&gt;
      defensePercent = (-2 * victim.magicDefense * victim.defensePercent) / 100;&lt;br /&gt;
    } else {&lt;br /&gt;
      defensePercent = (-2 * defenseBoost * victim.defensePercent) / 100;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isChecked(victim.steelDragonElixir)) {&lt;br /&gt;
      steelDragonElixir = 10;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillType === &amp;quot;magic&amp;quot;) {&lt;br /&gt;
    attackValueMeleeMagic = 0;&lt;br /&gt;
    magicAttackValueMeleeMagic =&lt;br /&gt;
      attacker.attackMagic + Math.min(100, attacker.attackMeleeMagic);&lt;br /&gt;
    attackValueMarriage = 0;&lt;br /&gt;
    defense = 0;&lt;br /&gt;
    if (isDispell(attacker, 6)) {&lt;br /&gt;
      typeBonus = 0;&lt;br /&gt;
      raceBonus = 0;&lt;br /&gt;
      raceResistance = 0;&lt;br /&gt;
      stoneBonus = 0;&lt;br /&gt;
      monsterBonus = 0;&lt;br /&gt;
      for (var index = 0; index &amp;lt; elementBonus.length; index++) {&lt;br /&gt;
        elementBonus[index] = 0;&lt;br /&gt;
      }&lt;br /&gt;
    } else {&lt;br /&gt;
      magicResistance = victim.magicResistance;&lt;br /&gt;
    }&lt;br /&gt;
    weaponDefense = 0;&lt;br /&gt;
    calcAttackValues = calcMagicAttackValue;&lt;br /&gt;
  } else {&lt;br /&gt;
    calcAttackValues = calcSecondaryAttackValue;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  missPercentage = Math.min(100, missPercentage);&lt;br /&gt;
&lt;br /&gt;
  var bonusValues = {&lt;br /&gt;
    missPercentage: missPercentage,&lt;br /&gt;
    weaponBonusCoeff: 1,&lt;br /&gt;
    attackValueCoeff: 100 + attackValueMeleeMagic,&lt;br /&gt;
    attackValueMarriage: attackValueMarriage,&lt;br /&gt;
    monsterResistanceMarriageCoeff: 100 - monsterResistanceMarriage,&lt;br /&gt;
    monsterResistanceCoeff: 100 - monsterResistance,&lt;br /&gt;
    typeBonusCoeff: typeBonus,&lt;br /&gt;
    raceBonusCoeff: raceBonus,&lt;br /&gt;
    raceResistanceCoeff: raceResistance,&lt;br /&gt;
    stoneBonusCoeff: stoneBonus,&lt;br /&gt;
    monsterBonusCoeff: monsterBonus,&lt;br /&gt;
    elementBonusCoeff: elementBonus,&lt;br /&gt;
    damageMultiplier: damageMultiplier,&lt;br /&gt;
    useDamage: useDamage,&lt;br /&gt;
    defense: defense,&lt;br /&gt;
    defenseBoost: defenseBoost,&lt;br /&gt;
    defenseMarriage: defenseMarriage,&lt;br /&gt;
    tigerStrengthCoeff: 100 + tigerStrength,&lt;br /&gt;
    magicResistanceCoeff: magicResistanceToCoeff(magicResistance),&lt;br /&gt;
    weaponDefenseCoeff: 100 - weaponDefense,&lt;br /&gt;
    berserkBonusCoeff: 100 + berserkBonus,&lt;br /&gt;
    blessingBonusCoeff: 100 - blessingBonus,&lt;br /&gt;
    fearBonusCoeff: 100 - fearBonus,&lt;br /&gt;
    magicAttackValueCoeff: 100 + magicAttackValueMeleeMagic,&lt;br /&gt;
    extraPiercingHitCoeff: 5 * extraPiercingHitPercentage,&lt;br /&gt;
    averageDamageCoeff: 100 + averageDamage,&lt;br /&gt;
    averageDamageResistanceCoeff: 100 - Math.min(99, averageDamageResistance),&lt;br /&gt;
    skillDamageCoeff: 100 + skillDamage,&lt;br /&gt;
    skillDamageResistanceCoeff: 100 - Math.min(99, skillDamageResistance),&lt;br /&gt;
    rankBonusCoeff: 100 + rankBonus,&lt;br /&gt;
    defensePercent: Math.floor(defensePercent),&lt;br /&gt;
    damageBonusCoeff: Math.min(20, damageBonus),&lt;br /&gt;
    empireMalusCoeff: 10 - empireMalus,&lt;br /&gt;
    sungMaStrBonusCoeff: 10000 + sungMaStrBonus,&lt;br /&gt;
    sungmaStrMalusCoeff: sungmaStrMalus,&lt;br /&gt;
    whiteDragonElixirCoeff: 100 + whiteDragonElixir,&lt;br /&gt;
    steelDragonElixirCoeff: 100 - steelDragonElixir,&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  criticalHitPercentage = Math.min(criticalHitPercentage, 100);&lt;br /&gt;
  piercingHitPercentage = Math.min(piercingHitPercentage, 100);&lt;br /&gt;
&lt;br /&gt;
  var damageTypeCombinaison = [&lt;br /&gt;
    {&lt;br /&gt;
      criticalHit: false,&lt;br /&gt;
      piercingHit: false,&lt;br /&gt;
      weight:&lt;br /&gt;
        (100 - criticalHitPercentage) *&lt;br /&gt;
        (100 - piercingHitPercentage) *&lt;br /&gt;
        (100 - missPercentage),&lt;br /&gt;
      name: &amp;quot;normalHit&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      criticalHit: true,&lt;br /&gt;
      piercingHit: false,&lt;br /&gt;
      weight:&lt;br /&gt;
        criticalHitPercentage *&lt;br /&gt;
        (100 - piercingHitPercentage) *&lt;br /&gt;
        (100 - missPercentage),&lt;br /&gt;
      name: &amp;quot;criticalHit&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      criticalHit: false,&lt;br /&gt;
      piercingHit: true,&lt;br /&gt;
      weight:&lt;br /&gt;
        (100 - criticalHitPercentage) *&lt;br /&gt;
        piercingHitPercentage *&lt;br /&gt;
        (100 - missPercentage),&lt;br /&gt;
      name: &amp;quot;piercingHit&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      criticalHit: true,&lt;br /&gt;
      piercingHit: true,&lt;br /&gt;
      weight:&lt;br /&gt;
        criticalHitPercentage * piercingHitPercentage * (100 - missPercentage),&lt;br /&gt;
      name: &amp;quot;criticalPiercingHit&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
  ];&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    attacker: attacker,&lt;br /&gt;
    victim: victim,&lt;br /&gt;
    attackFactor: calcAttackFactor(attacker, victim),&lt;br /&gt;
    mainAttackValue: calcMainAttackValue(attacker),&lt;br /&gt;
    attackValues: calcAttackValues(attacker),&lt;br /&gt;
    bonusValues: bonusValues,&lt;br /&gt;
    damageTypeCombinaison: damageTypeCombinaison,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateBattleValues(battleValues, skillFormula, skillInfo) {&lt;br /&gt;
  var weaponBonus = 0;&lt;br /&gt;
  var skillWard = 0;&lt;br /&gt;
  var skillBonus = 0;&lt;br /&gt;
  var skillBonusByBonus = 0;&lt;br /&gt;
  var { attacker: attacker, bonusValues: bonusValues } = battleValues;&lt;br /&gt;
  var {&lt;br /&gt;
    range: [minVariation, maxVariation],&lt;br /&gt;
  } = skillInfo;&lt;br /&gt;
  var variationLength = maxVariation - minVariation + 1;&lt;br /&gt;
&lt;br /&gt;
  if (skillInfo.hasOwnProperty(&amp;quot;weaponBonus&amp;quot;)) {&lt;br /&gt;
    var [weaponType, weaponBonusValue] = skillInfo.weaponBonus;&lt;br /&gt;
&lt;br /&gt;
    if (weaponType === attacker.weapon.type) {&lt;br /&gt;
      weaponBonus = weaponBonusValue;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillInfo.skillBonus) {&lt;br /&gt;
    skillBonus = skillInfo.skillBonus;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillInfo.skillWard) {&lt;br /&gt;
    skillWard = skillInfo.skillWard;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillInfo.skillBonusByBonus) {&lt;br /&gt;
    skillBonusByBonus = skillInfo.skillBonusByBonus;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillInfo.removeWeaponReduction) {&lt;br /&gt;
    bonusValues.weaponDefenseCoeff = 100;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  bonusValues.weaponBonusCoeff = 100 + weaponBonus;&lt;br /&gt;
  bonusValues.skillWardCoeff = 1 - skillWard / 100;&lt;br /&gt;
  bonusValues.skillBonusCoeff = 1 + skillBonus / 100;&lt;br /&gt;
  bonusValues.skillBonusByBonusCoeff = 100 + skillBonusByBonus;&lt;br /&gt;
&lt;br /&gt;
  battleValues.skillFormula = skillFormula;&lt;br /&gt;
  battleValues.skillRange = skillInfo.range;&lt;br /&gt;
  battleValues.attackValues.totalCardinal *= variationLength;&lt;br /&gt;
  battleValues.attackValues.possibleDamageCount *= variationLength;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcWeights(minValue, maxValue, minInterval) {&lt;br /&gt;
  var firstWeightLimit = minValue + minInterval - 1;&lt;br /&gt;
  var lastWeightsLimit = maxValue - minInterval + 1;&lt;br /&gt;
  var weights = [];&lt;br /&gt;
&lt;br /&gt;
  for (var value = minValue; value &amp;lt; firstWeightLimit; value++) {&lt;br /&gt;
    weights.push(value - minValue + 1);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (var value = firstWeightLimit; value &amp;lt;= lastWeightsLimit; value++) {&lt;br /&gt;
    weights.push(minInterval);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (var value = lastWeightsLimit + 1; value &amp;lt;= maxValue; value++) {&lt;br /&gt;
    weights.push(maxValue - value + 1);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return weights;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcBerserkBonus(skillPowerTable, victim) {&lt;br /&gt;
  if (!isChecked(victim.useBerserk) || victim.class !== &amp;quot;body&amp;quot;) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var skillPower = getSkillPower(victim[&amp;quot;skillBerserk&amp;quot;], skillPowerTable);&lt;br /&gt;
&lt;br /&gt;
  if (!skillPower) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var berserkBonus = Math.floor(skillPower * 25);&lt;br /&gt;
&lt;br /&gt;
  return berserkBonus;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcBlessingBonus(skillPowerTable, victim) {&lt;br /&gt;
  if (!isChecked(victim.isBlessed)) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var int = victim.intBlessing;&lt;br /&gt;
  var dex = victim.dexBlessing;&lt;br /&gt;
  var skillPower = getSkillPower(victim[&amp;quot;skillBlessing&amp;quot;], skillPowerTable);&lt;br /&gt;
&lt;br /&gt;
  if (!skillPower) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var blessingBonus = floorMultiplication(&lt;br /&gt;
    ((int * 0.3 + 5) * (2 * skillPower + 0.5) + 0.3 * dex) / (skillPower + 2.3),&lt;br /&gt;
    1&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  if (victim.class === &amp;quot;dragon&amp;quot; &amp;amp;&amp;amp; isChecked(victim.blessingOnself)) {&lt;br /&gt;
    blessingBonus = floorMultiplication(blessingBonus, 1.1);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return blessingBonus;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcFearBonus(skillPowerTable, victim) {&lt;br /&gt;
  if (!isChecked(victim.useFear) || victim.class !== &amp;quot;weaponary&amp;quot;) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var skillPower = getSkillPower(victim[&amp;quot;skillFear&amp;quot;], skillPowerTable);&lt;br /&gt;
&lt;br /&gt;
  if (!skillPower) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var fearBonus = 5 + Math.floor(skillPower * 20);&lt;br /&gt;
&lt;br /&gt;
  return fearBonus;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSkillFormula(battle, skillId, battleValues, removeSkillVariation) {&lt;br /&gt;
  var { attacker, victim, attackFactor } = battleValues;&lt;br /&gt;
  var skillPowerTable = battle.constants.skillPowerTable;&lt;br /&gt;
&lt;br /&gt;
  var skillFormula;&lt;br /&gt;
  var skillInfo = { range: [0, 0] };&lt;br /&gt;
&lt;br /&gt;
  var { class: attackerClass, level: lv, vit, str, int, dex } = attacker;&lt;br /&gt;
&lt;br /&gt;
  if (skillId &amp;lt;= 9) {&lt;br /&gt;
    var skillPower = getSkillPower(&lt;br /&gt;
      attacker[&amp;quot;attackSkill&amp;quot; + skillId],&lt;br /&gt;
      skillPowerTable&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    var improvedBySkillBonus = false;&lt;br /&gt;
    var improvedByBonus = false;&lt;br /&gt;
&lt;br /&gt;
    if (attackerClass === &amp;quot;body&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Triple lacération&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.1 * atk + (0.5 * atk + 1.5 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Moulinet à l'épée&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              3 * atk + (0.8 * atk + 5 * str + 3 * dex + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Accélération&lt;br /&gt;
        case 5:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * atk + (atk + dex * 3 + str * 7 + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Volonté de vivre&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              (3 * atk + (atk + 1.5 * str) * skillPower) * 1.07,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          break;&lt;br /&gt;
        // Tremblement de terre&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              3 * atk +&lt;br /&gt;
                (0.9 * atk + variation + 5 * str + 3 * dex + lv) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;mental&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Attaque de l'esprit&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2.3 * atk + (4 * atk + 4 * str + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Attaque de la paume&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2.3 * atk + (3 * atk + 4 * str + 3 * vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Charge&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * atk + (2 * atk + 2 * dex + 2 * vit + 4 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          break;&lt;br /&gt;
        // Coup d'épée&lt;br /&gt;
        case 5:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * atk + (atk + 3 * dex + 5 * str + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Orbe de l'épée&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              (2 * atk + (2 * atk + 2 * dex + 2 * vit + 4 * str) * skillPower) *&lt;br /&gt;
                1.1,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          break;&lt;br /&gt;
        // Tremblement de terre&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              3 * atk +&lt;br /&gt;
                (0.9 * atk + variation + 5 * str + 3 * dex + lv) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;blade_fight&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Embuscade&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk + (1.2 * atk + variation + 4 * dex + 4 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [1, 50];&lt;br /&gt;
          skillInfo.range = [500, 700];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Attaque rapide&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk + (1.6 * atk + variation + 7 * dex + 7 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [1, 35];&lt;br /&gt;
          skillInfo.range = [200, 300];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Dague filante&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * atk + (0.5 * atk + 9 * dex + 7 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Brume empoisonnée&lt;br /&gt;
        case 5:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * lv + (atk + 3 * str + 18 * dex) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Poison insidieux&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              (2 * lv + (atk + 3 * str + 18 * dex) * skillPower) * 1.1,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          break;&lt;br /&gt;
        // Étoiles brillantes&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk + (1.7 * atk + variation + 6 * dex + 5 * lv) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;archery&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Tir à répétition&lt;br /&gt;
        // case 1:&lt;br /&gt;
        //   skillFormula = function (atk) {&lt;br /&gt;
        //     return floorMultiplication(&lt;br /&gt;
        //       atk + 0.2 * atk * Math.floor(2 + 6 * skillPower) + (0.8 * atk + 8 * dex * attackFactor + 2 * int) * skillPower,&lt;br /&gt;
        //       1&lt;br /&gt;
        //     );&lt;br /&gt;
        //   };&lt;br /&gt;
        //   improvedByBonus = true;&lt;br /&gt;
        //   break;&lt;br /&gt;
        // Pluie de flèches&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk + (1.7 * atk + 5 * dex + str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Flèche de feu&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.5 * atk + (2.6 * atk + 0.9 * int + variation) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [100, 300];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Foulée de plume&lt;br /&gt;
        case 4:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              (3 * dex + 200 + 2 * str + 2 * int) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.removeWeaponReduction = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Flèche empoisonnée&lt;br /&gt;
        case 5:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk +&lt;br /&gt;
                (1.4 * atk + variation + 7 * dex + 4 * str + 4 * int) *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [100, 200];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Coup étincelant&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              (atk +&lt;br /&gt;
                (1.2 * atk + variation + 6 * dex + 3 * str + 3 * int) *&lt;br /&gt;
                  skillPower) *&lt;br /&gt;
                1.2,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [100, 200];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Tir tempête&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.9 * atk + (2.6 * atk + variation) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;weaponary&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Toucher brûlant&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk +&lt;br /&gt;
                2 * lv +&lt;br /&gt;
                2 * int +&lt;br /&gt;
                (2 * atk + 4 * str + 14 * int) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Tourbillon du dragon&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.1 * atk +&lt;br /&gt;
                2 * lv +&lt;br /&gt;
                2 * int +&lt;br /&gt;
                (1.5 * atk + str + 12 * int) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Contre-sort&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              40 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                2 * int +&lt;br /&gt;
                (10 * int + 7 * mav + variation) * attackFactor * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [50, 100];&lt;br /&gt;
          break;&lt;br /&gt;
        // Coup démoniaque&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.9 * atk + (2.6 * atk + variation) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;black_magic&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Attaque des ténèbres&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              40 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                2 * int +&lt;br /&gt;
                (13 * int + 6 * mav + variation) * attackFactor * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [50, 100];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Attaque de flammes&lt;br /&gt;
        // case 2:&lt;br /&gt;
        //   skillFormula = function (mav, variation) {&lt;br /&gt;
        //     return floorMultiplication(&lt;br /&gt;
        //       5 * lv + 2 * int + (7 * int + 8 * mav + 4 * str + 2 * vit + variation) * skillPower,&lt;br /&gt;
        //       1&lt;br /&gt;
        //     );&lt;br /&gt;
        //   };&lt;br /&gt;
        //   skillInfo.range = [180, 100];&lt;br /&gt;
        //   improvedByBonus = true;&lt;br /&gt;
        //   break;&lt;br /&gt;
        // Esprit de flammes&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              30 +&lt;br /&gt;
                2 * lv +&lt;br /&gt;
                2 * int +&lt;br /&gt;
                (7 * int + 6 * mav + variation) * attackFactor * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [200, 500];&lt;br /&gt;
          break;&lt;br /&gt;
        // Frappe de l'esprit&lt;br /&gt;
        // case 5:&lt;br /&gt;
        //   skillFormula = function (mav, variation) {&lt;br /&gt;
        //     return floorMultiplication(&lt;br /&gt;
        //       40 + 2 * lv + 2 * int + (2 * vit + 2 * dex + 13 * int + 6 * mav + variation) * attackFactor * skillPower,&lt;br /&gt;
        //       1&lt;br /&gt;
        //     );&lt;br /&gt;
        //   };&lt;br /&gt;
        //   skillInfo.range = [180, 200];&lt;br /&gt;
        //   break;&lt;br /&gt;
        // Orbe des ténèbres&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (mav) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              120 +&lt;br /&gt;
                6 * lv +&lt;br /&gt;
                (5 * vit + 5 * dex + 29 * int + 9 * mav) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Vague mortelle&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              120 +&lt;br /&gt;
                6 * lv +&lt;br /&gt;
                (5 * vit + 5 * dex + 30 * int + variation + 9 * mav) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;dragon&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Talisman volant&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (mav) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              70 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                (18 * int + 7 * str + 5 * mav + 50) * attackFactor * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [4, 10];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Dragon chassant&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (mav) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              60 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                (16 * int + 6 * dex + 6 * mav + 120) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [4, 10];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Rugissement du dragon&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (mav) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              70 +&lt;br /&gt;
                3 * lv +&lt;br /&gt;
                (20 * int + 3 * str + 10 * mav + 100) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [4, 10];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Météore&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              120 +&lt;br /&gt;
                6 * lv +&lt;br /&gt;
                (5 * vit + 5 * dex + 30 * int + variation + 9 * mav) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;heal&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Jet de foudre&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              60 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                (8 * int + 2 * dex + 8 * mav + variation) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [6, 10];&lt;br /&gt;
          skillInfo.range = [5 * int, 15 * int];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Invocation de foudre&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              40 +&lt;br /&gt;
                4 * lv +&lt;br /&gt;
                (13 * int + 2 * str + 10 * mav + variation) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [6, 10];&lt;br /&gt;
          skillInfo.range = [5 * int, 16 * int];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Griffe de foudre&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              50 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                (8 * int + 2 * str + 8 * mav + variation) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 800];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;lycan&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Déchiqueter&lt;br /&gt;
        // case 1:&lt;br /&gt;
        //   skillFormula = function (atk) {&lt;br /&gt;
        //     return floorMultiplication(&lt;br /&gt;
        //       1.1 * atk + (0.3 * atk + 1.5 * str) * skillPower,&lt;br /&gt;
        //       1&lt;br /&gt;
        //     );&lt;br /&gt;
        //   };&lt;br /&gt;
        //   skillInfo.weaponBonus = [5, 54];&lt;br /&gt;
        //   improvedByBonus = true;&lt;br /&gt;
        //   break;&lt;br /&gt;
        // Souffle de loup&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * atk + (atk + 3 * dex + 5 * str + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [5, 35];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Bond de loup&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk + (1.6 * atk + 200 + 7 * dex + 7 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [5, 35];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Griffe de loup&lt;br /&gt;
        case 4:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              3 * atk + (0.8 * atk + 6 * str + 2 * dex + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Tempête cinglante&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.8 * atk +&lt;br /&gt;
                (atk + 6 * dex + variation + 3 * str + lv) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
    if (improvedBySkillBonus) {&lt;br /&gt;
      skillInfo.skillBonus =&lt;br /&gt;
        16 * getSkillPower(attacker.skillBonus, skillPowerTable);&lt;br /&gt;
&lt;br /&gt;
      var skillWardChoice = victim.skillWardChoice;&lt;br /&gt;
&lt;br /&gt;
      if (skillWardChoice &amp;amp;&amp;amp; skillWardChoice === attackerClass) {&lt;br /&gt;
        skillInfo.skillWard =&lt;br /&gt;
          24 * getSkillPower(victim.skillWard, skillPowerTable);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (improvedByBonus) {&lt;br /&gt;
      skillInfo.skillBonusByBonus = attacker[&amp;quot;skillBonus&amp;quot; + skillId];&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (removeSkillVariation) {&lt;br /&gt;
      var averageVariation = (skillInfo.range[0] + skillInfo.range[0]) / 2;&lt;br /&gt;
      skillInfo.range = [averageVariation, averageVariation];&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    var skillPower = getSkillPower(&lt;br /&gt;
      attacker[&amp;quot;horseSkill&amp;quot; + skillId],&lt;br /&gt;
      skillPowerTable&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    switch (skillId) {&lt;br /&gt;
      // Combat équestre&lt;br /&gt;
      case 137:&lt;br /&gt;
        skillFormula = function (atk) {&lt;br /&gt;
          return floorMultiplication(atk + 2 * atk * skillPower, 1);&lt;br /&gt;
        };&lt;br /&gt;
        break;&lt;br /&gt;
      // Charge à cheval&lt;br /&gt;
      case 138:&lt;br /&gt;
        skillFormula = function (atk) {&lt;br /&gt;
          return floorMultiplication(&lt;br /&gt;
            2.4 * (200 + 1.5 * lv) + 600 * skillPower,&lt;br /&gt;
            1&lt;br /&gt;
          );&lt;br /&gt;
        };&lt;br /&gt;
        break;&lt;br /&gt;
      // Vague de Pouvoir&lt;br /&gt;
      case 139:&lt;br /&gt;
        skillFormula = function (atk) {&lt;br /&gt;
          return floorMultiplication(&lt;br /&gt;
            2 * (200 + 1.5 * lv) + 600 * skillPower,&lt;br /&gt;
            1&lt;br /&gt;
          );&lt;br /&gt;
        };&lt;br /&gt;
        break;&lt;br /&gt;
      // Grêle de flèches&lt;br /&gt;
      case 140:&lt;br /&gt;
        skillFormula = function (atk) {&lt;br /&gt;
          return floorMultiplication(atk + 2 * atk * skillPower, 1);&lt;br /&gt;
        };&lt;br /&gt;
        break;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  updateBattleValues(battleValues, skillFormula, skillInfo);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcMagicAttackValueAugmentation(&lt;br /&gt;
  magicAttackValueWeapon,&lt;br /&gt;
  magicAttackValueBonus&lt;br /&gt;
) {&lt;br /&gt;
  if (magicAttackValueBonus) {&lt;br /&gt;
    return Math.max(&lt;br /&gt;
      1,&lt;br /&gt;
      0.0025056 *&lt;br /&gt;
        magicAttackValueBonus ** 0.602338 *&lt;br /&gt;
        magicAttackValueWeapon ** 1.20476&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
  return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getMagicAttackValueAugmentation(&lt;br /&gt;
  minMagicAttackValue,&lt;br /&gt;
  maxMagicAttackValue,&lt;br /&gt;
  magicAttackValueBonus&lt;br /&gt;
) {&lt;br /&gt;
  var magicAttackValueAugmentation = [];&lt;br /&gt;
&lt;br /&gt;
  for (&lt;br /&gt;
    var magicAttackValue = minMagicAttackValue;&lt;br /&gt;
    magicAttackValue &amp;lt;= maxMagicAttackValue;&lt;br /&gt;
    magicAttackValue++&lt;br /&gt;
  ) {&lt;br /&gt;
    magicAttackValueAugmentation.push(&lt;br /&gt;
      calcMagicAttackValueAugmentation(magicAttackValue, magicAttackValueBonus)&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return magicAttackValueAugmentation;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcPhysicalDamage(battleValues) {&lt;br /&gt;
  var {&lt;br /&gt;
    attackFactor,&lt;br /&gt;
    mainAttackValue,&lt;br /&gt;
    attackValues: { minAttackValue, maxAttackValue, attackValueOther, weights },&lt;br /&gt;
    bonusValues,&lt;br /&gt;
    damageTypeCombinaison,&lt;br /&gt;
  } = battleValues;&lt;br /&gt;
&lt;br /&gt;
  var damageWeightedByType = {};&lt;br /&gt;
&lt;br /&gt;
  if (bonusValues.missPercentage) {&lt;br /&gt;
    damageWeightedByType.miss = bonusValues.missPercentage / 100;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (var damageType of damageTypeCombinaison) {&lt;br /&gt;
    if (!damageType.weight) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var damageWeighted = {};&lt;br /&gt;
    damageWeightedByType[damageType.name] = damageWeighted;&lt;br /&gt;
&lt;br /&gt;
    for (&lt;br /&gt;
      var attackValue = minAttackValue;&lt;br /&gt;
      attackValue &amp;lt;= maxAttackValue;&lt;br /&gt;
      attackValue++&lt;br /&gt;
    ) {&lt;br /&gt;
      var weight = weights[attackValue - minAttackValue] * damageType.weight;&lt;br /&gt;
&lt;br /&gt;
      var secondaryAttackValue = 2 * attackValue + attackValueOther;&lt;br /&gt;
      var rawDamage =&lt;br /&gt;
        mainAttackValue +&lt;br /&gt;
        floorMultiplication(attackFactor, secondaryAttackValue);&lt;br /&gt;
&lt;br /&gt;
      var damageWithPrimaryBonuses = calcDamageWithPrimaryBonuses(&lt;br /&gt;
        rawDamage,&lt;br /&gt;
        bonusValues&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      var minPiercingDamage =&lt;br /&gt;
        damageWithPrimaryBonuses -&lt;br /&gt;
        bonusValues.defenseBoost -&lt;br /&gt;
        bonusValues.defenseMarriage;&lt;br /&gt;
&lt;br /&gt;
      if (minPiercingDamage &amp;lt;= 2) {&lt;br /&gt;
        for (var damage = 1; damage &amp;lt;= 5; damage++) {&lt;br /&gt;
          var finalDamage = calcDamageWithSecondaryBonuses(&lt;br /&gt;
            damage,&lt;br /&gt;
            bonusValues,&lt;br /&gt;
            damageType,&lt;br /&gt;
            minPiercingDamage,&lt;br /&gt;
            damageWithPrimaryBonuses&lt;br /&gt;
          );&lt;br /&gt;
&lt;br /&gt;
          addKeyValue(damageWeighted, finalDamage, weight / 5);&lt;br /&gt;
        }&lt;br /&gt;
      } else {&lt;br /&gt;
        var finalDamage = calcDamageWithSecondaryBonuses(&lt;br /&gt;
          minPiercingDamage,&lt;br /&gt;
          bonusValues,&lt;br /&gt;
          damageType,&lt;br /&gt;
          minPiercingDamage,&lt;br /&gt;
          damageWithPrimaryBonuses&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        addKeyValue(damageWeighted, finalDamage, weight);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return damageWeightedByType;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcPhysicalSkillDamage(battleValues) {&lt;br /&gt;
  var {&lt;br /&gt;
    attackFactor,&lt;br /&gt;
    mainAttackValue,&lt;br /&gt;
    attackValues: { minAttackValue, maxAttackValue, attackValueOther, weights },&lt;br /&gt;
    bonusValues,&lt;br /&gt;
    damageTypeCombinaison,&lt;br /&gt;
    skillFormula,&lt;br /&gt;
    skillRange: [minVariation, maxVariation],&lt;br /&gt;
  } = battleValues;&lt;br /&gt;
&lt;br /&gt;
  var damageWeightedByType = {};&lt;br /&gt;
&lt;br /&gt;
  for (var damageType of damageTypeCombinaison) {&lt;br /&gt;
    if (!damageType.weight) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var damageWeighted = {};&lt;br /&gt;
    var savedDamage = {};&lt;br /&gt;
&lt;br /&gt;
    damageWeightedByType[damageType.name] = damageWeighted;&lt;br /&gt;
&lt;br /&gt;
    for (&lt;br /&gt;
      var attackValue = minAttackValue;&lt;br /&gt;
      attackValue &amp;lt;= maxAttackValue;&lt;br /&gt;
      attackValue++&lt;br /&gt;
    ) {&lt;br /&gt;
      var weight = weights[attackValue - minAttackValue] * damageType.weight;&lt;br /&gt;
&lt;br /&gt;
      var secondaryAttackValue = 2 * attackValue + attackValueOther;&lt;br /&gt;
      var rawDamage =&lt;br /&gt;
        mainAttackValue +&lt;br /&gt;
        floorMultiplication(attackFactor, secondaryAttackValue);&lt;br /&gt;
&lt;br /&gt;
      var damageWithPrimaryBonuses = calcDamageWithPrimaryBonuses(&lt;br /&gt;
        rawDamage,&lt;br /&gt;
        bonusValues&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      for (&lt;br /&gt;
        var variation = minVariation;&lt;br /&gt;
        variation &amp;lt;= maxVariation;&lt;br /&gt;
        variation++&lt;br /&gt;
      ) {&lt;br /&gt;
        if (damageWithPrimaryBonuses &amp;lt;= 2) {&lt;br /&gt;
          for (var damage = 1; damage &amp;lt;= 5; damage++) {&lt;br /&gt;
            var damageWithFormula = skillFormula(&lt;br /&gt;
              damage * bonusValues.useDamage,&lt;br /&gt;
              variation&lt;br /&gt;
            );&lt;br /&gt;
&lt;br /&gt;
            damageWithFormula = Math.floor(&lt;br /&gt;
              (damageWithFormula * bonusValues.weaponBonusCoeff) / 100&lt;br /&gt;
            );&lt;br /&gt;
&lt;br /&gt;
            var finalDamage = calcSkillDamageWithSecondaryBonuses(&lt;br /&gt;
              damageWithFormula,&lt;br /&gt;
              bonusValues,&lt;br /&gt;
              damageType,&lt;br /&gt;
              damageWithPrimaryBonuses&lt;br /&gt;
            );&lt;br /&gt;
&lt;br /&gt;
            addKeyValue(damageWeighted, finalDamage, weight / 5);&lt;br /&gt;
          }&lt;br /&gt;
        } else {&lt;br /&gt;
          var damageWithFormula = skillFormula(&lt;br /&gt;
            damageWithPrimaryBonuses * bonusValues.useDamage,&lt;br /&gt;
            variation&lt;br /&gt;
          );&lt;br /&gt;
&lt;br /&gt;
          if (savedDamage.hasOwnProperty(damageWithFormula)) {&lt;br /&gt;
            var finalDamage = savedDamage[damageWithFormula];&lt;br /&gt;
            damageWeighted[finalDamage] += weight;&lt;br /&gt;
            continue;&lt;br /&gt;
          }&lt;br /&gt;
&lt;br /&gt;
          var finalDamage = Math.floor(&lt;br /&gt;
            (damageWithFormula * bonusValues.weaponBonusCoeff) / 100&lt;br /&gt;
          );&lt;br /&gt;
&lt;br /&gt;
          finalDamage = calcSkillDamageWithSecondaryBonuses(&lt;br /&gt;
            finalDamage,&lt;br /&gt;
            bonusValues,&lt;br /&gt;
            damageType,&lt;br /&gt;
            damageWithPrimaryBonuses&lt;br /&gt;
          );&lt;br /&gt;
&lt;br /&gt;
          savedDamage[damageWithFormula] = finalDamage;&lt;br /&gt;
          addKeyValue(damageWeighted, finalDamage, weight);&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return damageWeightedByType;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcMagicSkillDamage(battleValues) {&lt;br /&gt;
  var {&lt;br /&gt;
    attackValues: {&lt;br /&gt;
      minMagicAttackValue,&lt;br /&gt;
      maxMagicAttackValue,&lt;br /&gt;
      magicAttackValueAugmentation,&lt;br /&gt;
      weights,&lt;br /&gt;
    },&lt;br /&gt;
    bonusValues,&lt;br /&gt;
    damageTypeCombinaison,&lt;br /&gt;
    skillFormula,&lt;br /&gt;
    skillRange: [minVariation, maxVariation],&lt;br /&gt;
  } = battleValues;&lt;br /&gt;
&lt;br /&gt;
  var damageWeightedByType = {};&lt;br /&gt;
&lt;br /&gt;
  for (var damageType of damageTypeCombinaison) {&lt;br /&gt;
    if (!damageType.weight) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var damageWeighted = {};&lt;br /&gt;
    var savedDamage = {};&lt;br /&gt;
&lt;br /&gt;
    damageWeightedByType[damageType.name] = damageWeighted;&lt;br /&gt;
&lt;br /&gt;
    for (&lt;br /&gt;
      var magicAttackValue = minMagicAttackValue;&lt;br /&gt;
      magicAttackValue &amp;lt;= maxMagicAttackValue;&lt;br /&gt;
      magicAttackValue++&lt;br /&gt;
    ) {&lt;br /&gt;
      var index = magicAttackValue - minMagicAttackValue;&lt;br /&gt;
      var weight = weights[index] * damageType.weight;&lt;br /&gt;
&lt;br /&gt;
      for (&lt;br /&gt;
        var variation = minVariation;&lt;br /&gt;
        variation &amp;lt;= maxVariation;&lt;br /&gt;
        variation++&lt;br /&gt;
      ) {&lt;br /&gt;
        var rawDamage = skillFormula(&lt;br /&gt;
          magicAttackValue + magicAttackValueAugmentation[index],&lt;br /&gt;
          variation&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        if (savedDamage.hasOwnProperty(rawDamage)) {&lt;br /&gt;
          var finalDamage = savedDamage[rawDamage];&lt;br /&gt;
          damageWeighted[finalDamage] += weight;&lt;br /&gt;
          continue;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var damageWithPrimaryBonuses = Math.floor(&lt;br /&gt;
          (rawDamage * bonusValues.weaponBonusCoeff) / 100&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        damageWithPrimaryBonuses = calcDamageWithPrimaryBonuses(&lt;br /&gt;
          damageWithPrimaryBonuses,&lt;br /&gt;
          bonusValues&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        if (damageWithPrimaryBonuses &amp;lt;= 2) {&lt;br /&gt;
          for (var damage = 1; damage &amp;lt;= 5; damage++) {&lt;br /&gt;
            var finalDamage = calcSkillDamageWithSecondaryBonuses(&lt;br /&gt;
              damage,&lt;br /&gt;
              bonusValues,&lt;br /&gt;
              damageType,&lt;br /&gt;
              damageWithPrimaryBonuses&lt;br /&gt;
            );&lt;br /&gt;
            addKeyValue(damageWeighted, finalDamage, weight / 5);&lt;br /&gt;
          }&lt;br /&gt;
        } else {&lt;br /&gt;
          var finalDamage = calcSkillDamageWithSecondaryBonuses(&lt;br /&gt;
            damageWithPrimaryBonuses,&lt;br /&gt;
            bonusValues,&lt;br /&gt;
            damageType,&lt;br /&gt;
            damageWithPrimaryBonuses&lt;br /&gt;
          );&lt;br /&gt;
&lt;br /&gt;
          savedDamage[rawDamage] = finalDamage;&lt;br /&gt;
          addKeyValue(damageWeighted, finalDamage, weight);&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return damageWeightedByType;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcDamage(&lt;br /&gt;
  attacker,&lt;br /&gt;
  victim,&lt;br /&gt;
  attackType,&lt;br /&gt;
  battle,&lt;br /&gt;
  removeSkillVariation&lt;br /&gt;
) {&lt;br /&gt;
  var damageCalculator, skillId, skillType;&lt;br /&gt;
&lt;br /&gt;
  if (attackType === &amp;quot;physical&amp;quot;) {&lt;br /&gt;
    damageCalculator = calcPhysicalDamage;&lt;br /&gt;
  } else if (attackType.startsWith(&amp;quot;attackSkill&amp;quot;)) {&lt;br /&gt;
    skillId = Number(attackType.split(&amp;quot;attackSkill&amp;quot;)[1]);&lt;br /&gt;
&lt;br /&gt;
    if (isMagicClass(attacker) || isDispell(attacker, skillId)) {&lt;br /&gt;
      skillType = &amp;quot;magic&amp;quot;;&lt;br /&gt;
      damageCalculator = calcMagicSkillDamage;&lt;br /&gt;
    } else {&lt;br /&gt;
      skillType = &amp;quot;physical&amp;quot;;&lt;br /&gt;
      damageCalculator = calcPhysicalSkillDamage;&lt;br /&gt;
    }&lt;br /&gt;
  } else if (attackType.startsWith(&amp;quot;horseSkill&amp;quot;)) {&lt;br /&gt;
    skillType = &amp;quot;physical&amp;quot;;&lt;br /&gt;
    skillId = Number(attackType.split(&amp;quot;horseSkill&amp;quot;)[1]);&lt;br /&gt;
    damageCalculator = calcPhysicalSkillDamage;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var battleValues = createBattleValues(attacker, victim, battle, skillType);&lt;br /&gt;
&lt;br /&gt;
  if (skillId) {&lt;br /&gt;
    getSkillFormula(battle, skillId, battleValues, removeSkillVariation);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var {&lt;br /&gt;
    attackValues: { totalCardinal, possibleDamageCount },&lt;br /&gt;
  } = battleValues;&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    damageWeightedByType: damageCalculator(battleValues),&lt;br /&gt;
    totalCardinal: totalCardinal,&lt;br /&gt;
    possibleDamageCount: possibleDamageCount,&lt;br /&gt;
    skillType: skillType,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function damageWithoutVariation(&lt;br /&gt;
  attacker,&lt;br /&gt;
  victim,&lt;br /&gt;
  attackType,&lt;br /&gt;
  battle,&lt;br /&gt;
  characters&lt;br /&gt;
) {&lt;br /&gt;
  var startDamageTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
  var {&lt;br /&gt;
    damageWeightedByType,&lt;br /&gt;
    totalCardinal,&lt;br /&gt;
    possibleDamageCount,&lt;br /&gt;
    skillType,&lt;br /&gt;
  } = calcDamage(attacker, victim, attackType, battle);&lt;br /&gt;
&lt;br /&gt;
  var endDamageTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
  possibleDamageCount = displayResults(&lt;br /&gt;
    possibleDamageCount,&lt;br /&gt;
    totalCardinal,&lt;br /&gt;
    damageWeightedByType,&lt;br /&gt;
    battle,&lt;br /&gt;
    attacker.name,&lt;br /&gt;
    victim.name&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  var endDisplayTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
  displayFightInfo(&lt;br /&gt;
    possibleDamageCount,&lt;br /&gt;
    endDamageTime - startDamageTime,&lt;br /&gt;
    endDisplayTime - endDamageTime,&lt;br /&gt;
    battle&lt;br /&gt;
  );&lt;br /&gt;
  addPotentialErrorInformation(&lt;br /&gt;
    battle.errorInformation,&lt;br /&gt;
    attacker,&lt;br /&gt;
    victim,&lt;br /&gt;
    skillType,&lt;br /&gt;
    characters&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  hideElement(battle.bonusVariationResultContainer);&lt;br /&gt;
  showElement(battle.fightResultTitle);&lt;br /&gt;
  showElement(battle.fightResultContainer);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function damageWithVariation(&lt;br /&gt;
  attacker,&lt;br /&gt;
  victim,&lt;br /&gt;
  attackType,&lt;br /&gt;
  battle,&lt;br /&gt;
  entity,&lt;br /&gt;
  entityVariation&lt;br /&gt;
) {&lt;br /&gt;
  var startTime = performance.now();&lt;br /&gt;
  var damageByBonus = [];&lt;br /&gt;
  var augmentationByBonus = [];&lt;br /&gt;
  var {&lt;br /&gt;
    bonusVariationMinValue: minVariation,&lt;br /&gt;
    bonusVariationMaxValue: maxVariation,&lt;br /&gt;
  } = entity;&lt;br /&gt;
  var step = Math.ceil((maxVariation - minVariation + 1) / 500);&lt;br /&gt;
  var simulationCount = 0;&lt;br /&gt;
  var simulationTime;&lt;br /&gt;
  var firstDamage = 1;&lt;br /&gt;
&lt;br /&gt;
  for (&lt;br /&gt;
    var bonusValue = minVariation;&lt;br /&gt;
    bonusValue &amp;lt;= maxVariation;&lt;br /&gt;
    bonusValue += step&lt;br /&gt;
  ) {&lt;br /&gt;
    entity[entityVariation] = bonusValue;&lt;br /&gt;
&lt;br /&gt;
    var { damageWeightedByType, totalCardinal } = calcDamage(&lt;br /&gt;
      copyObject(attacker),&lt;br /&gt;
      copyObject(victim),&lt;br /&gt;
      attackType,&lt;br /&gt;
      battle,&lt;br /&gt;
      true&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    var meanDamage = calcMeanDamage(damageWeightedByType, totalCardinal);&lt;br /&gt;
&lt;br /&gt;
    if (bonusValue === minVariation) {&lt;br /&gt;
      firstDamage = Math.max(meanDamage, 1e-3);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    damageByBonus.push({ x: bonusValue, y: meanDamage });&lt;br /&gt;
    augmentationByBonus.push({&lt;br /&gt;
      x: bonusValue,&lt;br /&gt;
      y: meanDamage / firstDamage - 1,&lt;br /&gt;
    });&lt;br /&gt;
    simulationCount++;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var endTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
  battle.damageByBonus = damageByBonus.concat(entityVariation);&lt;br /&gt;
&lt;br /&gt;
  addToBonusVariationChart(&lt;br /&gt;
    damageByBonus,&lt;br /&gt;
    augmentationByBonus,&lt;br /&gt;
    entity.bonusVariationName,&lt;br /&gt;
    battle.bonusVariationChart&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  simulationCount = battle.numberFormats.default.format(simulationCount);&lt;br /&gt;
  simulationTime = battle.numberFormats.second.format(&lt;br /&gt;
    (endTime - startTime) / 1000&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  battle.simulationCounter.textContent = simulationCount;&lt;br /&gt;
  battle.simulationTime.textContent = simulationTime;&lt;br /&gt;
&lt;br /&gt;
  hideElement(battle.fightResultContainer);&lt;br /&gt;
  showElement(battle.fightResultTitle);&lt;br /&gt;
  showElement(battle.bonusVariationResultContainer);&lt;br /&gt;
&lt;br /&gt;
  if (&lt;br /&gt;
    isChecked(attacker.useBonusVariation) &amp;amp;&amp;amp;&lt;br /&gt;
    isChecked(victim.useBonusVariation)&lt;br /&gt;
  ) {&lt;br /&gt;
    showElement(battle.errorInformation[&amp;quot;attacker-victim-variation&amp;quot;]);&lt;br /&gt;
  } else {&lt;br /&gt;
    hideElement(battle.errorInformation[&amp;quot;attacker-victim-variation&amp;quot;]);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function changeMonsterValues(monster, instance, attacker) {&lt;br /&gt;
  switch (instance) {&lt;br /&gt;
    case &amp;quot;SungMahiTower&amp;quot;:&lt;br /&gt;
      var sungMahiFloor = 1;&lt;br /&gt;
      var sungMahiStep = 1;&lt;br /&gt;
      var rawDefense = 120;&lt;br /&gt;
&lt;br /&gt;
      if (isPC(attacker)) {&lt;br /&gt;
        sungMahiFloor = attacker.sungMahiFloor;&lt;br /&gt;
        sungMahiStep = attacker.sungMahiStep;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (monster.rank === 5) {&lt;br /&gt;
        monster.level = 121;&lt;br /&gt;
        monster.dex = 75;&lt;br /&gt;
        rawDefense += 1;&lt;br /&gt;
      } else if (monster.rank === 6) {&lt;br /&gt;
        monster.level = 123;&lt;br /&gt;
        monster.dex = 75;&lt;br /&gt;
        rawDefense += 1;&lt;br /&gt;
      } else {&lt;br /&gt;
        monster.level = 120;&lt;br /&gt;
        monster.dex = 68;&lt;br /&gt;
      }&lt;br /&gt;
      monster.vit = 100;&lt;br /&gt;
      monster.rawDefense = rawDefense + (sungMahiStep - 1) * 6;&lt;br /&gt;
      monster.fistDefense = 0;&lt;br /&gt;
      monster.swordDefense = 0;&lt;br /&gt;
      monster.twoHandedSwordDefense = 0;&lt;br /&gt;
      monster.daggerDefense = 0;&lt;br /&gt;
      monster.bellDefense = 0;&lt;br /&gt;
      monster.fanDefense = 0;&lt;br /&gt;
      monster.arrowDefense = 0;&lt;br /&gt;
      monster.clawDefense = 0;&lt;br /&gt;
      monster.magicResistance = 0;&lt;br /&gt;
      monster.fireResistance = -20;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  // Alastor&lt;br /&gt;
  if (monster.vnum === 6790) {&lt;br /&gt;
    monster.iceResistance = 0;&lt;br /&gt;
    monster.iceBonus = 0;&lt;br /&gt;
    monster.lightningResistance = -10;&lt;br /&gt;
    monster.lightningBonus = 65;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createWeapon(vnum) {&lt;br /&gt;
  var weapon = copyObject(weaponData[vnum]);&lt;br /&gt;
  var serpentVnums = [360, 380, 1210, 2230, 3250, 5200, 6150, 7330];&lt;br /&gt;
  var weaponValues = weapon[1];&lt;br /&gt;
  var isSerpent = isValueInArray(Number(vnum), serpentVnums);&lt;br /&gt;
  var isSpecial = Array.isArray(weaponValues[0]);&lt;br /&gt;
  var isMagic;&lt;br /&gt;
&lt;br /&gt;
  if (isSpecial) {&lt;br /&gt;
    isMagic = weaponValues[0][1] &amp;gt; 0;&lt;br /&gt;
  } else {&lt;br /&gt;
    isMagic = weaponValues[1] &amp;gt; 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    type: weapon[0],&lt;br /&gt;
    maxUpgrade: weapon[2].length - 1,&lt;br /&gt;
    isSerpent: isSerpent,&lt;br /&gt;
    isMagic: isMagic,&lt;br /&gt;
    getValues: function (upgrade) {&lt;br /&gt;
      var currentWeaponValues = weaponValues;&lt;br /&gt;
&lt;br /&gt;
      if (upgrade === undefined) {&lt;br /&gt;
        // rare bug when weaponUpgrade is deleted&lt;br /&gt;
        console.warn(&amp;quot;WeaponUpgrade is missing.&amp;quot;);&lt;br /&gt;
        upgrade = this.maxUpgrade;&lt;br /&gt;
      }&lt;br /&gt;
      upgrade = Math.min(upgrade, this.maxUpgrade);&lt;br /&gt;
&lt;br /&gt;
      if (isSpecial) {&lt;br /&gt;
        currentWeaponValues = weaponValues[upgrade];&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      this.minAttackValue = currentWeaponValues[2];&lt;br /&gt;
      this.maxAttackValue = currentWeaponValues[3];&lt;br /&gt;
      this.minMagicAttackValue = currentWeaponValues[0];&lt;br /&gt;
      this.maxMagicAttackValue = currentWeaponValues[1];&lt;br /&gt;
      this.growth = weapon[2][upgrade];&lt;br /&gt;
    },&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createMonster(monsterVnum, attacker, polymorphMonster) {&lt;br /&gt;
  var monsterAttributes = monsterData[monsterVnum];&lt;br /&gt;
&lt;br /&gt;
  var monster = {&lt;br /&gt;
    vnum: Number(monsterVnum),&lt;br /&gt;
    name: monsterAttributes[36],&lt;br /&gt;
    rank: monsterAttributes[0],&lt;br /&gt;
    race: monsterAttributes[1],&lt;br /&gt;
    attack: monsterAttributes[2],&lt;br /&gt;
    level: monsterAttributes[3],&lt;br /&gt;
    type: monsterAttributes[4],&lt;br /&gt;
    str: monsterAttributes[5],&lt;br /&gt;
    dex: monsterAttributes[6],&lt;br /&gt;
    vit: monsterAttributes[7],&lt;br /&gt;
    int: monsterAttributes[8],&lt;br /&gt;
    minAttackValue: monsterAttributes[9],&lt;br /&gt;
    maxAttackValue: monsterAttributes[10],&lt;br /&gt;
    rawDefense: monsterAttributes[11],&lt;br /&gt;
    criticalHit: monsterAttributes[12],&lt;br /&gt;
    piercingHit: monsterAttributes[13],&lt;br /&gt;
    fistDefense: monsterAttributes[14],&lt;br /&gt;
    swordDefense: monsterAttributes[15],&lt;br /&gt;
    twoHandedSwordDefense: monsterAttributes[16],&lt;br /&gt;
    daggerDefense: monsterAttributes[17],&lt;br /&gt;
    bellDefense: monsterAttributes[18],&lt;br /&gt;
    fanDefense: monsterAttributes[19],&lt;br /&gt;
    arrowDefense: monsterAttributes[20],&lt;br /&gt;
    clawDefense: monsterAttributes[21],&lt;br /&gt;
    fireResistance: monsterAttributes[22],&lt;br /&gt;
    lightningResistance: monsterAttributes[23],&lt;br /&gt;
    magicResistance: monsterAttributes[24],&lt;br /&gt;
    windResistance: monsterAttributes[25],&lt;br /&gt;
    lightningBonus: monsterAttributes[26],&lt;br /&gt;
    fireBonus: monsterAttributes[27],&lt;br /&gt;
    iceBonus: monsterAttributes[28],&lt;br /&gt;
    windBonus: monsterAttributes[29],&lt;br /&gt;
    earthBonus: monsterAttributes[30],&lt;br /&gt;
    darknessBonus: monsterAttributes[31],&lt;br /&gt;
    darknessResistance: monsterAttributes[32],&lt;br /&gt;
    iceResistance: monsterAttributes[33],&lt;br /&gt;
    earthResistance: monsterAttributes[34],&lt;br /&gt;
    damageMultiplier: monsterAttributes[35],&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  // monster.instance = 0;&lt;br /&gt;
&lt;br /&gt;
  // if (attacker &amp;amp;&amp;amp; monster.instance === 0) {&lt;br /&gt;
  //   changeMonsterValues(monster, &amp;quot;SungMahiTower&amp;quot;, attacker);&lt;br /&gt;
  // }&lt;br /&gt;
  if (!polymorphMonster) {&lt;br /&gt;
    changeMonsterValues(monster);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  monster.defense = monster.rawDefense + monster.level + monster.vit;&lt;br /&gt;
&lt;br /&gt;
  return monster;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addPotentialErrorInformation(&lt;br /&gt;
  errorInformation,&lt;br /&gt;
  attacker,&lt;br /&gt;
  victim,&lt;br /&gt;
  skillType,&lt;br /&gt;
  characters&lt;br /&gt;
) {&lt;br /&gt;
  for (var error of Object.values(errorInformation)) {&lt;br /&gt;
    hideElement(error);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker)) {&lt;br /&gt;
    if (isRiding(attacker)) {&lt;br /&gt;
      if (attacker.horsePoint === 0) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;horse-level&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
      showElement(errorInformation[&amp;quot;horse-stat&amp;quot;]);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isPolymorph(attacker)) {&lt;br /&gt;
      if (attacker.polymorphPoint === 0) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;polymorph-level&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (&lt;br /&gt;
        (attacker.polymorphPoint &amp;lt;= 39 &amp;amp;&amp;amp; attacker.attackValuePercent &amp;lt;= 199) ||&lt;br /&gt;
        (attacker.polymorphPoint === 40 &amp;amp;&amp;amp; attacker.attackValuePercent &amp;lt;= 299)&lt;br /&gt;
      ) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;polymorph-bonus&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
    if (skillType === &amp;quot;magic&amp;quot;) {&lt;br /&gt;
      if (attacker.magicAttackValue) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;magic-attack-value-bonus&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
      if (victim.magicResistance) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;magic-resistance&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    showElement(errorInformation[&amp;quot;monster-attacker&amp;quot;]);&lt;br /&gt;
    if (isMagicAttacker(attacker) &amp;amp;&amp;amp; victim.magicResistance) {&lt;br /&gt;
      showElement(errorInformation[&amp;quot;magic-resistance&amp;quot;]);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (isPC(victim)) {&lt;br /&gt;
    if (isRiding(victim)) {&lt;br /&gt;
      showElement(errorInformation[&amp;quot;horse-stat&amp;quot;]);&lt;br /&gt;
    }&lt;br /&gt;
    if (isPolymorph(victim)) {&lt;br /&gt;
      if (attacker.polymorphPoint === 0) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;polymorph-level&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
      showElement(errorInformation[&amp;quot;polymorph-defense&amp;quot;]);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (characters.unsavedChanges) {&lt;br /&gt;
    showElement(errorInformation[&amp;quot;save&amp;quot;]);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function reduceChartPointsListener(battle) {&lt;br /&gt;
  var {&lt;br /&gt;
    reduceChartPointsContainer,&lt;br /&gt;
    reduceChartPoints,&lt;br /&gt;
    numberFormats: { second: numberFormat },&lt;br /&gt;
    displayTime,&lt;br /&gt;
  } = battle;&lt;br /&gt;
&lt;br /&gt;
  reduceChartPoints.addEventListener(&amp;quot;change&amp;quot;, function () {&lt;br /&gt;
    reduceChartPoints.disabled = true;&lt;br /&gt;
&lt;br /&gt;
    var startDisplayTime = performance.now();&lt;br /&gt;
    var scatterDataByType = battle.scatterDataByType;&lt;br /&gt;
    var {&lt;br /&gt;
      chart,&lt;br /&gt;
      maxPoints,&lt;br /&gt;
      chart: {&lt;br /&gt;
        data: { datasets },&lt;br /&gt;
      },&lt;br /&gt;
    } = battle.damageChart;&lt;br /&gt;
    var addAnimations = false;&lt;br /&gt;
&lt;br /&gt;
    for (var index = 0; index &amp;lt; datasets.length; index++) {&lt;br /&gt;
      var dataset = datasets[index];&lt;br /&gt;
      var scatterData = scatterDataByType[dataset.name];&lt;br /&gt;
&lt;br /&gt;
      if (dataset.canBeReduced &amp;amp;&amp;amp; reduceChartPoints.checked) {&lt;br /&gt;
        dataset.data = aggregateDamage(scatterData, maxPoints);&lt;br /&gt;
        addAnimations = true;&lt;br /&gt;
      } else {&lt;br /&gt;
        dataset.data = scatterData;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    handleChartAnimations(chart, addAnimations);&lt;br /&gt;
    chart.update();&lt;br /&gt;
&lt;br /&gt;
    displayTime.textContent = numberFormat.format(&lt;br /&gt;
      (performance.now() - startDisplayTime) / 1000&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    setTimeout(function () {&lt;br /&gt;
      reduceChartPoints.disabled = false;&lt;br /&gt;
    }, 1000);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  reduceChartPointsContainer.addEventListener(&amp;quot;pointerup&amp;quot;, function (event) {&lt;br /&gt;
    if (event.pointerType === &amp;quot;mouse&amp;quot;) {&lt;br /&gt;
      if (event.target.closest(&amp;quot;label&amp;quot;)) {&lt;br /&gt;
        return;&lt;br /&gt;
      }&lt;br /&gt;
      reduceChartPoints.click();&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function downloadRawDataListener(battle) {&lt;br /&gt;
  var { downLoadRawData, downLoadRawDataVariation } = battle;&lt;br /&gt;
  var fileType = &amp;quot;text/csv;charset=utf-8;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  downLoadRawData.addEventListener(&amp;quot;click&amp;quot;, function () {&lt;br /&gt;
    var damageWeightedByType = battle.damageWeightedByType;&lt;br /&gt;
    var filename = &amp;quot;raw_damage.csv&amp;quot;;&lt;br /&gt;
    var csvContent = &amp;quot;damage,probabilities,damageType\n&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    for (var damageType in damageWeightedByType) {&lt;br /&gt;
      var damageWeighted = damageWeightedByType[damageType];&lt;br /&gt;
&lt;br /&gt;
      for (var damage in damageWeighted) {&lt;br /&gt;
        csvContent +=&lt;br /&gt;
          damage + &amp;quot;,&amp;quot; + damageWeighted[damage] + &amp;quot;,&amp;quot; + damageType + &amp;quot;\n&amp;quot;;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    downloadData(csvContent, fileType, filename);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  downLoadRawDataVariation.addEventListener(&amp;quot;click&amp;quot;, function () {&lt;br /&gt;
    var damageByBonus = battle.damageByBonus;&lt;br /&gt;
    var damageByBonusLength = damageByBonus.length;&lt;br /&gt;
    var filename = &amp;quot;damage_variation.csv&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    if (!damageByBonusLength) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var csvContent =&lt;br /&gt;
      damageByBonus[damageByBonusLength - 1] + &amp;quot;,averageDamage\n&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    for (var index = 0; index &amp;lt; damageByBonusLength - 1; index++) {&lt;br /&gt;
      var row = damageByBonus[index];&lt;br /&gt;
&lt;br /&gt;
      csvContent += row.x + &amp;quot;,&amp;quot; + row.y + &amp;quot;\n&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    downloadData(csvContent, fileType, filename);&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function displayResults(&lt;br /&gt;
  possibleDamageCount,&lt;br /&gt;
  totalCardinal,&lt;br /&gt;
  damageWeightedByType,&lt;br /&gt;
  battle,&lt;br /&gt;
  attackerName,&lt;br /&gt;
  victimName&lt;br /&gt;
) {&lt;br /&gt;
  var [&lt;br /&gt;
    meanDamage,&lt;br /&gt;
    minDamage,&lt;br /&gt;
    maxDamage,&lt;br /&gt;
    scatterDataByType,&lt;br /&gt;
    possibleDamageCount,&lt;br /&gt;
    uniqueDamageCount,&lt;br /&gt;
  ] = prepareDamageData(&lt;br /&gt;
    damageWeightedByType,&lt;br /&gt;
    possibleDamageCount,&lt;br /&gt;
    totalCardinal&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  addToDamageChart(&lt;br /&gt;
    scatterDataByType,&lt;br /&gt;
    battle.damageChart,&lt;br /&gt;
    battle.reduceChartPoints.checked&lt;br /&gt;
  );&lt;br /&gt;
  updateDamageChartDescription(&lt;br /&gt;
    battle.uniqueDamageCounters,&lt;br /&gt;
    uniqueDamageCount,&lt;br /&gt;
    battle.numberFormats.default&lt;br /&gt;
  );&lt;br /&gt;
  displayFightResults(&lt;br /&gt;
    battle,&lt;br /&gt;
    attackerName,&lt;br /&gt;
    victimName,&lt;br /&gt;
    meanDamage,&lt;br /&gt;
    minDamage,&lt;br /&gt;
    maxDamage&lt;br /&gt;
  );&lt;br /&gt;
  battle.damageWeightedByType = damageWeightedByType;&lt;br /&gt;
  battle.scatterDataByType = scatterDataByType;&lt;br /&gt;
&lt;br /&gt;
  return possibleDamageCount;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function displayFightResults(&lt;br /&gt;
  battle,&lt;br /&gt;
  attackerName,&lt;br /&gt;
  victimName,&lt;br /&gt;
  meanDamage,&lt;br /&gt;
  minDamage,&lt;br /&gt;
  maxDamage&lt;br /&gt;
) {&lt;br /&gt;
  var {&lt;br /&gt;
    tableResultFight,&lt;br /&gt;
    tableResultHistory,&lt;br /&gt;
    savedFights,&lt;br /&gt;
    numberFormats: { default: numberFormat },&lt;br /&gt;
    deleteFightTemplate,&lt;br /&gt;
  } = battle;&lt;br /&gt;
&lt;br /&gt;
  hideElement(tableResultHistory.rows[1]);&lt;br /&gt;
&lt;br /&gt;
  var valuesToDisplay = [&lt;br /&gt;
    attackerName,&lt;br /&gt;
    victimName,&lt;br /&gt;
    battle.battleChoice.attackType.selectedText,&lt;br /&gt;
    meanDamage,&lt;br /&gt;
    minDamage,&lt;br /&gt;
    maxDamage,&lt;br /&gt;
  ];&lt;br /&gt;
&lt;br /&gt;
  savedFights.push(valuesToDisplay);&lt;br /&gt;
  updateSavedFights(savedFights);&lt;br /&gt;
&lt;br /&gt;
  editTableResultRow(tableResultFight.rows[1], valuesToDisplay, numberFormat);&lt;br /&gt;
  addRowToTableResultHistory(&lt;br /&gt;
    tableResultHistory,&lt;br /&gt;
    valuesToDisplay,&lt;br /&gt;
    deleteFightTemplate,&lt;br /&gt;
    numberFormat&lt;br /&gt;
  );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function displayFightInfo(&lt;br /&gt;
  possibleDamageCount,&lt;br /&gt;
  damageTimeDuration,&lt;br /&gt;
  displayTimeDuration,&lt;br /&gt;
  battle&lt;br /&gt;
) {&lt;br /&gt;
  var container = battle.possibleDamageCounter.parentElement;&lt;br /&gt;
&lt;br /&gt;
  if (possibleDamageCount &amp;lt;= 1) {&lt;br /&gt;
    hideElement(container);&lt;br /&gt;
    return;&lt;br /&gt;
  } else {&lt;br /&gt;
    showElement(container);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var { numberFormats, possibleDamageCounter, damageTime, displayTime } =&lt;br /&gt;
    battle;&lt;br /&gt;
&lt;br /&gt;
  possibleDamageCount = numberFormats.default.format(possibleDamageCount);&lt;br /&gt;
  damageTimeDuration = numberFormats.second.format(damageTimeDuration / 1000);&lt;br /&gt;
  displayTimeDuration = numberFormats.second.format(displayTimeDuration / 1000);&lt;br /&gt;
&lt;br /&gt;
  possibleDamageCounter.textContent = possibleDamageCount;&lt;br /&gt;
  damageTime.textContent = damageTimeDuration;&lt;br /&gt;
  displayTime.textContent = displayTimeDuration;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function parseTypeAndName(data) {&lt;br /&gt;
  var [type, nameOrVnum] = splitFirst(data, &amp;quot;-&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    type: type,&lt;br /&gt;
    nameOrVnum: nameOrVnum,&lt;br /&gt;
    isCharacter: type === &amp;quot;character&amp;quot;,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isCharacterSelected(characterName, selected) {&lt;br /&gt;
  if (!selected) {&lt;br /&gt;
    return false;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var { nameOrVnum, isCharacter } = parseTypeAndName(selected);&lt;br /&gt;
&lt;br /&gt;
  return nameOrVnum === characterName &amp;amp;&amp;amp; isCharacter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function useBonusVariationMode(character, variation) {&lt;br /&gt;
  return (&lt;br /&gt;
    isChecked(character.useBonusVariation) &amp;amp;&amp;amp;&lt;br /&gt;
    character.hasOwnProperty(variation) &amp;amp;&amp;amp;&lt;br /&gt;
    character.bonusVariationMinValue &amp;lt; character.bonusVariationMaxValue&lt;br /&gt;
  );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createBattle(characters, battle) {&lt;br /&gt;
  var battleChoice = battle.battleChoice;&lt;br /&gt;
  var battleForm = battleChoice.form;&lt;br /&gt;
  var lastInvalidTime = 0;&lt;br /&gt;
&lt;br /&gt;
  battleForm.addEventListener(&amp;quot;change&amp;quot;, handleBattleFormChange);&lt;br /&gt;
  battleForm.addEventListener(&amp;quot;invalid&amp;quot;, handleBattleFormInvalid, true);&lt;br /&gt;
  battleForm.addEventListener(&amp;quot;submit&amp;quot;, handleBattleFormSubmit);&lt;br /&gt;
&lt;br /&gt;
  function handleBattleFormChange(event) {&lt;br /&gt;
    var target = event.target;&lt;br /&gt;
    var { name: targetName, value: targetValue, type: targetType } = target;&lt;br /&gt;
&lt;br /&gt;
    if (targetType !== &amp;quot;radio&amp;quot;) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (targetName === &amp;quot;attackType&amp;quot;) {&lt;br /&gt;
      battleChoice.attackType.selectedText =&lt;br /&gt;
        target.previousElementSibling.dataset.o;&lt;br /&gt;
    } else {&lt;br /&gt;
      updateBattleChoiceButton(battleChoice, targetName, targetValue);&lt;br /&gt;
&lt;br /&gt;
      if (targetName === &amp;quot;attacker&amp;quot;) {&lt;br /&gt;
        filterAttackTypeSelection(characters, battleChoice, targetValue);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function handleBattleFormInvalid(event) {&lt;br /&gt;
    var currentTime = Date.now();&lt;br /&gt;
&lt;br /&gt;
    if (currentTime - lastInvalidTime &amp;lt; 100) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    lastInvalidTime = currentTime;&lt;br /&gt;
&lt;br /&gt;
    var target = event.target;&lt;br /&gt;
    var modal = target.closest(&amp;quot;.modal&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (!modal) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var dataModal = modal.dataset.modal;&lt;br /&gt;
&lt;br /&gt;
    if (!dataModal) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var category = dataModal.split(&amp;quot;-&amp;quot;)[0];&lt;br /&gt;
&lt;br /&gt;
    if (isValueInArray(category, battleChoice.categories)) {&lt;br /&gt;
      battleChoice[category].button.click();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function handleBattleFormSubmit(event) {&lt;br /&gt;
    event.preventDefault();&lt;br /&gt;
&lt;br /&gt;
    // auto save&lt;br /&gt;
    if (characters.unsavedChanges) {&lt;br /&gt;
      characters.saveButton.click();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var battleInfo = new FormData(event.target);&lt;br /&gt;
    var attackerData = battleInfo.get(&amp;quot;attacker&amp;quot;);&lt;br /&gt;
    var attackType = battleInfo.get(&amp;quot;attackType&amp;quot;);&lt;br /&gt;
    var victimData = battleInfo.get(&amp;quot;victim&amp;quot;);&lt;br /&gt;
    var attackerVariation;&lt;br /&gt;
    var victimVariation;&lt;br /&gt;
&lt;br /&gt;
    if (!attackerData &amp;amp;&amp;amp; !attackType &amp;amp;&amp;amp; !victimData) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var { nameOrVnum: attackerNameOrVnum, isCharacter: attackerIsPlayer } =&lt;br /&gt;
      parseTypeAndName(attackerData);&lt;br /&gt;
    var { nameOrVnum: victimNameOrVnum, isCharacter: victimIsPlayer } =&lt;br /&gt;
      parseTypeAndName(victimData);&lt;br /&gt;
&lt;br /&gt;
    if (attackerIsPlayer) {&lt;br /&gt;
      var attacker = copyObject(characters.savedCharacters[attackerNameOrVnum]);&lt;br /&gt;
      attackerVariation = attacker.bonusVariation;&lt;br /&gt;
    } else {&lt;br /&gt;
      var attacker = createMonster(attackerNameOrVnum);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (victimIsPlayer) {&lt;br /&gt;
      var victim = copyObject(characters.savedCharacters[victimNameOrVnum]);&lt;br /&gt;
      victimVariation = victim.bonusVariation;&lt;br /&gt;
    } else {&lt;br /&gt;
      var victim = createMonster(victimNameOrVnum, attacker);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (useBonusVariationMode(attacker, attackerVariation)) {&lt;br /&gt;
      damageWithVariation(&lt;br /&gt;
        attacker,&lt;br /&gt;
        victim,&lt;br /&gt;
        attackType,&lt;br /&gt;
        battle,&lt;br /&gt;
        attacker,&lt;br /&gt;
        attackerVariation&lt;br /&gt;
      );&lt;br /&gt;
    } else if (useBonusVariationMode(victim, victimVariation)) {&lt;br /&gt;
      damageWithVariation(&lt;br /&gt;
        attacker,&lt;br /&gt;
        victim,&lt;br /&gt;
        attackType,&lt;br /&gt;
        battle,&lt;br /&gt;
        victim,&lt;br /&gt;
        victimVariation&lt;br /&gt;
      );&lt;br /&gt;
    } else {&lt;br /&gt;
      damageWithoutVariation(attacker, victim, attackType, battle, characters);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createMapping() {&lt;br /&gt;
  var mapping = {&lt;br /&gt;
    typeFlag: [&lt;br /&gt;
      &amp;quot;animalBonus&amp;quot;, // 0&lt;br /&gt;
      &amp;quot;humanBonus&amp;quot;, // 1&lt;br /&gt;
      &amp;quot;orcBonus&amp;quot;, // 2&lt;br /&gt;
      &amp;quot;mysticBonus&amp;quot;, // 3&lt;br /&gt;
      &amp;quot;undeadBonus&amp;quot;, // 4&lt;br /&gt;
      &amp;quot;insectBonus&amp;quot;, // 5&lt;br /&gt;
      &amp;quot;desertBonus&amp;quot;, // 6&lt;br /&gt;
      &amp;quot;devilBonus&amp;quot;, // 7&lt;br /&gt;
    ],&lt;br /&gt;
    raceBonus: {&lt;br /&gt;
      warrior: &amp;quot;warriorBonus&amp;quot;,&lt;br /&gt;
      sura: &amp;quot;suraBonus&amp;quot;,&lt;br /&gt;
      ninja: &amp;quot;ninjaBonus&amp;quot;,&lt;br /&gt;
      shaman: &amp;quot;shamanBonus&amp;quot;,&lt;br /&gt;
      lycan: &amp;quot;lycanBonus&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    raceResistance: {&lt;br /&gt;
      warrior: &amp;quot;warriorResistance&amp;quot;,&lt;br /&gt;
      sura: &amp;quot;suraResistance&amp;quot;,&lt;br /&gt;
      ninja: &amp;quot;ninjaResistance&amp;quot;,&lt;br /&gt;
      shaman: &amp;quot;shamanResistance&amp;quot;,&lt;br /&gt;
      lycan: &amp;quot;lycanResistance&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    defenseWeapon: [&lt;br /&gt;
      &amp;quot;swordDefense&amp;quot;, // 0&lt;br /&gt;
      &amp;quot;daggerDefense&amp;quot;, // 1&lt;br /&gt;
      &amp;quot;arrowDefense&amp;quot;, // 2&lt;br /&gt;
      &amp;quot;twoHandedSwordDefense&amp;quot;, // 3&lt;br /&gt;
      &amp;quot;bellDefense&amp;quot;, // 4&lt;br /&gt;
      &amp;quot;clawDefense&amp;quot;, // 5&lt;br /&gt;
      &amp;quot;fanDefense&amp;quot;, // 6&lt;br /&gt;
      &amp;quot;swordDefense&amp;quot;, // 7&lt;br /&gt;
      &amp;quot;fistDefense&amp;quot;, // 8&lt;br /&gt;
    ],&lt;br /&gt;
    breakWeapon: [&lt;br /&gt;
      &amp;quot;breakSwordDefense&amp;quot;, // 0&lt;br /&gt;
      &amp;quot;breakDaggerDefense&amp;quot;, // 1&lt;br /&gt;
      &amp;quot;breakArrowDefense&amp;quot;, // 2&lt;br /&gt;
      &amp;quot;breakTwoHandedSwordDefense&amp;quot;, // 3&lt;br /&gt;
      &amp;quot;breakBellDefense&amp;quot;, // 4&lt;br /&gt;
      &amp;quot;breakClawDefense&amp;quot;, // 5&lt;br /&gt;
      &amp;quot;breakFanDefense&amp;quot;, // 6&lt;br /&gt;
      &amp;quot;breakSwordDefense&amp;quot;, // 7&lt;br /&gt;
    ],&lt;br /&gt;
    elementBonus: [&lt;br /&gt;
      &amp;quot;fireBonus&amp;quot;, // 0&lt;br /&gt;
      &amp;quot;iceBonus&amp;quot;, // 1&lt;br /&gt;
      &amp;quot;windBonus&amp;quot;, // 2&lt;br /&gt;
      &amp;quot;lightningBonus&amp;quot;, // 3&lt;br /&gt;
      &amp;quot;earthBonus&amp;quot;, // 4&lt;br /&gt;
      &amp;quot;darknessBonus&amp;quot;, // 5&lt;br /&gt;
    ],&lt;br /&gt;
    elementResistance: [&lt;br /&gt;
      &amp;quot;fireResistance&amp;quot;, // 0&lt;br /&gt;
      &amp;quot;iceResistance&amp;quot;, // 1&lt;br /&gt;
      &amp;quot;windResistance&amp;quot;, // 2&lt;br /&gt;
      &amp;quot;lightningResistance&amp;quot;, // 3&lt;br /&gt;
      &amp;quot;earthResistance&amp;quot;, // 4&lt;br /&gt;
      &amp;quot;darknessResistance&amp;quot;, // 5&lt;br /&gt;
    ],&lt;br /&gt;
  };&lt;br /&gt;
  return mapping;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createConstants() {&lt;br /&gt;
  var constants = {&lt;br /&gt;
    polymorphPowerTable: [&lt;br /&gt;
      10, 11, 11, 12, 13, 13, 14, 15, 16, 17, 18, 19, 20, 22, 23, 24, 26, 27,&lt;br /&gt;
      29, 31, 33, 35, 37, 39, 41, 44, 46, 49, 52, 55, 59, 62, 66, 70, 74, 79,&lt;br /&gt;
      84, 89, 94, 100, 0,&lt;br /&gt;
    ],&lt;br /&gt;
    skillPowerTable: [&lt;br /&gt;
      0, 0.05, 0.06, 0.08, 0.1, 0.12, 0.14, 0.16, 0.18, 0.2, 0.22, 0.24, 0.26,&lt;br /&gt;
      0.28, 0.3, 0.32, 0.34, 0.36, 0.38, 0.4, 0.5, 0.52, 0.54, 0.56, 0.58, 0.6,&lt;br /&gt;
      0.63, 0.66, 0.69, 0.72, 0.82, 0.85, 0.88, 0.91, 0.94, 0.98, 1.02, 1.06,&lt;br /&gt;
      1.1, 1.15, 1.25,&lt;br /&gt;
    ],&lt;br /&gt;
    marriageTable: {&lt;br /&gt;
      harmonyEarrings: [4, 5, 6, 8],&lt;br /&gt;
      loveEarrings: [4, 5, 6, 8],&lt;br /&gt;
      harmonyBracelet: [4, 5, 6, 8],&lt;br /&gt;
      loveNecklace: [20, 25, 30, 40],&lt;br /&gt;
      harmonyNecklace: [12, 16, 20, 30],&lt;br /&gt;
    },&lt;br /&gt;
    allowedWeaponsPerRace: {&lt;br /&gt;
      warrior: [0, 3, 8],&lt;br /&gt;
      ninja: [0, 1, 2, 8],&lt;br /&gt;
      sura: [0, 7, 8],&lt;br /&gt;
      shaman: [4, 6, 8],&lt;br /&gt;
      lycan: [5, 8],&lt;br /&gt;
    },&lt;br /&gt;
    translation: {&lt;br /&gt;
      fr: {&lt;br /&gt;
        damage: &amp;quot;Dégâts&amp;quot;,&lt;br /&gt;
        percentage: &amp;quot;Pourcentage&amp;quot;,&lt;br /&gt;
        miss: &amp;quot;Miss&amp;quot;,&lt;br /&gt;
        normalHit: &amp;quot;Coup classique&amp;quot;,&lt;br /&gt;
        criticalHit: &amp;quot;Coup critique&amp;quot;,&lt;br /&gt;
        piercingHit: &amp;quot;Coup perçant&amp;quot;,&lt;br /&gt;
        criticalPiercingHit: &amp;quot;Coup critique perçant&amp;quot;,&lt;br /&gt;
        damageRepartition: &amp;quot;Distribution des dégâts&amp;quot;,&lt;br /&gt;
        averageDamage: &amp;quot;Dégâts moyens&amp;quot;,&lt;br /&gt;
        damageAugmentation: &amp;quot;Augmentation des dégâts&amp;quot;,&lt;br /&gt;
        bonusVariationTitle: [&lt;br /&gt;
          &amp;quot;Évolution des dégâts moyens&amp;quot;,&lt;br /&gt;
          &amp;quot;par rapport à la valeur d'un bonus&amp;quot;,&lt;br /&gt;
        ],&lt;br /&gt;
      },&lt;br /&gt;
      en: {&lt;br /&gt;
        damage: &amp;quot;Damage&amp;quot;,&lt;br /&gt;
        percentage: &amp;quot;Percentage&amp;quot;,&lt;br /&gt;
        miss: &amp;quot;Miss&amp;quot;,&lt;br /&gt;
        normalHit: &amp;quot;Normal Hit&amp;quot;,&lt;br /&gt;
        criticalHit: &amp;quot;Critical Hit&amp;quot;,&lt;br /&gt;
        piercingHit: &amp;quot;Piercing Hit&amp;quot;,&lt;br /&gt;
        criticalPiercingHit: &amp;quot;Critical Piercing Hit&amp;quot;,&lt;br /&gt;
        damageRepartition: &amp;quot;Damage Repartition&amp;quot;,&lt;br /&gt;
        averageDamage: &amp;quot;Average Damage&amp;quot;,&lt;br /&gt;
        damageAugmentation: &amp;quot;Damage Augmentation&amp;quot;,&lt;br /&gt;
        bonusVariationTitle: [&lt;br /&gt;
          &amp;quot;Evolution of Average Damage&amp;quot;,&lt;br /&gt;
          &amp;quot;Relative to a Bonus Value&amp;quot;,&lt;br /&gt;
        ],&lt;br /&gt;
      },&lt;br /&gt;
      tr: {&lt;br /&gt;
        damage: &amp;quot;Hasar&amp;quot;,&lt;br /&gt;
        percentage: &amp;quot;Yüzde&amp;quot;,&lt;br /&gt;
        miss: &amp;quot;Miss Vuruş&amp;quot;,&lt;br /&gt;
        normalHit: &amp;quot;Düz Vuruş&amp;quot;,&lt;br /&gt;
        criticalHit: &amp;quot;Kritik Vuruş&amp;quot;,&lt;br /&gt;
        piercingHit: &amp;quot;Delici Vuruş&amp;quot;,&lt;br /&gt;
        criticalPiercingHit: &amp;quot;Kritikli Delici Vuruş&amp;quot;,&lt;br /&gt;
        damageRepartition: &amp;quot;Hasar Dağılımı&amp;quot;,&lt;br /&gt;
        averageDamage: &amp;quot;Ortalama Hasar&amp;quot;,&lt;br /&gt;
        damageAugmentation: &amp;quot;Ortalama Hasar Artışı&amp;quot;,&lt;br /&gt;
        bonusVariationTitle: [&lt;br /&gt;
          &amp;quot;Bir bonusun değerine kıyasla&amp;quot;,&lt;br /&gt;
          &amp;quot;Ortalama Hasar Çizelgesi&amp;quot;,&lt;br /&gt;
        ],&lt;br /&gt;
      },&lt;br /&gt;
      ro: {&lt;br /&gt;
        damage: &amp;quot;Daune&amp;quot;,&lt;br /&gt;
        percentage: &amp;quot;Procent&amp;quot;,&lt;br /&gt;
        miss: &amp;quot;Miss&amp;quot;,&lt;br /&gt;
        normalHit: &amp;quot;Lovitura normala&amp;quot;,&lt;br /&gt;
        criticalHit: &amp;quot;Lovitura critica&amp;quot;,&lt;br /&gt;
        piercingHit: &amp;quot;Lovitura patrunzatoare&amp;quot;,&lt;br /&gt;
        criticalPiercingHit: &amp;quot;Lovitura critica si patrunzatoare&amp;quot;,&lt;br /&gt;
        damageRepartition: &amp;quot;Distribuția daunelor&amp;quot;,&lt;br /&gt;
        averageDamage: &amp;quot;Media damageului&amp;quot;,&lt;br /&gt;
        damageAugmentation: &amp;quot;Damage imbunatatit&amp;quot;,&lt;br /&gt;
        bonusVariationTitle: [&lt;br /&gt;
          &amp;quot;Evolutia mediei damageului&amp;quot;,&lt;br /&gt;
          &amp;quot;relativ la o valoare bonus&amp;quot;,&lt;br /&gt;
        ],&lt;br /&gt;
      },&lt;br /&gt;
      de: {&lt;br /&gt;
        damage: &amp;quot;Schäden&amp;quot;,&lt;br /&gt;
        percentage: &amp;quot;Prozentsatz&amp;quot;,&lt;br /&gt;
        miss: &amp;quot;Verfehlen&amp;quot;,&lt;br /&gt;
        normalHit: &amp;quot;Normaler Treffer&amp;quot;,&lt;br /&gt;
        criticalHit: &amp;quot;Kritischer Treffer&amp;quot;,&lt;br /&gt;
        piercingHit: &amp;quot;Durchdringender Treffer&amp;quot;,&lt;br /&gt;
        criticalPiercingHit: &amp;quot;Kritischer durchdringender Treffer&amp;quot;,&lt;br /&gt;
        damageRepartition: &amp;quot;Schadensverteilung&amp;quot;,&lt;br /&gt;
        averageDamage: &amp;quot;Durchschnittlicher Schaden&amp;quot;,&lt;br /&gt;
        damageAugmentation: &amp;quot;Schadenserhöhung&amp;quot;,&lt;br /&gt;
        bonusVariationTitle: [&lt;br /&gt;
          &amp;quot;Entwicklung des durchschnittlichen Schadens&amp;quot;,&lt;br /&gt;
          &amp;quot;im Verhältnis zu einem Bonus&amp;quot;,&lt;br /&gt;
        ],&lt;br /&gt;
      },&lt;br /&gt;
      pt: {&lt;br /&gt;
        damage: &amp;quot;Dano&amp;quot;,&lt;br /&gt;
        percentage: &amp;quot;Percentagem&amp;quot;,&lt;br /&gt;
        miss: &amp;quot;Miss&amp;quot;,&lt;br /&gt;
        normalHit: &amp;quot;Dano normal&amp;quot;,&lt;br /&gt;
        criticalHit: &amp;quot;Dano crítico&amp;quot;,&lt;br /&gt;
        piercingHit: &amp;quot;Dano perfurante&amp;quot;,&lt;br /&gt;
        criticalPiercingHit: &amp;quot;Dano crítico perfurante&amp;quot;,&lt;br /&gt;
        damageRepartition: &amp;quot;Repartição de dano&amp;quot;,&lt;br /&gt;
        averageDamage: &amp;quot;Dano médio&amp;quot;,&lt;br /&gt;
        damageAugmentation: &amp;quot;Aumento de dano&amp;quot;,&lt;br /&gt;
        bonusVariationTitle: [&amp;quot;Evolução do dano médio&amp;quot;, &amp;quot;relativo a um bónus&amp;quot;],&lt;br /&gt;
      },&lt;br /&gt;
      // es: {&lt;br /&gt;
      //   damage: &amp;quot;Daño&amp;quot;,&lt;br /&gt;
      //   percentage: &amp;quot;Porcentaje&amp;quot;,&lt;br /&gt;
      //   miss: &amp;quot;Miss&amp;quot;,&lt;br /&gt;
      //   normalHit: &amp;quot;Daño normal&amp;quot;,&lt;br /&gt;
      //   criticalHit: &amp;quot;Daño crítico&amp;quot;,&lt;br /&gt;
      //   piercingHit: &amp;quot;Daño perforante&amp;quot;,&lt;br /&gt;
      //   criticalPiercingHit: &amp;quot;Daño crítico perforante&amp;quot;,&lt;br /&gt;
      //   damageRepartition: &amp;quot;Repartición de daños&amp;quot;,&lt;br /&gt;
      //   averageDamage: &amp;quot;Daño medio&amp;quot;,&lt;br /&gt;
      //   damageAugmentation: &amp;quot;Aumento de daño&amp;quot;,&lt;br /&gt;
      //   bonusVariationTitle: [&amp;quot;Evolución del daño medio&amp;quot;, &amp;quot;Relativo a una bonificación&amp;quot;]&lt;br /&gt;
      // },&lt;br /&gt;
    },&lt;br /&gt;
  };&lt;br /&gt;
  return constants;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initResultTableHistory(battle) {&lt;br /&gt;
  var {&lt;br /&gt;
    tableResultHistory,&lt;br /&gt;
    savedFights,&lt;br /&gt;
    deleteFightTemplate,&lt;br /&gt;
    numberFormats: { default: numberFormat },&lt;br /&gt;
  } = battle;&lt;br /&gt;
  var startIndex = 3;&lt;br /&gt;
&lt;br /&gt;
  if (savedFights.length) {&lt;br /&gt;
    hideElement(tableResultHistory.rows[1]);&lt;br /&gt;
&lt;br /&gt;
    for (var savedFight of savedFights) {&lt;br /&gt;
      addRowToTableResultHistory(&lt;br /&gt;
        tableResultHistory,&lt;br /&gt;
        savedFight,&lt;br /&gt;
        deleteFightTemplate,&lt;br /&gt;
        numberFormat&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  tableResultHistory.addEventListener(&amp;quot;click&amp;quot;, function (event) {&lt;br /&gt;
    var deleteButton = event.target.closest(&amp;quot;.svg-icon-delete&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (deleteButton) {&lt;br /&gt;
      var row = deleteButton.closest(&amp;quot;tr&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
      if (row) {&lt;br /&gt;
        savedFights.splice(row.rowIndex - startIndex, 1);&lt;br /&gt;
        updateSavedFights(savedFights);&lt;br /&gt;
&lt;br /&gt;
        row.remove();&lt;br /&gt;
&lt;br /&gt;
        if (tableResultHistory.rows.length === startIndex) {&lt;br /&gt;
          showElement(tableResultHistory.rows[1]);&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initDamageChart(battle) {&lt;br /&gt;
  var { translation, reduceChartPointsContainer, reduceChartPoints } = battle;&lt;br /&gt;
  var percentFormat = battle.numberFormats.percent;&lt;br /&gt;
  var customPlugins = {&lt;br /&gt;
    id: &amp;quot;customPlugins&amp;quot;,&lt;br /&gt;
    afterDraw(chart) {&lt;br /&gt;
      var missPercentage = chart.data.missPercentage;&lt;br /&gt;
&lt;br /&gt;
      if (!missPercentage) {&lt;br /&gt;
        return;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      var {&lt;br /&gt;
        ctx,&lt;br /&gt;
        chartArea: { top, right },&lt;br /&gt;
      } = chart;&lt;br /&gt;
      ctx.save();&lt;br /&gt;
      var text =&lt;br /&gt;
        translation.miss + &amp;quot; : &amp;quot; + percentFormat.format(missPercentage);&lt;br /&gt;
      var padding = 4;&lt;br /&gt;
      var fontSize = 14;&lt;br /&gt;
&lt;br /&gt;
      ctx.font = fontSize + &amp;quot;px Helvetica Neue&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
      var textWidth = ctx.measureText(text).width;&lt;br /&gt;
      var xPosition = right - textWidth - 5;&lt;br /&gt;
      var yPosition = top + 5;&lt;br /&gt;
&lt;br /&gt;
      ctx.fillStyle = &amp;quot;rgba(255, 0, 0, 0.2)&amp;quot;;&lt;br /&gt;
      ctx.fillRect(&lt;br /&gt;
        xPosition - padding,&lt;br /&gt;
        yPosition - padding,&lt;br /&gt;
        textWidth + 2 * padding,&lt;br /&gt;
        fontSize + 2 * padding&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      ctx.strokeStyle = &amp;quot;red&amp;quot;;&lt;br /&gt;
      ctx.strokeRect(&lt;br /&gt;
        xPosition - padding,&lt;br /&gt;
        yPosition - padding,&lt;br /&gt;
        textWidth + 2 * padding,&lt;br /&gt;
        fontSize + 2 * padding&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      ctx.fillStyle = &amp;quot;#666&amp;quot;;&lt;br /&gt;
      ctx.textBaseline = &amp;quot;top&amp;quot;;&lt;br /&gt;
      ctx.fillText(text, xPosition, yPosition + 1);&lt;br /&gt;
&lt;br /&gt;
      ctx.restore();&lt;br /&gt;
    },&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  Chart.register(customPlugins);&lt;br /&gt;
&lt;br /&gt;
  var ctx = battle.plotDamage.getContext(&amp;quot;2d&amp;quot;);&lt;br /&gt;
  var maxLabelsInTooltip = 10;&lt;br /&gt;
  var nullLabelText = &amp;quot; ...&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  var chart = new Chart(ctx, {&lt;br /&gt;
    type: &amp;quot;scatter&amp;quot;,&lt;br /&gt;
    data: {&lt;br /&gt;
      missPercentage: 0,&lt;br /&gt;
      datasets: [],&lt;br /&gt;
    },&lt;br /&gt;
    options: {&lt;br /&gt;
      responsive: true,&lt;br /&gt;
      maintainAspectRatio: false,&lt;br /&gt;
      plugins: {&lt;br /&gt;
        legend: {&lt;br /&gt;
          display: true,&lt;br /&gt;
          onHover: function (e) {&lt;br /&gt;
            e.native.target.style.cursor = &amp;quot;pointer&amp;quot;;&lt;br /&gt;
          },&lt;br /&gt;
          onLeave: function (e) {&lt;br /&gt;
            e.native.target.style.cursor = &amp;quot;default&amp;quot;;&lt;br /&gt;
          },&lt;br /&gt;
          onClick: function (e, legendItem, legend) {&lt;br /&gt;
            var currentIndex = legendItem.datasetIndex;&lt;br /&gt;
            var ci = legend.chart;&lt;br /&gt;
            var isCurrentDatasetVisible = ci.isDatasetVisible(currentIndex);&lt;br /&gt;
            var datasets = ci.data.datasets;&lt;br /&gt;
            var hideReducePoints = true;&lt;br /&gt;
            var isReducePointsChecked = reduceChartPoints.checked;&lt;br /&gt;
&lt;br /&gt;
            datasets[currentIndex].hidden = isCurrentDatasetVisible;&lt;br /&gt;
            legendItem.hidden = isCurrentDatasetVisible;&lt;br /&gt;
&lt;br /&gt;
            for (var index in datasets) {&lt;br /&gt;
              if (ci.isDatasetVisible(index) &amp;amp;&amp;amp; datasets[index].canBeReduced) {&lt;br /&gt;
                showElement(reduceChartPointsContainer);&lt;br /&gt;
                hideReducePoints = false;&lt;br /&gt;
                break;&lt;br /&gt;
              }&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            if (hideReducePoints) {&lt;br /&gt;
              hideElement(reduceChartPointsContainer);&lt;br /&gt;
              handleChartAnimations(ci, true);&lt;br /&gt;
            } else {&lt;br /&gt;
              handleChartAnimations(ci, isReducePointsChecked);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            ci.update();&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        title: {&lt;br /&gt;
          display: true,&lt;br /&gt;
          text: translation.damageRepartition,&lt;br /&gt;
          font: {&lt;br /&gt;
            size: 20,&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        tooltip: {&lt;br /&gt;
          callbacks: {&lt;br /&gt;
            label: function (context) {&lt;br /&gt;
              if (context.label === null) {&lt;br /&gt;
                return nullLabelText;&lt;br /&gt;
              }&lt;br /&gt;
&lt;br /&gt;
              var xValue = battle.numberFormats.default.format(&lt;br /&gt;
                context.parsed.x&lt;br /&gt;
              );&lt;br /&gt;
              var yValue = battle.numberFormats.percent.format(&lt;br /&gt;
                context.parsed.y&lt;br /&gt;
              );&lt;br /&gt;
              var label =&lt;br /&gt;
                &amp;quot; &amp;quot; +&lt;br /&gt;
                context.dataset.label +&lt;br /&gt;
                &amp;quot; : (&amp;quot; +&lt;br /&gt;
                xValue +&lt;br /&gt;
                &amp;quot;, &amp;quot; +&lt;br /&gt;
                yValue +&lt;br /&gt;
                &amp;quot;)&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
              return label;&lt;br /&gt;
            },&lt;br /&gt;
            beforeBody: function (tooltipItems) {&lt;br /&gt;
              if (tooltipItems.length &amp;gt; maxLabelsInTooltip + 1) {&lt;br /&gt;
                tooltipItems.splice(maxLabelsInTooltip + 1);&lt;br /&gt;
                tooltipItems[maxLabelsInTooltip].label = null;&lt;br /&gt;
              }&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          caretPadding: 10,&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
      scales: {&lt;br /&gt;
        x: {&lt;br /&gt;
          type: &amp;quot;linear&amp;quot;,&lt;br /&gt;
          position: &amp;quot;bottom&amp;quot;,&lt;br /&gt;
          title: {&lt;br /&gt;
            display: true,&lt;br /&gt;
            text: translation.damage,&lt;br /&gt;
            font: {&lt;br /&gt;
              size: 16,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        y: {&lt;br /&gt;
          title: {&lt;br /&gt;
            display: true,&lt;br /&gt;
            text: translation.percentage,&lt;br /&gt;
            font: {&lt;br /&gt;
              size: 16,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          ticks: {&lt;br /&gt;
            format: {&lt;br /&gt;
              style: &amp;quot;percent&amp;quot;,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
      elements: {&lt;br /&gt;
        point: {&lt;br /&gt;
          borderWidth: 1,&lt;br /&gt;
          radius: 3,&lt;br /&gt;
          hitRadius: 3,&lt;br /&gt;
          hoverRadius: 6,&lt;br /&gt;
          hoverBorderWidth: 2,&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
    },&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  var datasetsStyle = [&lt;br /&gt;
    {&lt;br /&gt;
      name: &amp;quot;normalHit&amp;quot;,&lt;br /&gt;
      canBeReduced: false,&lt;br /&gt;
      label: translation.normalHit,&lt;br /&gt;
      backgroundColor: &amp;quot;rgba(75, 192, 192, 0.2)&amp;quot;,&lt;br /&gt;
      borderColor: &amp;quot;rgba(75, 192, 192, 1)&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      name: &amp;quot;piercingHit&amp;quot;,&lt;br /&gt;
      canBeReduced: false,&lt;br /&gt;
      label: translation.piercingHit,&lt;br /&gt;
      backgroundColor: &amp;quot;rgba(192, 192, 75, 0.2)&amp;quot;,&lt;br /&gt;
      borderColor: &amp;quot;rgba(192, 192, 75, 1)&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      name: &amp;quot;criticalHit&amp;quot;,&lt;br /&gt;
      canBeReduced: false,&lt;br /&gt;
      label: translation.criticalHit,&lt;br /&gt;
      backgroundColor: &amp;quot;rgba(192, 75, 192, 0.2)&amp;quot;,&lt;br /&gt;
      borderColor: &amp;quot;rgba(192, 75, 192, 1)&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      name: &amp;quot;criticalPiercingHit&amp;quot;,&lt;br /&gt;
      canBeReduced: false,&lt;br /&gt;
      label: translation.criticalPiercingHit,&lt;br /&gt;
      backgroundColor: &amp;quot;rgba(75, 75, 192, 0.2)&amp;quot;,&lt;br /&gt;
      borderColor: &amp;quot;rgba(75, 75, 192, 1)&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
  ];&lt;br /&gt;
  battle.damageChart = {&lt;br /&gt;
    chart: chart,&lt;br /&gt;
    datasetsStyle: datasetsStyle,&lt;br /&gt;
    maxPoints: 500,&lt;br /&gt;
    reduceChartPointsContainer: reduceChartPointsContainer,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initBonusVariationChart(battle) {&lt;br /&gt;
  var translation = battle.translation;&lt;br /&gt;
&lt;br /&gt;
  var ctx = battle.plotBonusVariation.getContext(&amp;quot;2d&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  var chart = new Chart(ctx, {&lt;br /&gt;
    type: &amp;quot;line&amp;quot;,&lt;br /&gt;
    data: {&lt;br /&gt;
      datasets: [&lt;br /&gt;
        {&lt;br /&gt;
          label: translation.averageDamage,&lt;br /&gt;
          backgroundColor: &amp;quot;rgba(75, 192, 192, 0.2)&amp;quot;,&lt;br /&gt;
          borderColor: &amp;quot;rgba(75, 192, 192, 1)&amp;quot;,&lt;br /&gt;
          fill: true,&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          label: translation.damageAugmentation,&lt;br /&gt;
          backgroundColor: &amp;quot;rgba(192, 192, 75, 0.2)&amp;quot;,&lt;br /&gt;
          borderColor: &amp;quot;rgba(192, 192, 75, 1)&amp;quot;,&lt;br /&gt;
          hidden: true,&lt;br /&gt;
          yTicksFormat: { style: &amp;quot;percent&amp;quot; },&lt;br /&gt;
          fill: true,&lt;br /&gt;
        },&lt;br /&gt;
      ],&lt;br /&gt;
    },&lt;br /&gt;
    options: {&lt;br /&gt;
      responsive: true,&lt;br /&gt;
      maintainAspectRatio: false,&lt;br /&gt;
      plugins: {&lt;br /&gt;
        legend: {&lt;br /&gt;
          display: true,&lt;br /&gt;
          onHover: function (e) {&lt;br /&gt;
            e.native.target.style.cursor = &amp;quot;pointer&amp;quot;;&lt;br /&gt;
          },&lt;br /&gt;
          onLeave: function (e) {&lt;br /&gt;
            e.native.target.style.cursor = &amp;quot;default&amp;quot;;&lt;br /&gt;
          },&lt;br /&gt;
          onClick: function (e, legendItem, legend) {&lt;br /&gt;
            var currentIndex = legendItem.datasetIndex;&lt;br /&gt;
            var ci = legend.chart;&lt;br /&gt;
            var datasets = ci.data.datasets;&lt;br /&gt;
            var isCurrentDatasetVisible = ci.isDatasetVisible(currentIndex);&lt;br /&gt;
            var yAxis = ci.options.scales.y;&lt;br /&gt;
&lt;br /&gt;
            var otherIndex = currentIndex === 0 ? 1 : 0;&lt;br /&gt;
            var visibleDataset = isCurrentDatasetVisible&lt;br /&gt;
              ? datasets[otherIndex]&lt;br /&gt;
              : datasets[currentIndex];&lt;br /&gt;
&lt;br /&gt;
            datasets[currentIndex].hidden = isCurrentDatasetVisible;&lt;br /&gt;
            datasets[otherIndex].hidden = !isCurrentDatasetVisible;&lt;br /&gt;
&lt;br /&gt;
            yAxis.title.text = visibleDataset.label;&lt;br /&gt;
            yAxis.ticks.format = visibleDataset.yTicksFormat;&lt;br /&gt;
&lt;br /&gt;
            ci.update();&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        title: {&lt;br /&gt;
          display: true,&lt;br /&gt;
          text: translation.bonusVariationTitle,&lt;br /&gt;
          font: {&lt;br /&gt;
            size: 18,&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        tooltip: {&lt;br /&gt;
          caretPadding: 10,&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
      scales: {&lt;br /&gt;
        x: {&lt;br /&gt;
          type: &amp;quot;linear&amp;quot;,&lt;br /&gt;
          position: &amp;quot;bottom&amp;quot;,&lt;br /&gt;
          title: {&lt;br /&gt;
            display: true,&lt;br /&gt;
            text: &amp;quot;Bonus&amp;quot;,&lt;br /&gt;
            font: {&lt;br /&gt;
              size: 16,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          ticks: {&lt;br /&gt;
            callback: function (value) {&lt;br /&gt;
              if (Number.isInteger(value)) {&lt;br /&gt;
                return Number(value);&lt;br /&gt;
              }&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        y: {&lt;br /&gt;
          title: {&lt;br /&gt;
            display: true,&lt;br /&gt;
            text: translation.averageDamage,&lt;br /&gt;
            font: {&lt;br /&gt;
              size: 16,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
      elements: {&lt;br /&gt;
        point: {&lt;br /&gt;
          borderWidth: 1,&lt;br /&gt;
          radius: 3,&lt;br /&gt;
          hitRadius: 3,&lt;br /&gt;
          hoverRadius: 6,&lt;br /&gt;
          hoverBorderWidth: 2,&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
    },&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  battle.bonusVariationChart = chart;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterAttackTypeSelection(characters, battleChoice, targetValue) {&lt;br /&gt;
  var { nameOrVnum: attackerNameOrVnum, isCharacter: isAttackerPlayer } =&lt;br /&gt;
    parseTypeAndName(targetValue);&lt;br /&gt;
&lt;br /&gt;
  if (isAttackerPlayer) {&lt;br /&gt;
    var attacker = characters.savedCharacters[attackerNameOrVnum];&lt;br /&gt;
    filterAttackTypeSelectionCharacter(attacker, battleChoice.attackType);&lt;br /&gt;
  } else {&lt;br /&gt;
    filterAttackTypeSelectionMonster(battleChoice.attackType);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getTranslation(translation) {&lt;br /&gt;
  var userLanguage = navigator.language;&lt;br /&gt;
  var langToUse = &amp;quot;en&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  for (var lang in translation) {&lt;br /&gt;
    if (userLanguage.startsWith(lang)) {&lt;br /&gt;
      langToUse = lang;&lt;br /&gt;
      break;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return translation[langToUse];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addBattleData(battle) {&lt;br /&gt;
  var errorElements = document.querySelectorAll(&amp;quot;[data-error]&amp;quot;);&lt;br /&gt;
  var { elements: attackTypeElements, container: attackTypeContainer } =&lt;br /&gt;
    battle.battleChoice.attackType;&lt;br /&gt;
  var attackTypeChilds = attackTypeContainer.children;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; errorElements.length; index++) {&lt;br /&gt;
    var errorElement = errorElements[index];&lt;br /&gt;
    battle.errorInformation[errorElement.dataset.error] = errorElement;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (var index = 1; index &amp;lt; attackTypeChilds.length - 1; index++) {&lt;br /&gt;
    var attackTypeChild = attackTypeChilds[index];&lt;br /&gt;
    var input = attackTypeChild.querySelector(&amp;quot;input&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    attackTypeElements.push({&lt;br /&gt;
      container: attackTypeChild,&lt;br /&gt;
      input: input,&lt;br /&gt;
      inputClass: input.dataset.class,&lt;br /&gt;
      inputValue: input.value,&lt;br /&gt;
    });&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createDamageCalculatorInformation(chartSource) {&lt;br /&gt;
  var characters = {&lt;br /&gt;
    unsavedChanges: false,&lt;br /&gt;
    savedCharacters: {},&lt;br /&gt;
    currentCharacter: null,&lt;br /&gt;
    savedMonsters: getSavedMonsters(),&lt;br /&gt;
    monsterElements: {},&lt;br /&gt;
    characterCreation: document.getElementById(&amp;quot;character-creation&amp;quot;),&lt;br /&gt;
    addNewCharacterButton: document.getElementById(&amp;quot;add-new-character&amp;quot;),&lt;br /&gt;
    dropZone: document.getElementById(&amp;quot;character-drop-zone&amp;quot;),&lt;br /&gt;
    characterInput: document.getElementById(&amp;quot;character-input&amp;quot;),&lt;br /&gt;
    newCharacterTemplate: document.getElementById(&amp;quot;new-character-template&amp;quot;)&lt;br /&gt;
      .children[0],&lt;br /&gt;
    charactersContainer: document.getElementById(&amp;quot;characters-container&amp;quot;),&lt;br /&gt;
    monsterButtonTemplates: document.getElementById(&amp;quot;monster-button-templates&amp;quot;),&lt;br /&gt;
    monsterTemplate: document.getElementById(&amp;quot;new-monster-template&amp;quot;)&lt;br /&gt;
      .children[0],&lt;br /&gt;
    monstersContainer: document.getElementById(&amp;quot;monsters-container&amp;quot;),&lt;br /&gt;
    monsteriFrame: document.getElementById(&amp;quot;monster-iframe&amp;quot;),&lt;br /&gt;
    stoneiFrame: document.getElementById(&amp;quot;stone-iframe&amp;quot;),&lt;br /&gt;
    saveButton: document.getElementById(&amp;quot;save-character&amp;quot;),&lt;br /&gt;
    weaponCategory: document.getElementById(&amp;quot;weapon-category&amp;quot;),&lt;br /&gt;
    weaponDisplay: document.getElementById(&amp;quot;weapon-display&amp;quot;),&lt;br /&gt;
    randomAttackValue: document.getElementById(&amp;quot;random-attack-value&amp;quot;),&lt;br /&gt;
    randomMagicAttackValue: document.getElementById(&lt;br /&gt;
      &amp;quot;random-magic-attack-value&amp;quot;&lt;br /&gt;
    ),&lt;br /&gt;
    polymorphDisplay: document.getElementById(&amp;quot;polymorph-display&amp;quot;),&lt;br /&gt;
    polymorphCreation: document.getElementById(&amp;quot;polymorph-creation&amp;quot;),&lt;br /&gt;
    yoharaCreation: document.getElementById(&amp;quot;yohara-creation&amp;quot;),&lt;br /&gt;
    rankSelection: document.getElementById(&amp;quot;rank-selection&amp;quot;),&lt;br /&gt;
    blessingCreation: document.getElementById(&amp;quot;blessing-creation&amp;quot;),&lt;br /&gt;
    marriageCreation: document.getElementById(&amp;quot;marriage-creation&amp;quot;),&lt;br /&gt;
    bonusVariation: {&lt;br /&gt;
      tabButton: document.getElementById(&amp;quot;Variation&amp;quot;),&lt;br /&gt;
      checkbox: document.getElementById(&amp;quot;use-bonus-variation&amp;quot;),&lt;br /&gt;
      input: document.getElementById(&amp;quot;bonus-variation&amp;quot;),&lt;br /&gt;
      inputName: document.getElementById(&amp;quot;bonus-variation-name&amp;quot;),&lt;br /&gt;
      container: document.getElementById(&amp;quot;bonus-variation-creation&amp;quot;),&lt;br /&gt;
      minValue: document.getElementById(&amp;quot;bonus-variation-min-value&amp;quot;),&lt;br /&gt;
      maxValue: document.getElementById(&amp;quot;bonus-variation-max-value&amp;quot;),&lt;br /&gt;
      disabledText: document.getElementById(&amp;quot;bonus-variation-disabled&amp;quot;),&lt;br /&gt;
      selectedText: document.getElementById(&amp;quot;bonus-variation-selected&amp;quot;),&lt;br /&gt;
      displaySpan: document.getElementById(&amp;quot;bonus-variation-display&amp;quot;),&lt;br /&gt;
    },&lt;br /&gt;
    skillElementsToFilter: document.querySelectorAll(&lt;br /&gt;
      &amp;quot;#skill-container [data-class]&amp;quot;&lt;br /&gt;
    ),&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  for (var [pseudo, character] of Object.entries(getSavedCharacters())) {&lt;br /&gt;
    characters.savedCharacters[pseudo] = character;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var constants = createConstants();&lt;br /&gt;
&lt;br /&gt;
  var battle = {&lt;br /&gt;
    savedFights: getSavedFights(),&lt;br /&gt;
    battleChoice: {&lt;br /&gt;
      resetAttackType: false,&lt;br /&gt;
      form: document.getElementById(&amp;quot;create-battle&amp;quot;),&lt;br /&gt;
      template: document.getElementById(&amp;quot;battle-selection-template&amp;quot;)&lt;br /&gt;
        .children[0],&lt;br /&gt;
      raceToImage: {&lt;br /&gt;
        warrior: &amp;quot;/images/0/0f/Bandeaurougehomme.png&amp;quot;,&lt;br /&gt;
        ninja: &amp;quot;/images/0/0e/Queuedechevalclair.png&amp;quot;,&lt;br /&gt;
        sura: &amp;quot;/images/3/37/Couperespectablerouge.png&amp;quot;,&lt;br /&gt;
        shaman: &amp;quot;/images/6/6a/Coupeeleganteclairfemme.png&amp;quot;,&lt;br /&gt;
        lycan: &amp;quot;/images/4/4e/Protectionfrontalerouge.png&amp;quot;,&lt;br /&gt;
      },&lt;br /&gt;
      categories: [&amp;quot;attacker&amp;quot;, &amp;quot;victim&amp;quot;],&lt;br /&gt;
      attacker: {&lt;br /&gt;
        character: {&lt;br /&gt;
          count: 0,&lt;br /&gt;
          container: document.getElementById(&amp;quot;attacker-selection-characters&amp;quot;),&lt;br /&gt;
          elements: {},&lt;br /&gt;
        },&lt;br /&gt;
        monster: {&lt;br /&gt;
          count: 0,&lt;br /&gt;
          container: document.getElementById(&amp;quot;attacker-selection-monsters&amp;quot;),&lt;br /&gt;
          elements: {},&lt;br /&gt;
        },&lt;br /&gt;
        button: document.getElementById(&amp;quot;attacker-trigger&amp;quot;),&lt;br /&gt;
        defaultButtonContent: document.getElementById(&lt;br /&gt;
          &amp;quot;attacker-default-button-content&amp;quot;&lt;br /&gt;
        ),&lt;br /&gt;
        buttonContent: document.getElementById(&amp;quot;attacker-button-content&amp;quot;),&lt;br /&gt;
        container: document.getElementById(&amp;quot;attacker-selection&amp;quot;),&lt;br /&gt;
        selected: null,&lt;br /&gt;
      },&lt;br /&gt;
      victim: {&lt;br /&gt;
        character: {&lt;br /&gt;
          count: 0,&lt;br /&gt;
          container: document.getElementById(&amp;quot;victim-selection-characters&amp;quot;),&lt;br /&gt;
          elements: {},&lt;br /&gt;
        },&lt;br /&gt;
        monster: {&lt;br /&gt;
          count: 0,&lt;br /&gt;
          container: document.getElementById(&amp;quot;victim-selection-monsters&amp;quot;),&lt;br /&gt;
          elements: {},&lt;br /&gt;
        },&lt;br /&gt;
        stone: {&lt;br /&gt;
          count: 0,&lt;br /&gt;
          container: document.getElementById(&amp;quot;victim-selection-stones&amp;quot;),&lt;br /&gt;
          elements: {},&lt;br /&gt;
        },&lt;br /&gt;
        button: document.getElementById(&amp;quot;victim-trigger&amp;quot;),&lt;br /&gt;
        defaultButtonContent: document.getElementById(&lt;br /&gt;
          &amp;quot;victim-default-button-content&amp;quot;&lt;br /&gt;
        ),&lt;br /&gt;
        buttonContent: document.getElementById(&amp;quot;victim-button-content&amp;quot;),&lt;br /&gt;
        selected: null,&lt;br /&gt;
      },&lt;br /&gt;
      attackType: {&lt;br /&gt;
        container: document.getElementById(&amp;quot;attack-type-selection&amp;quot;),&lt;br /&gt;
        elements: [],&lt;br /&gt;
        defaultInput: document.getElementById(&amp;quot;physical-attack&amp;quot;),&lt;br /&gt;
        selectedText: &amp;quot;&amp;quot;,&lt;br /&gt;
      },&lt;br /&gt;
    },&lt;br /&gt;
    damageWeightedByType: {},&lt;br /&gt;
    scatterDataByType: {},&lt;br /&gt;
    damageByBonus: [],&lt;br /&gt;
    tableResultFight: document.getElementById(&amp;quot;result-table-fight&amp;quot;),&lt;br /&gt;
    tableResultHistory: document.getElementById(&amp;quot;result-table-history&amp;quot;),&lt;br /&gt;
    deleteFightTemplate: document.getElementById(&amp;quot;delete-fight-template&amp;quot;)&lt;br /&gt;
      .children[0],&lt;br /&gt;
    errorInformation: {},&lt;br /&gt;
    fightResultTitle: document.getElementById(&amp;quot;fight-result-title&amp;quot;),&lt;br /&gt;
    fightResultContainer: document.getElementById(&amp;quot;fight-result-container&amp;quot;),&lt;br /&gt;
    downLoadRawData: document.getElementById(&amp;quot;download-raw-data&amp;quot;),&lt;br /&gt;
    downLoadRawDataVariation: document.getElementById(&lt;br /&gt;
      &amp;quot;download-raw-data-variation&amp;quot;&lt;br /&gt;
    ),&lt;br /&gt;
    bonusVariationResultContainer: document.getElementById(&lt;br /&gt;
      &amp;quot;bonus-variation-result-container&amp;quot;&lt;br /&gt;
    ),&lt;br /&gt;
    reduceChartPointsContainer: document.getElementById(&lt;br /&gt;
      &amp;quot;reduce-chart-points-container&amp;quot;&lt;br /&gt;
    ),&lt;br /&gt;
    reduceChartPoints: document.getElementById(&amp;quot;reduce-chart-points&amp;quot;),&lt;br /&gt;
    plotDamage: document.getElementById(&amp;quot;plot-damage&amp;quot;),&lt;br /&gt;
    plotBonusVariation: document.getElementById(&amp;quot;plot-bonus-variation&amp;quot;),&lt;br /&gt;
    uniqueDamageCounters: document.querySelectorAll(&amp;quot;.unique-damage-counter&amp;quot;),&lt;br /&gt;
    possibleDamageCounter: document.getElementById(&amp;quot;possible-damage-counter&amp;quot;),&lt;br /&gt;
    damageTime: document.getElementById(&amp;quot;damage-time&amp;quot;),&lt;br /&gt;
    displayTime: document.getElementById(&amp;quot;display-time&amp;quot;),&lt;br /&gt;
    simulationCounter: document.getElementById(&amp;quot;simulation-counter&amp;quot;),&lt;br /&gt;
    simulationTime: document.getElementById(&amp;quot;simulation-time&amp;quot;),&lt;br /&gt;
    numberFormats: {&lt;br /&gt;
      default: new Intl.NumberFormat(undefined, {&lt;br /&gt;
        minimumFractionDigits: 0,&lt;br /&gt;
        maximumFractionDigits: 1,&lt;br /&gt;
      }),&lt;br /&gt;
      percent: new Intl.NumberFormat(undefined, {&lt;br /&gt;
        style: &amp;quot;percent&amp;quot;,&lt;br /&gt;
        maximumFractionDigits: 3,&lt;br /&gt;
      }),&lt;br /&gt;
      second: new Intl.NumberFormat(undefined, {&lt;br /&gt;
        style: &amp;quot;unit&amp;quot;,&lt;br /&gt;
        unit: &amp;quot;second&amp;quot;,&lt;br /&gt;
        unitDisplay: &amp;quot;long&amp;quot;,&lt;br /&gt;
        maximumFractionDigits: 3,&lt;br /&gt;
      }),&lt;br /&gt;
    },&lt;br /&gt;
    mapping: createMapping(),&lt;br /&gt;
    constants: constants,&lt;br /&gt;
    translation: getTranslation(constants.translation),&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  addBattleData(battle);&lt;br /&gt;
  initResultTableHistory(battle);&lt;br /&gt;
  addScript(chartSource, function () {&lt;br /&gt;
    initDamageChart(battle);&lt;br /&gt;
    initBonusVariationChart(battle);&lt;br /&gt;
  });&lt;br /&gt;
  reduceChartPointsListener(battle);&lt;br /&gt;
  downloadRawDataListener(battle);&lt;br /&gt;
&lt;br /&gt;
  return [characters, battle];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadStyle(src) {&lt;br /&gt;
  var link = document.createElement(&amp;quot;link&amp;quot;);&lt;br /&gt;
  link.href = src;&lt;br /&gt;
  link.rel = &amp;quot;stylesheet&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  document.head.appendChild(link);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
(function () {&lt;br /&gt;
  var javascriptSource =&lt;br /&gt;
    &amp;quot;/index.php?title=Utilisateur:Ankhseram/Calculator.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&amp;quot;;&lt;br /&gt;
  var cssSource =&lt;br /&gt;
    &amp;quot;/index.php?title=Utilisateur:Ankhseram/Style.css&amp;amp;action=raw&amp;amp;ctype=text/css&amp;quot;;&lt;br /&gt;
  var chartSource = &amp;quot;https://cdn.jsdelivr.net/npm/chart.js&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  loadStyle(cssSource);&lt;br /&gt;
&lt;br /&gt;
  function main() {&lt;br /&gt;
    var [characters, battle] = createDamageCalculatorInformation(chartSource);&lt;br /&gt;
&lt;br /&gt;
    characterManagement(characters, battle);&lt;br /&gt;
    monsterManagement(characters, battle);&lt;br /&gt;
&lt;br /&gt;
    updateBattleChoice(characters, battle.battleChoice);&lt;br /&gt;
    createBattle(characters, battle);&lt;br /&gt;
  }&lt;br /&gt;
  addScript(javascriptSource, main);&lt;br /&gt;
})();&lt;/div&gt;</summary>
		<author><name>Dexter</name></author>
		
	</entry>
	<entry>
		<id>https://fr-wiki.metin2.gameforge.com/index.php?title=Page_de_test&amp;diff=106259</id>
		<title>Page de test</title>
		<link rel="alternate" type="text/html" href="https://fr-wiki.metin2.gameforge.com/index.php?title=Page_de_test&amp;diff=106259"/>
		<updated>2025-01-21T13:58:35Z</updated>

		<summary type="html">&lt;p&gt;Dexter : test&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Test1|name=test|button=Modal|title=Ttire|content=Contenu}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;notranslate&amp;quot; style=&amp;quot;display: none;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;display: inline-block;&amp;quot; data-pet=&amp;quot;monkey&amp;quot;&amp;gt;[[Image:Petitsingeapparence3.png|50px|link=Petit singe]]&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;display: inline-block;&amp;quot; data-pet=&amp;quot;spider&amp;quot;&amp;gt;[[Image:Petitearaigneeapparence3.png|50px|link=Petite araignée]]&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;display: inline-block;&amp;quot; data-pet=&amp;quot;razador&amp;quot;&amp;gt;[[Image:Petitrazadorapparence3.png|50px|link=Petit Razador]]&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;display: inline-block;&amp;quot; data-pet=&amp;quot;nemere&amp;quot;&amp;gt;[[Image:Petitnemereapparence3.png|50px|link=Petit Nemere]]&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;display: inline-block;&amp;quot; data-pet=&amp;quot;dragonette&amp;quot;&amp;gt;[[Image:Petitdragonapparence3.png|50px|link=Petit dragon]]&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;display: inline-block;&amp;quot; data-pet=&amp;quot;meley&amp;quot;&amp;gt;[[Image:Petitemeleyapparence3.png|50px|link=Petite Meley]]&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;display: inline-block;&amp;quot; data-pet=&amp;quot;azrael&amp;quot;&amp;gt;[[Image:Miniazraelapparence3.png|50px|link=Mini-Azraël]]&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;display: inline-block;&amp;quot; data-pet=&amp;quot;executor&amp;quot;&amp;gt;[[Image:Minibourreauventruapparence3.png|50px|link=Minibourreau ventru]]&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;display: inline-block;&amp;quot; data-pet=&amp;quot;baashido&amp;quot;&amp;gt;[[Image:Bebebaashidoapparence3.png|50px|link=Bébé Baashido]]&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;display: inline-block;&amp;quot; data-pet=&amp;quot;nessie&amp;quot;&amp;gt;[[Image:Nessieapparence3.png|50px|link=Nessie]]&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;display: inline-block;&amp;quot; data-pet=&amp;quot;exedyar&amp;quot;&amp;gt;[[Image:Exedyarcouvecailleapparence3.png|50px|link=Exédyar couvécaille]]&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;display: inline-block;&amp;quot; data-pet=&amp;quot;alastor&amp;quot;&amp;gt;[[Image:Minialastorfurieuxapparence3.png|50px|link=Mini Alastor furieux]]&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;display: inline-block;&amp;quot; data-pet=&amp;quot;boss&amp;quot;&amp;gt;[[Image:Commandantbebeapparence3.png|50px|link=Commandant bébé]]&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;display: flex; flex-direction: column; white-space: nowrap;&amp;quot; data-skill=&amp;quot;warrior&amp;quot;&amp;gt;[[Image:Resistanceguerriericone.png|link=Résistance (Guerrier)]] [[Résistance (Guerrier)|Rés. Guerrier]]&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;display: flex; flex-direction: column; white-space: nowrap;&amp;quot; data-skill=&amp;quot;sura&amp;quot;&amp;gt;[[Image:Resistanceguerriericone.png|link=Résistance (Sura)]] [[Résistance (Sura)|Rés. Sura]]&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;display: flex; flex-direction: column; white-space: nowrap;&amp;quot; data-skill=&amp;quot;ninja&amp;quot;&amp;gt;[[Image:Resistanceguerriericone.png|link=Résistance (Ninja)]] [[Résistance (Ninja)|Rés. Ninja]]&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;display: flex; flex-direction: column; white-space: nowrap;&amp;quot; data-skill=&amp;quot;shaman&amp;quot;&amp;gt;[[Image:Resistanceguerriericone.png|link=Résistance (Chamane)]] [[Résistance (Chamane)|Rés. Chamane]]&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;display: flex; flex-direction: column; white-space: nowrap;&amp;quot; data-skill=&amp;quot;lycan&amp;quot;&amp;gt;[[Image:Resistanceguerriericone.png|link=Résistance (Lycan)]] [[Résistance (Lycan)|Rés. Lycan]]&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;display: flex; flex-direction: column; white-space: nowrap;&amp;quot; data-skill=&amp;quot;berserker&amp;quot;&amp;gt;[[Image:Berserkericone.png|link=Berserker]] [[Berserker]]&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;display: flex; flex-direction: column; white-space: nowrap;&amp;quot; data-skill=&amp;quot;antiMagic&amp;quot;&amp;gt;[[Image:Antimagieicone.png|link=Anti-magie]] [[Anti-magie]]&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;display: flex; flex-direction: column; white-space: nowrap;&amp;quot; data-skill=&amp;quot;haste&amp;quot;&amp;gt;[[Image:Accelerationicone.png|link=Accélération]] [[Accélération]]&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;display: flex; flex-direction: column; white-space: nowrap;&amp;quot; data-skill=&amp;quot;drill&amp;quot;&amp;gt;[[Image:Drillicone.png|link=Drill]] [[Drill]]&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;display: flex; flex-direction: column; white-space: nowrap;&amp;quot; data-skill=&amp;quot;restoration&amp;quot;&amp;gt;[[Image:Renouvellementicone.png|link=Renouvellement]] [[Renouvellement]]&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;display: flex; flex-direction: column; white-space: nowrap;&amp;quot; data-skill=&amp;quot;vampirism&amp;quot;&amp;gt;[[Image:Vampireicone.png|link=Vampire]] [[Vampire]]&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;display: flex; flex-direction: column; white-space: nowrap;&amp;quot; data-skill=&amp;quot;spiritualism&amp;quot;&amp;gt;[[Image:Fantomesicone.png|link=Fantômes]] [[Fantômes]]&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;display: flex; flex-direction: column; white-space: nowrap;&amp;quot; data-skill=&amp;quot;bulwark&amp;quot;&amp;gt;[[Image:Obstacleicone.png|link=Obstacle]] [[Obstacle]]&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;display: flex; flex-direction: column; white-space: nowrap;&amp;quot; data-skill=&amp;quot;reflection&amp;quot;&amp;gt;[[Image:Miroiricone.png|link=Miroir]] [[Miroir]]&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;display: flex; flex-direction: column; white-space: nowrap;&amp;quot; data-skill=&amp;quot;yang&amp;quot;&amp;gt;[[Image:Chutedeyangsicone.png|link=Chute de Yangs]] [[Chute de Yangs]]&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;display: flex; flex-direction: column; white-space: nowrap;&amp;quot; data-skill=&amp;quot;range&amp;quot;&amp;gt;[[Image:Porteeicone.png|link=Portée]] [[Portée]]&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;display: flex; flex-direction: column; white-space: nowrap;&amp;quot; data-skill=&amp;quot;immortal&amp;quot;&amp;gt;[[Image:Invincibiliteicone.png|link=Invincibilité]] [[Invincibilité]]&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;display: flex; flex-direction: column; white-space: nowrap;&amp;quot; data-skill=&amp;quot;panacea&amp;quot;&amp;gt;[[Image:Soinsicone.png|link=Soins]] [[Soins]]&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;display: flex; flex-direction: column; white-space: nowrap;&amp;quot; data-skill=&amp;quot;masterBrewer&amp;quot;&amp;gt;[[Image:Maitrebrasseuricone.png|link=Maître brasseur]] [[Maître brasseur]]&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;display: flex; flex-direction: column; white-space: nowrap;&amp;quot; data-skill=&amp;quot;monster&amp;quot;&amp;gt;[[Image:Chasseurdemonstresicone.png|link=Chasseur de monstres]] [[Chasseur de monstres|Monstres]]&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;display: flex; flex-direction: column; white-space: nowrap;&amp;quot; data-skill=&amp;quot;eagleEye&amp;quot;&amp;gt;[[Image:Regardpercanticone.png|link=Regard perçant]] [[Regard perçant]]&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;display: flex; flex-direction: column; white-space: nowrap;&amp;quot; data-skill=&amp;quot;drain&amp;quot;&amp;gt;[[Image:Sangsueicone.png|link=Sangsue]] [[Sangsue]]&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;span style=&amp;quot;display: flex; flex-direction: column; white-space: nowrap;&amp;quot; data-skill=&amp;quot;feather&amp;quot;&amp;gt;[[Image:Poidsplumeicone.png|link=Poids plume]] [[Poids plume]]&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;span data-type=&amp;quot;0&amp;quot;&amp;gt;Type 1&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;span data-type=&amp;quot;1&amp;quot;&amp;gt;Type 2&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;span data-type=&amp;quot;2&amp;quot;&amp;gt;Type 3&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;span data-type=&amp;quot;3&amp;quot;&amp;gt;Type 4&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;span data-type=&amp;quot;4&amp;quot;&amp;gt;Type 5&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;span data-type=&amp;quot;5&amp;quot;&amp;gt;Type 6&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;span data-type=&amp;quot;6&amp;quot;&amp;gt;Type 7&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;span data-type=&amp;quot;7&amp;quot;&amp;gt;Type 8&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;span data-level=&amp;quot;0&amp;quot;&amp;gt;81&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;span data-level=&amp;quot;1&amp;quot;&amp;gt;82&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;span data-level=&amp;quot;2&amp;quot;&amp;gt;83&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;span data-level=&amp;quot;3&amp;quot;&amp;gt;84&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;span data-level=&amp;quot;4&amp;quot;&amp;gt;85&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;span data-level=&amp;quot;5&amp;quot;&amp;gt;86&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;span data-level=&amp;quot;6&amp;quot;&amp;gt;87&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;span data-level=&amp;quot;7&amp;quot;&amp;gt;88&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;span data-level=&amp;quot;8&amp;quot;&amp;gt;89&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;span data-level=&amp;quot;9&amp;quot;&amp;gt;90&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;span data-level=&amp;quot;10&amp;quot;&amp;gt;91&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;span data-level=&amp;quot;11&amp;quot;&amp;gt;92&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;span data-level=&amp;quot;12&amp;quot;&amp;gt;93&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;span data-level=&amp;quot;13&amp;quot;&amp;gt;94&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;span data-level=&amp;quot;14&amp;quot;&amp;gt;95&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;span data-level=&amp;quot;15&amp;quot;&amp;gt;96&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;span data-level=&amp;quot;16&amp;quot;&amp;gt;97&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;span data-level=&amp;quot;17&amp;quot;&amp;gt;98&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;span data-level=&amp;quot;18&amp;quot;&amp;gt;99&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;span data-level=&amp;quot;19&amp;quot;&amp;gt;100&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;span data-level=&amp;quot;20&amp;quot;&amp;gt;101&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;span data-level=&amp;quot;21&amp;quot;&amp;gt;102&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;span data-level=&amp;quot;22&amp;quot;&amp;gt;103&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;span data-level=&amp;quot;23&amp;quot;&amp;gt;104&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;span data-level=&amp;quot;24&amp;quot;&amp;gt;105&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
{{LoadJavascript|Script=element}}&lt;br /&gt;
{{LoadJavascript|Script=pets}}&lt;br /&gt;
{{Form|id=edit-table|style=display: flex; margin-bottom: 10px; flex-wrap: wrap;|content=&lt;br /&gt;
{{Select|id=axis-x|name=axisX|content=&lt;br /&gt;
{{Option|value=pet|text=Familiers|selected=True}}&lt;br /&gt;
{{Option|value=skill|text=Compétences}}&lt;br /&gt;
{{Option|value=type|text=Types}}&lt;br /&gt;
{{Option|value=level|text=Niveaux}}&lt;br /&gt;
}}&lt;br /&gt;
{{Select|id=axis-y|name=axisY|content=&lt;br /&gt;
{{Option|value=pet|text=Familiers}}&lt;br /&gt;
{{Option|value=skill|text=Compétences|selected=True}}&lt;br /&gt;
{{Option|value=type|text=Types}}&lt;br /&gt;
{{Option|value=level|text=Niveaux}}&lt;br /&gt;
}}&lt;br /&gt;
{{Select|id=pet|name=pet|content=&lt;br /&gt;
{{Option|value=monkey|text=singe}}&lt;br /&gt;
{{Option|value=spider|text=araignée}}&lt;br /&gt;
{{Option|value=razador|text=razador}}&lt;br /&gt;
{{Option|value=nemere|text=nemere}}&lt;br /&gt;
{{Option|value=dragonette|text=dragon bleu}}&lt;br /&gt;
{{Option|value=meley|text=meley}}&lt;br /&gt;
{{Option|value=azrael|text=azraël}}&lt;br /&gt;
{{Option|value=executor|text=bourreau}}&lt;br /&gt;
{{Option|value=baashido|text=baashido}}&lt;br /&gt;
{{Option|value=nessie|text=nessie}}&lt;br /&gt;
{{Option|value=exedyar|text=exedyar}}&lt;br /&gt;
{{Option|value=alastor|text=alastor}}&lt;br /&gt;
{{Option|value=boss|text=mini commandant}}&lt;br /&gt;
}}&lt;br /&gt;
{{Select|id=skill|name=skill|content=&lt;br /&gt;
{{Option|value=warrior|text=anti G}}&lt;br /&gt;
{{Option|value=sura|text=anti S}}&lt;br /&gt;
{{Option|value=ninja|text=anti N}}&lt;br /&gt;
{{Option|value=shaman|text=anti Sh}}&lt;br /&gt;
{{Option|value=lycan|text=anti L}}&lt;br /&gt;
{{Option|value=berserker|text=berserker}}&lt;br /&gt;
{{Option|value=antiMagic|text=anti magie}}&lt;br /&gt;
{{Option|value=haste|text=accélération}}&lt;br /&gt;
{{Option|value=drill|text=drill}}&lt;br /&gt;
{{Option|value=restoration|text=renouvellemnt}}&lt;br /&gt;
{{Option|value=vampirism|text=vampire}}&lt;br /&gt;
{{Option|value=spiritualism|text=fantômes}}&lt;br /&gt;
{{Option|value=bulwark|text=obstable}}&lt;br /&gt;
{{Option|value=reflection|text=miroir}}&lt;br /&gt;
{{Option|value=yang|text=yang}}&lt;br /&gt;
{{Option|value=range|text=portée}}&lt;br /&gt;
{{Option|value=immortal|text=invincibilité}}&lt;br /&gt;
{{Option|value=panacea|text=soins}}&lt;br /&gt;
{{Option|value=masterBrewer|text=maître brasseur}}&lt;br /&gt;
{{Option|value=monster|text=monstre}}&lt;br /&gt;
{{Option|value=eagleEye|text=regard perçant}}&lt;br /&gt;
{{Option|value=drain|text=sangsue}}&lt;br /&gt;
{{Option|value=feather|text=poids plume}}&lt;br /&gt;
}}&lt;br /&gt;
{{Select|id=type|name=type|content=&lt;br /&gt;
{{Option|value=0|text=T1}}&lt;br /&gt;
{{Option|value=1|text=T2}}&lt;br /&gt;
{{Option|value=2|text=T3}}&lt;br /&gt;
{{Option|value=3|text=T4}}&lt;br /&gt;
{{Option|value=4|text=T5}}&lt;br /&gt;
{{Option|value=5|text=T6}}&lt;br /&gt;
{{Option|value=6|text=T7}}&lt;br /&gt;
{{Option|value=7|text=T8}}&lt;br /&gt;
}}&lt;br /&gt;
{{Select|id=level|name=level|content=&lt;br /&gt;
{{Option|value=0|text=81}}&lt;br /&gt;
{{Option|value=1|text=82}}&lt;br /&gt;
{{Option|value=2|text=83}}&lt;br /&gt;
{{Option|value=3|text=84}}&lt;br /&gt;
{{Option|value=4|text=85}}&lt;br /&gt;
{{Option|value=5|text=86}}&lt;br /&gt;
{{Option|value=6|text=87}}&lt;br /&gt;
{{Option|value=7|text=88}}&lt;br /&gt;
{{Option|value=8|text=89}}&lt;br /&gt;
{{Option|value=9|text=90}}&lt;br /&gt;
{{Option|value=10|text=91}}&lt;br /&gt;
{{Option|value=11|text=92}}&lt;br /&gt;
{{Option|value=12|text=93}}&lt;br /&gt;
{{Option|value=13|text=94}}&lt;br /&gt;
{{Option|value=14|text=95}}&lt;br /&gt;
{{Option|value=15|text=96}}&lt;br /&gt;
{{Option|value=16|text=97}}&lt;br /&gt;
{{Option|value=17|text=98}}&lt;br /&gt;
{{Option|value=18|text=99}}&lt;br /&gt;
{{Option|value=19|text=100}}&lt;br /&gt;
{{Option|value=20|text=101}}&lt;br /&gt;
{{Option|value=21|text=102}}&lt;br /&gt;
{{Option|value=22|text=103}}&lt;br /&gt;
{{Option|value=23|text=104}}&lt;br /&gt;
{{Option|value=24|text=105}}&lt;br /&gt;
}}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;width: max-content; max-width: 100%; min-height: max(100%, 400px); height: 60vh; max-height: 100%; overflow: auto; resize: both;&amp;quot;&amp;gt;&lt;br /&gt;
{| id=&amp;quot;pet-values&amp;quot; style=&amp;quot;border-spacing: 0; border-collapse: collapse; text-align: center;&amp;quot; class=&amp;quot;sticky-header-row sticky-header-column&amp;quot;&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
Catégories de compétences.&lt;br /&gt;
&amp;lt;div style=&amp;quot;display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 7px; text-align: center;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;border:1px black solid; border-radius: 8px; overflow: hidden;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;fondfenetre&amp;quot; style=&amp;quot;display: flex; justify-content: center; gap: 5px; align-items: center; padding: 2px 5px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div&amp;gt;[[Image:Livredecompetence.png|25px|link=Compétences de classe]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div&amp;gt;[[Compétences de classe]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div&amp;gt;[[Image:Weiliaozi.png|25px|link=Compétences de classe]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;display: flex; justify-content: center;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;display: flex; justify-content: center;&amp;quot;&amp;gt;[[File:Competencedeclasseanimation.gif|link=Compétences de classe]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;border:1px black solid; border-radius: 8px; overflow: hidden;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;fondfenetre&amp;quot; style=&amp;quot;display: flex; justify-content: center; gap: 5px; align-items: center; padding: 2px 5px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div&amp;gt;[[Image:Livredeparade.png|25px|link=]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div&amp;gt;Parade &amp;amp; Bonus&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div&amp;gt;[[Image:Livredebonus.png|25px|link=]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding: 5px;&amp;quot;&amp;gt;Image&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;border:1px black solid; border-radius: 8px; overflow: hidden;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;fondfenetre&amp;quot; style=&amp;quot;display: flex; justify-content: center; gap: 5px; align-items: center; padding: 2px 5px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div&amp;gt;[[Image:9ecompetence.png|25px|link=]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div&amp;gt;9&amp;lt;sup&amp;gt;e&amp;lt;/sup&amp;gt; compétence&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div&amp;gt;[[Image:9ecompetence.png|25px|link=]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding: 5px;&amp;quot;&amp;gt;Image&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;border:1px black solid; border-radius: 8px; overflow: hidden;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;fondfenetre&amp;quot; style=&amp;quot;display: flex; justify-content: center; gap: 5px; align-items: center; padding: 2px 5px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div&amp;gt;[[Image:Livredeprecision.png|25px|link=]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div&amp;gt;Compétences secondaires&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div&amp;gt;[[Image:Lartdeguerresunzi.png|25px|link=]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding: 5px;&amp;quot;&amp;gt;Image&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;border:1px black solid; border-radius: 8px; overflow: hidden;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;fondfenetre&amp;quot; style=&amp;quot;display: flex; justify-content: center; gap: 5px; align-items: center; padding: 2px 5px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div&amp;gt;[[Image:Manueldequitation.png|25px|link=]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div&amp;gt;Compétences de monture&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div&amp;gt;[[Image:Competencecheval2.png|25px|link=]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding: 5px;&amp;quot;&amp;gt;Image&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;border:1px black solid; border-radius: 8px; overflow: hidden;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;fondfenetre&amp;quot; style=&amp;quot;display: flex; justify-content: center; gap: 5px; align-items: center; padding: 2px 5px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div&amp;gt;[[Image:Livredefamilierrouge.png|25px|link=]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div&amp;gt;Compétences de familier&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div&amp;gt;[[Image:Livredefamilierbleu.png|25px|link=]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding: 5px;&amp;quot;&amp;gt;Image&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
hello world&lt;br /&gt;
chocolat&lt;/div&gt;</summary>
		<author><name>Dexter</name></author>
		
	</entry>
	<entry>
		<id>https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Script/Calculator.js&amp;diff=106014</id>
		<title>MediaWiki:Script/Calculator.js</title>
		<link rel="alternate" type="text/html" href="https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Script/Calculator.js&amp;diff=106014"/>
		<updated>2024-12-27T01:14:15Z</updated>

		<summary type="html">&lt;p&gt;Dexter : v0.17&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;function removeAccent(str) {&lt;br /&gt;
  return str.normalize(&amp;quot;NFD&amp;quot;).replace(/[\u0300-\u036f]/g, &amp;quot;&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function pseudoFormat(str) {&lt;br /&gt;
  return removeAccent(str).replace(/[^A-Za-z0-9 \(\)\+_-]+/g, &amp;quot;&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isValueInArray(value, array) {&lt;br /&gt;
  return array.indexOf(value) !== -1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function copyObject(object) {&lt;br /&gt;
  var copy = {};&lt;br /&gt;
  for (var key in object) {&lt;br /&gt;
    copy[key] = object[key];&lt;br /&gt;
  }&lt;br /&gt;
  return copy;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function compareNumbers(a, b) {&lt;br /&gt;
  return b - a;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isChecked(attribute) {&lt;br /&gt;
  return attribute === &amp;quot;on&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function floorMultiplication(firstFactor, secondFactor) {&lt;br /&gt;
  return Math.floor((firstFactor * secondFactor).toFixed(8));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function truncateNumber(number, precision) {&lt;br /&gt;
  return Math.floor(number * 10 ** precision) / 10 ** precision;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addKeyValue(object, key, value) {&lt;br /&gt;
  if (object.hasOwnProperty(key)) {&lt;br /&gt;
    object[key] += value;&lt;br /&gt;
  } else {&lt;br /&gt;
    object[key] = value;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function openTargetTab(target) {&lt;br /&gt;
  var tabberContainer = target.closest(&amp;quot;.tabber-container&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (!tabberContainer) {&lt;br /&gt;
    return;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var [buttonsContainer, tabsContainer] = tabberContainer.children;&lt;br /&gt;
  var buttons = buttonsContainer.children;&lt;br /&gt;
  var tabs = tabsContainer.children;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; tabs.length; index++) {&lt;br /&gt;
    var tab = tabs[index];&lt;br /&gt;
    if (tab.contains(target) &amp;amp;&amp;amp; !tab.checkVisibility()) {&lt;br /&gt;
      buttons[index].click();&lt;br /&gt;
      break;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function openTargetCollapsible(target) {&lt;br /&gt;
  var collapsible = target.closest(&amp;quot;.improved-collapsible&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (!collapsible) {&lt;br /&gt;
    return;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var span = collapsible.firstElementChild;&lt;br /&gt;
&lt;br /&gt;
  if (!span.classList.contains(&amp;quot;mw-collapsible-toggle-expanded&amp;quot;)) {&lt;br /&gt;
    span.click();&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function editTableResultRow(row, valuesToDisplay, numberFormat) {&lt;br /&gt;
  row.innerHTML = &amp;quot;&amp;quot;;&lt;br /&gt;
  for (var index = 0; index &amp;lt; valuesToDisplay.length; index++) {&lt;br /&gt;
    var cell = row.insertCell();&lt;br /&gt;
    var textContent;&lt;br /&gt;
&lt;br /&gt;
    if (index &amp;gt;= 3) {&lt;br /&gt;
      textContent = numberFormat.format(valuesToDisplay[index]);&lt;br /&gt;
    } else {&lt;br /&gt;
      textContent = valuesToDisplay[index];&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    cell.textContent = textContent;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return row;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addRowToTableResultHistory(&lt;br /&gt;
  tableResultHistory,&lt;br /&gt;
  valuesToDisplay,&lt;br /&gt;
  deleteFightTemplate,&lt;br /&gt;
  numberFormat&lt;br /&gt;
) {&lt;br /&gt;
  var row = tableResultHistory.insertRow();&lt;br /&gt;
  editTableResultRow(row, valuesToDisplay, numberFormat);&lt;br /&gt;
  var cell = row.insertCell();&lt;br /&gt;
  cell.appendChild(deleteFightTemplate.cloneNode(true));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcMeanDamages(damagesWeightedByType, totalCardinal) {&lt;br /&gt;
  var sumDamages = 0;&lt;br /&gt;
&lt;br /&gt;
  for (var damagesTypeName in damagesWeightedByType) {&lt;br /&gt;
    if (damagesTypeName === &amp;quot;miss&amp;quot;) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var damagesWeighted = damagesWeightedByType[damagesTypeName];&lt;br /&gt;
&lt;br /&gt;
    for (var damages in damagesWeighted) {&lt;br /&gt;
      sumDamages += damages * damagesWeighted[damages];&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return sumDamages / totalCardinal;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function prepareDamagesData(&lt;br /&gt;
  damagesWeightedByType,&lt;br /&gt;
  possibleDamagesCountTemp,&lt;br /&gt;
  totalCardinal&lt;br /&gt;
) {&lt;br /&gt;
  var minDamages = Infinity;&lt;br /&gt;
  var maxDamages = 0;&lt;br /&gt;
  var scatterDataByType = {};&lt;br /&gt;
  var sumDamages = 0;&lt;br /&gt;
  var possibleDamagesCount = 0;&lt;br /&gt;
  var uniqueDamagesCount = 0;&lt;br /&gt;
&lt;br /&gt;
  for (var damagesTypeName in damagesWeightedByType) {&lt;br /&gt;
    if (damagesTypeName === &amp;quot;miss&amp;quot;) {&lt;br /&gt;
      scatterDataByType.miss = damagesWeightedByType.miss;&lt;br /&gt;
      possibleDamagesCount++;&lt;br /&gt;
      uniqueDamagesCount++;&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var firstIteration = true;&lt;br /&gt;
    var damagesWeighted = damagesWeightedByType[damagesTypeName];&lt;br /&gt;
    var scatterData = [];&lt;br /&gt;
    scatterDataByType[damagesTypeName] = scatterData;&lt;br /&gt;
&lt;br /&gt;
    for (var damages in damagesWeighted) {&lt;br /&gt;
      damages = +damages;&lt;br /&gt;
&lt;br /&gt;
      if (firstIteration) {&lt;br /&gt;
        if (damages &amp;lt; minDamages) {&lt;br /&gt;
          minDamages = damages;&lt;br /&gt;
        }&lt;br /&gt;
        firstIteration = false;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      var weight = damagesWeighted[damages];&lt;br /&gt;
      var probability = weight / totalCardinal;&lt;br /&gt;
&lt;br /&gt;
      sumDamages += damages * weight;&lt;br /&gt;
      damagesWeighted[damages] = probability;&lt;br /&gt;
      scatterData.push({ x: damages, y: probability });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var scatterDataLength = scatterData.length;&lt;br /&gt;
&lt;br /&gt;
    possibleDamagesCount += possibleDamagesCountTemp;&lt;br /&gt;
    uniqueDamagesCount += scatterDataLength;&lt;br /&gt;
&lt;br /&gt;
    if (damages &amp;gt; maxDamages) {&lt;br /&gt;
      maxDamages = damages;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (minDamages === Infinity) {&lt;br /&gt;
    minDamages = 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return [&lt;br /&gt;
    sumDamages / totalCardinal,&lt;br /&gt;
    minDamages,&lt;br /&gt;
    maxDamages,&lt;br /&gt;
    scatterDataByType,&lt;br /&gt;
    possibleDamagesCount,&lt;br /&gt;
    uniqueDamagesCount,&lt;br /&gt;
  ];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function aggregateDamages(scatterData, maxPoints) {&lt;br /&gt;
  var dataLength = scatterData.length;&lt;br /&gt;
  var remainingData = dataLength;&lt;br /&gt;
  var aggregateScatterData = [];&lt;br /&gt;
&lt;br /&gt;
  for (var groupIndex = 0; groupIndex &amp;lt; maxPoints; groupIndex++) {&lt;br /&gt;
    var groupLength = Math.floor(remainingData / (maxPoints - groupIndex));&lt;br /&gt;
    var startIndex = dataLength - remainingData;&lt;br /&gt;
    var aggregateDamages = 0;&lt;br /&gt;
    var aggregateProbability = 0;&lt;br /&gt;
&lt;br /&gt;
    for (var index = startIndex; index &amp;lt; startIndex + groupLength; index++) {&lt;br /&gt;
      var { x: damages, y: probability } = scatterData[index];&lt;br /&gt;
      aggregateDamages += damages * probability;&lt;br /&gt;
      aggregateProbability += probability;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    aggregateScatterData.push({&lt;br /&gt;
      x: aggregateDamages / aggregateProbability,&lt;br /&gt;
      y: aggregateProbability,&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    remainingData -= groupLength;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return aggregateScatterData;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addToDamagesChart(&lt;br /&gt;
  scatterDataByType,&lt;br /&gt;
  damagesChart,&lt;br /&gt;
  isReducePointsChecked&lt;br /&gt;
) {&lt;br /&gt;
  var { chart, datasetsStyle, maxPoints, reduceChartPointsContainer } =&lt;br /&gt;
    damagesChart;&lt;br /&gt;
  var isFirstDataset = true;&lt;br /&gt;
  var datasets = chart.data.datasets;&lt;br /&gt;
&lt;br /&gt;
  datasets.length = 0;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; datasetsStyle.length; index++) {&lt;br /&gt;
    var dataset = copyObject(datasetsStyle[index]);&lt;br /&gt;
&lt;br /&gt;
    if (!scatterDataByType.hasOwnProperty(dataset.name)) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var scatterData = scatterDataByType[dataset.name];&lt;br /&gt;
    var canBeReduced = scatterData.length &amp;gt; 2 * maxPoints;&lt;br /&gt;
&lt;br /&gt;
    dataset.hidden = !isFirstDataset;&lt;br /&gt;
    dataset.canBeReduced = canBeReduced;&lt;br /&gt;
&lt;br /&gt;
    if (canBeReduced &amp;amp;&amp;amp; isReducePointsChecked) {&lt;br /&gt;
      dataset.data = aggregateDamages(scatterData, maxPoints);&lt;br /&gt;
    } else {&lt;br /&gt;
      dataset.data = scatterData;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isFirstDataset) {&lt;br /&gt;
      isFirstDataset = false;&lt;br /&gt;
&lt;br /&gt;
      if (canBeReduced) {&lt;br /&gt;
        showElement(reduceChartPointsContainer);&lt;br /&gt;
&lt;br /&gt;
        if (!isReducePointsChecked) {&lt;br /&gt;
          handleChartAnimations(chart, false);&lt;br /&gt;
        }&lt;br /&gt;
      } else {&lt;br /&gt;
        hideElement(reduceChartPointsContainer);&lt;br /&gt;
        handleChartAnimations(chart, true);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    datasets.push(dataset);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  chart.data.missPercentage = scatterDataByType.miss;&lt;br /&gt;
  chart.update();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addToBonusVariationChart(&lt;br /&gt;
  damagesByBonus,&lt;br /&gt;
  augmentationByBonus,&lt;br /&gt;
  xLabel,&lt;br /&gt;
  chart&lt;br /&gt;
) {&lt;br /&gt;
  chart.data.datasets[0].data = damagesByBonus;&lt;br /&gt;
  chart.data.datasets[1].data = augmentationByBonus;&lt;br /&gt;
  chart.options.scales.x.title.text = xLabel;&lt;br /&gt;
  chart.update();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleChartAnimations(chart, addAnimations) {&lt;br /&gt;
  chart.options.animation = addAnimations;&lt;br /&gt;
  chart.options.animations.colors = addAnimations;&lt;br /&gt;
  chart.options.animations.x = addAnimations;&lt;br /&gt;
  chart.options.transitions.active.animation.duration = addAnimations * 1000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateDamagesChartDescription(&lt;br /&gt;
  uniqueDamagesCounters,&lt;br /&gt;
  uniqueDamagesCount,&lt;br /&gt;
  formatNumber&lt;br /&gt;
) {&lt;br /&gt;
  uniqueDamagesCounters.forEach(function (element) {&lt;br /&gt;
    if (uniqueDamagesCount &amp;lt;= 1) {&lt;br /&gt;
      hideElement(element.parentElement);&lt;br /&gt;
    } else {&lt;br /&gt;
      showElement(element.parentElement);&lt;br /&gt;
      element.textContent = formatNumber.format(uniqueDamagesCount);&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getMonsterName(monsterVnum) {&lt;br /&gt;
  var monsterAttributes = monsterData[monsterVnum];&lt;br /&gt;
  return monsterAttributes[monsterAttributes.length - 1];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterClass(selectedRace, classChoice, selectValueIsChanged = false) {&lt;br /&gt;
  showElement(classChoice.parentElement);&lt;br /&gt;
&lt;br /&gt;
  for (var option of classChoice.options) {&lt;br /&gt;
    if (option.getAttribute(&amp;quot;data-race&amp;quot;) === selectedRace) {&lt;br /&gt;
      if (!selectValueIsChanged) {&lt;br /&gt;
        classChoice.value = option.value;&lt;br /&gt;
        selectValueIsChanged = true;&lt;br /&gt;
      }&lt;br /&gt;
      showElement(option);&lt;br /&gt;
    } else {&lt;br /&gt;
      hideElement(option);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  if (selectedRace == &amp;quot;lycan&amp;quot;) {&lt;br /&gt;
    hideElement(classChoice.parentElement);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterWeapon(&lt;br /&gt;
  selectedRace,&lt;br /&gt;
  weaponElement,&lt;br /&gt;
  weaponCategory,&lt;br /&gt;
  allowedWeaponsPerRace,&lt;br /&gt;
  selectValueIsChanged = false&lt;br /&gt;
) {&lt;br /&gt;
  var allowedWeapons = allowedWeaponsPerRace[selectedRace];&lt;br /&gt;
&lt;br /&gt;
  if (!selectValueIsChanged) {&lt;br /&gt;
    var weaponType = createWeapon(weaponElement.value).type;&lt;br /&gt;
&lt;br /&gt;
    if (!isValueInArray(weaponType, allowedWeapons)) {&lt;br /&gt;
      weaponElement.value = 0;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var children = weaponCategory.children;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; children.length; index++) {&lt;br /&gt;
    var child = children[index];&lt;br /&gt;
&lt;br /&gt;
    if (isValueInArray(index, allowedWeapons)) {&lt;br /&gt;
      showElement(child);&lt;br /&gt;
    } else {&lt;br /&gt;
      hideElement(child);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function changePolymorphValues(characterCreation, monsterVnum, monsterImage) {&lt;br /&gt;
  var { polymorphMonster, polymorphMonsterImage } = characterCreation;&lt;br /&gt;
  var changeEvent = new Event(&amp;quot;change&amp;quot;, { bubbles: true });&lt;br /&gt;
&lt;br /&gt;
  polymorphMonster.value = monsterVnum;&lt;br /&gt;
  polymorphMonsterImage.value = monsterImage;&lt;br /&gt;
&lt;br /&gt;
  polymorphMonster.dispatchEvent(changeEvent);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handlePolymorphDisplay(polymorphDisplay, monsterVnum, monsterSrc) {&lt;br /&gt;
  var newLink = document.createElement(&amp;quot;a&amp;quot;);&lt;br /&gt;
  var oldImage = polymorphDisplay.firstChild;&lt;br /&gt;
  var oldLink = oldImage.nextElementSibling;&lt;br /&gt;
  var monsterName = getMonsterName(monsterVnum);&lt;br /&gt;
&lt;br /&gt;
  oldImage.src = monsterSrc;&lt;br /&gt;
  oldImage.alt = monsterSrc.split(&amp;quot;/&amp;quot;).pop();&lt;br /&gt;
  oldImage.removeAttribute(&amp;quot;srcset&amp;quot;);&lt;br /&gt;
  newLink.href = mw.util.getUrl(monsterName);&lt;br /&gt;
  newLink.title = monsterName;&lt;br /&gt;
  newLink.textContent = monsterName;&lt;br /&gt;
&lt;br /&gt;
  polymorphDisplay.replaceChild(newLink, oldLink);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSelectedWeapon(weaponCategory) {&lt;br /&gt;
  return weaponCategory.querySelector(&amp;quot;input[type='radio']:checked&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleWeaponDisplay(&lt;br /&gt;
  weaponCategory,&lt;br /&gt;
  weaponDisplay,&lt;br /&gt;
  weaponVnum,&lt;br /&gt;
  newWeapon&lt;br /&gt;
) {&lt;br /&gt;
  var newWeapon = newWeapon || getSelectedWeapon(weaponCategory);&lt;br /&gt;
&lt;br /&gt;
  var newImage = newWeapon.nextElementSibling;&lt;br /&gt;
  var newText = document.createElement(&amp;quot;span&amp;quot;);&lt;br /&gt;
  var oldImage = weaponDisplay.firstChild;&lt;br /&gt;
  var oldText = oldImage.nextElementSibling;&lt;br /&gt;
  var weaponName = newImage.nextElementSibling.dataset.o;&lt;br /&gt;
&lt;br /&gt;
  if (weaponVnum == 0) {&lt;br /&gt;
    newText.textContent = &amp;quot; &amp;quot; + weaponName + &amp;quot; &amp;quot;;&lt;br /&gt;
  } else {&lt;br /&gt;
    var weaponLink = document.createElement(&amp;quot;a&amp;quot;);&lt;br /&gt;
    weaponLink.href = mw.util.getUrl(weaponName);&lt;br /&gt;
    weaponLink.title = weaponName;&lt;br /&gt;
    weaponLink.textContent = weaponName;&lt;br /&gt;
&lt;br /&gt;
    newText.appendChild(document.createTextNode(&amp;quot; &amp;quot;));&lt;br /&gt;
    newText.appendChild(weaponLink);&lt;br /&gt;
    newText.appendChild(document.createTextNode(&amp;quot; &amp;quot;));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  weaponDisplay.replaceChild(newImage.cloneNode(), oldImage);&lt;br /&gt;
  weaponDisplay.replaceChild(newText, oldText);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterUpgrade(&lt;br /&gt;
  weaponUpgrade,&lt;br /&gt;
  weaponVnum,&lt;br /&gt;
  randomAttackValue,&lt;br /&gt;
  randomMagicAttackValue&lt;br /&gt;
) {&lt;br /&gt;
  var weapon = createWeapon(weaponVnum);&lt;br /&gt;
  var currentUpgrade = Number(weaponUpgrade.value);&lt;br /&gt;
&lt;br /&gt;
  if (weapon.isSerpent) {&lt;br /&gt;
    showElement(randomAttackValue);&lt;br /&gt;
&lt;br /&gt;
    if (weapon.isMagic) {&lt;br /&gt;
      showElement(randomMagicAttackValue);&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    hideElement(randomAttackValue);&lt;br /&gt;
    hideElement(randomMagicAttackValue);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (weapon.maxUpgrade &amp;lt; 1) {&lt;br /&gt;
    hideElement(weaponUpgrade.parentElement);&lt;br /&gt;
  } else {&lt;br /&gt;
    showElement(weaponUpgrade.parentElement);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  weaponUpgrade.innerHTML = &amp;quot;&amp;quot;;&lt;br /&gt;
  var lastOption;&lt;br /&gt;
&lt;br /&gt;
  for (var upgrade = 0; upgrade &amp;lt;= weapon.maxUpgrade; upgrade++) {&lt;br /&gt;
    var option = document.createElement(&amp;quot;option&amp;quot;);&lt;br /&gt;
    option.value = upgrade;&lt;br /&gt;
    option.textContent = &amp;quot;+&amp;quot; + upgrade;&lt;br /&gt;
    weaponUpgrade.appendChild(option);&lt;br /&gt;
&lt;br /&gt;
    if (upgrade === currentUpgrade) {&lt;br /&gt;
      option.selected = true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    lastOption = option;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if ((currentUpgrade &amp;gt; weapon.maxUpgrade || !currentUpgrade) &amp;amp;&amp;amp; lastOption) {&lt;br /&gt;
    lastOption.selected = true;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterCheckbox(checkbox, element) {&lt;br /&gt;
  if (checkbox.checked) {&lt;br /&gt;
    showElement(element);&lt;br /&gt;
  } else {&lt;br /&gt;
    hideElement(element);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterSkills(selectedClass, skillElementsToFilter) {&lt;br /&gt;
  for (var element of skillElementsToFilter) {&lt;br /&gt;
    if (isValueInArray(selectedClass, element.dataset.class)) {&lt;br /&gt;
      showElement(element);&lt;br /&gt;
    } else {&lt;br /&gt;
      hideElement(element);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterAttackTypeSelection(attacker, attackTypeSelection) {&lt;br /&gt;
  var attackerClass = attacker.class;&lt;br /&gt;
  var selectedOption =&lt;br /&gt;
    attackTypeSelection.options[attackTypeSelection.selectedIndex];&lt;br /&gt;
  var attackerIsNotPolymorph = !isPolymorph(attacker);&lt;br /&gt;
&lt;br /&gt;
  for (var index = 2; index &amp;lt; attackTypeSelection.options.length; index++) {&lt;br /&gt;
    var option = attackTypeSelection.options[index];&lt;br /&gt;
    var optionClass = option.dataset.class;&lt;br /&gt;
    var optionValue = option.value;&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      attackerIsNotPolymorph &amp;amp;&amp;amp;&lt;br /&gt;
      attacker[optionValue] &amp;amp;&amp;amp;&lt;br /&gt;
      (attackerClass === optionClass ||&lt;br /&gt;
        (optionValue.startsWith(&amp;quot;horseSkill&amp;quot;) &amp;amp;&amp;amp;&lt;br /&gt;
          isRiding(attacker) &amp;amp;&amp;amp;&lt;br /&gt;
          (!optionClass || isValueInArray(attackerClass, optionClass))))&lt;br /&gt;
    ) {&lt;br /&gt;
      showElement(option);&lt;br /&gt;
    } else {&lt;br /&gt;
      hideElement(option);&lt;br /&gt;
&lt;br /&gt;
      if (selectedOption === option) {&lt;br /&gt;
        attackTypeSelection.selectedIndex = 0;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterAttackTypeSelectionMonster(attackTypeSelection) {&lt;br /&gt;
  for (var index = 2; index &amp;lt; attackTypeSelection.options.length; index++) {&lt;br /&gt;
    hideElement(attackTypeSelection.options[index]);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (attackTypeSelection.selectedIndex !== 1) {&lt;br /&gt;
    attackTypeSelection.selectedIndex = 0;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterForm(characters, battle) {&lt;br /&gt;
  var characterCreation = characters.characterCreation;&lt;br /&gt;
  var allowedWeaponsPerRace = battle.constants.allowedWeaponsPerRace;&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;change&amp;quot;, function (event) {&lt;br /&gt;
    var target = event.target;&lt;br /&gt;
    var targetName = target.name;&lt;br /&gt;
&lt;br /&gt;
    switch (targetName) {&lt;br /&gt;
      case &amp;quot;race&amp;quot;:&lt;br /&gt;
        var selectedRace = target.value;&lt;br /&gt;
        var classChoice = characterCreation.class;&lt;br /&gt;
        var weaponElement = characterCreation.weapon;&lt;br /&gt;
&lt;br /&gt;
        filterClass(selectedRace, classChoice);&lt;br /&gt;
        filterWeapon(&lt;br /&gt;
          selectedRace,&lt;br /&gt;
          weaponElement,&lt;br /&gt;
          characters.weaponCategory,&lt;br /&gt;
          allowedWeaponsPerRace&lt;br /&gt;
        );&lt;br /&gt;
        handleWeaponDisplay(&lt;br /&gt;
          characters.weaponCategory,&lt;br /&gt;
          characters.weaponDisplay,&lt;br /&gt;
          weaponElement.value&lt;br /&gt;
        );&lt;br /&gt;
        filterUpgrade(&lt;br /&gt;
          characterCreation.weaponUpgrade,&lt;br /&gt;
          weaponElement.value,&lt;br /&gt;
          characters.randomAttackValue,&lt;br /&gt;
          characters.randomMagicAttackValue&lt;br /&gt;
        );&lt;br /&gt;
        filterSkills(classChoice.value, characters.skillElementsToFilter);&lt;br /&gt;
        handleBonusVariationUpdate(&lt;br /&gt;
          characterCreation,&lt;br /&gt;
          characters.bonusVariation,&lt;br /&gt;
          true&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        if (characterCreation.name.value === battle.attackerSelection.value) {&lt;br /&gt;
          battle.resetAttackType = true;&lt;br /&gt;
        }&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;class&amp;quot;:&lt;br /&gt;
        filterSkills(target.value, characters.skillElementsToFilter);&lt;br /&gt;
        handleBonusVariationUpdate(&lt;br /&gt;
          characterCreation,&lt;br /&gt;
          characters.bonusVariation,&lt;br /&gt;
          true&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        if (characterCreation.name.value === battle.attackerSelection.value) {&lt;br /&gt;
          battle.resetAttackType = true;&lt;br /&gt;
        }&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;weapon&amp;quot;:&lt;br /&gt;
        var weaponElement = characterCreation.weapon;&lt;br /&gt;
&lt;br /&gt;
        handleWeaponDisplay(&lt;br /&gt;
          characters.weaponCategory,&lt;br /&gt;
          characters.weaponDisplay,&lt;br /&gt;
          weaponElement.value,&lt;br /&gt;
          target&lt;br /&gt;
        );&lt;br /&gt;
        filterUpgrade(&lt;br /&gt;
          characterCreation.weaponUpgrade,&lt;br /&gt;
          target.value,&lt;br /&gt;
          characters.randomAttackValue,&lt;br /&gt;
          characters.randomMagicAttackValue&lt;br /&gt;
        );&lt;br /&gt;
        handleBonusVariationUpdate(&lt;br /&gt;
          characterCreation,&lt;br /&gt;
          characters.bonusVariation&lt;br /&gt;
        );&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;isPolymorph&amp;quot;:&lt;br /&gt;
        filterCheckbox(target, characters.polymorphCreation);&lt;br /&gt;
        if (characterCreation.name.value === battle.attackerSelection.value) {&lt;br /&gt;
          battle.resetAttackType = true;&lt;br /&gt;
        }&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;lowRank&amp;quot;:&lt;br /&gt;
        filterCheckbox(target, characterCreation.playerRank.parentElement);&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;isBlessed&amp;quot;:&lt;br /&gt;
        filterCheckbox(target, characters.blessingCreation);&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;onYohara&amp;quot;:&lt;br /&gt;
        filterCheckbox(target, characters.yoharaCreation);&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;isMarried&amp;quot;:&lt;br /&gt;
        filterCheckbox(target, characters.marriageCreation);&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;useBonusVariation&amp;quot;:&lt;br /&gt;
        filterCheckbox(target, characters.bonusVariation.container);&lt;br /&gt;
        break;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      targetName.startsWith(&amp;quot;attackSkill&amp;quot;) ||&lt;br /&gt;
      targetName.startsWith(&amp;quot;horseSkill&amp;quot;)&lt;br /&gt;
    ) {&lt;br /&gt;
      battle.resetAttackType = true;&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addUniquePseudo(characterDataObject, savedCharactersPseudo) {&lt;br /&gt;
  var characterPseudo = String(characterDataObject.name);&lt;br /&gt;
  var originalPseudo = characterPseudo;&lt;br /&gt;
  var count = 0;&lt;br /&gt;
&lt;br /&gt;
  var regex = /(.*)(\d)$/;&lt;br /&gt;
  var match = characterPseudo.match(regex);&lt;br /&gt;
&lt;br /&gt;
  if (match) {&lt;br /&gt;
    originalPseudo = match[1];&lt;br /&gt;
    count = match[2];&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  while (isValueInArray(characterPseudo, savedCharactersPseudo)) {&lt;br /&gt;
    characterPseudo = originalPseudo + count;&lt;br /&gt;
    count++;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  characterDataObject.name = characterPseudo;&lt;br /&gt;
  return [characterDataObject, characterPseudo];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function convertToNumber(value) {&lt;br /&gt;
  var valueNumber = Number(value);&lt;br /&gt;
  return isNaN(valueNumber) ? value : valueNumber;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getLocalStorageValue(key, defaultValue) {&lt;br /&gt;
  var storedValue = localStorage.getItem(key);&lt;br /&gt;
&lt;br /&gt;
  if (storedValue) {&lt;br /&gt;
    return JSON.parse(storedValue);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return defaultValue;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSavedCharacters() {&lt;br /&gt;
  return getLocalStorageValue(&amp;quot;savedCharactersCalculator&amp;quot;, {});&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSavedMonsters() {&lt;br /&gt;
  var savedMonsters = getLocalStorageValue(&amp;quot;savedMonstersCalculator&amp;quot;, {});&lt;br /&gt;
&lt;br /&gt;
  if (Array.isArray(savedMonsters)) {&lt;br /&gt;
    return {};&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var filteredMonsters = {};&lt;br /&gt;
&lt;br /&gt;
  for (var vnum in savedMonsters) {&lt;br /&gt;
    if (&lt;br /&gt;
      String(Number(vnum)) === vnum &amp;amp;&amp;amp;&lt;br /&gt;
      savedMonsters[vnum].hasOwnProperty(&amp;quot;category&amp;quot;)&lt;br /&gt;
    ) {&lt;br /&gt;
      filteredMonsters[vnum] = savedMonsters[vnum];&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  updateSavedMonsters(filteredMonsters);&lt;br /&gt;
&lt;br /&gt;
  return filteredMonsters;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSavedFights() {&lt;br /&gt;
  return getLocalStorageValue(&amp;quot;savedFightsCalculator&amp;quot;, []);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveToLocalStorage(key, value) {&lt;br /&gt;
  localStorage.setItem(key, JSON.stringify(value));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateSavedCharacters(savedCharacters) {&lt;br /&gt;
  saveToLocalStorage(&amp;quot;savedCharactersCalculator&amp;quot;, savedCharacters);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateSavedMonsters(savedMonsters) {&lt;br /&gt;
  saveToLocalStorage(&amp;quot;savedMonstersCalculator&amp;quot;, savedMonsters);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateSavedFights(savedFights) {&lt;br /&gt;
  saveToLocalStorage(&amp;quot;savedFightsCalculator&amp;quot;, savedFights);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveCharacter(&lt;br /&gt;
  savedCharacters,&lt;br /&gt;
  characterCreation,&lt;br /&gt;
  battle,&lt;br /&gt;
  newCharacter,&lt;br /&gt;
  characterDataObject&lt;br /&gt;
) {&lt;br /&gt;
  if (!characterDataObject) {&lt;br /&gt;
    var characterData = new FormData(characterCreation);&lt;br /&gt;
    var characterDataObject = {};&lt;br /&gt;
&lt;br /&gt;
    characterData.forEach(function (value, key) {&lt;br /&gt;
      characterDataObject[key] = convertToNumber(value);&lt;br /&gt;
    });&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  savedCharacters[characterDataObject.name] = characterDataObject;&lt;br /&gt;
  updateSavedCharacters(savedCharacters);&lt;br /&gt;
&lt;br /&gt;
  if (newCharacter) {&lt;br /&gt;
    addBattleChoice(battle, characterDataObject.name);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (battle.resetAttackType) {&lt;br /&gt;
    filterAttackTypeSelection(characterDataObject, battle.attackTypeSelection);&lt;br /&gt;
    battle.resetAttackType = false;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveButtonGreen(saveButton) {&lt;br /&gt;
  saveButton.classList.remove(&amp;quot;unsaved-character&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveButtonOrange(saveButton) {&lt;br /&gt;
  saveButton.classList.add(&amp;quot;unsaved-character&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function characterCreationListener(characters, battle) {&lt;br /&gt;
  var { characterCreation, saveButton, weaponCategory } = characters;&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;submit&amp;quot;, handleSubmitForm);&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;invalid&amp;quot;, handleInvalidInput, true);&lt;br /&gt;
  document.addEventListener(&amp;quot;keydown&amp;quot;, handleSaveShortcut);&lt;br /&gt;
  weaponCategory.addEventListener(&amp;quot;mouseover&amp;quot;, handleTooltipOverflow);&lt;br /&gt;
&lt;br /&gt;
  function handleSubmitForm(event) {&lt;br /&gt;
    event.preventDefault();&lt;br /&gt;
&lt;br /&gt;
    if (characters.unsavedChanges) {&lt;br /&gt;
      saveCharacter(characters.savedCharacters, characterCreation, battle);&lt;br /&gt;
      saveButtonGreen(saveButton);&lt;br /&gt;
      characters.unsavedChanges = false;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function handleInvalidInput(event) {&lt;br /&gt;
    var target = event.target;&lt;br /&gt;
&lt;br /&gt;
    if (target.checkVisibility()) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var autoCorrectInput = target.closest(&amp;quot;.auto-correct-input&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      autoCorrectInput &amp;amp;&amp;amp;&lt;br /&gt;
      autoCorrectInput.classList.contains(&amp;quot;tabber-noactive&amp;quot;)&lt;br /&gt;
    ) {&lt;br /&gt;
      target.value = target.defaultValue;&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    openTargetTab(target);&lt;br /&gt;
    openTargetCollapsible(target);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function handleSaveShortcut(event) {&lt;br /&gt;
    if (event.ctrlKey &amp;amp;&amp;amp; event.key === &amp;quot;s&amp;quot;) {&lt;br /&gt;
      event.preventDefault();&lt;br /&gt;
      saveButton.click();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function handleTooltipOverflow(event) {&lt;br /&gt;
    label = event.target.closest(&amp;quot;label&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (label) {&lt;br /&gt;
      var tooltip = label.lastChild;&lt;br /&gt;
&lt;br /&gt;
      if (tooltip.classList.contains(&amp;quot;popContenu&amp;quot;)) {&lt;br /&gt;
        var tooltipRect = tooltip.getBoundingClientRect();&lt;br /&gt;
        var modalRect = weaponCategory.getBoundingClientRect();&lt;br /&gt;
&lt;br /&gt;
        if (tooltipRect.right &amp;gt; modalRect.right) {&lt;br /&gt;
          tooltip.style.left = &amp;quot;-100%&amp;quot;;&lt;br /&gt;
        } else if (tooltipRect.left &amp;lt; modalRect.left) {&lt;br /&gt;
          tooltip.style.left = &amp;quot;200%&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function downloadData(content, type, filename) {&lt;br /&gt;
  var link = document.createElement(&amp;quot;a&amp;quot;);&lt;br /&gt;
  var blob = new Blob([content], { type: type });&lt;br /&gt;
  var blobURL = URL.createObjectURL(blob);&lt;br /&gt;
&lt;br /&gt;
  link.href = blobURL;&lt;br /&gt;
  link.download = filename;&lt;br /&gt;
  document.body.appendChild(link);&lt;br /&gt;
&lt;br /&gt;
  link.click();&lt;br /&gt;
  document.body.removeChild(link);&lt;br /&gt;
  URL.revokeObjectURL(blobURL);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function uploadCharacter(&lt;br /&gt;
  selectedFiles,&lt;br /&gt;
  characters,&lt;br /&gt;
  characterTemplate,&lt;br /&gt;
  charactersContainer,&lt;br /&gt;
  battle&lt;br /&gt;
) {&lt;br /&gt;
  var selectFilesLength = selectedFiles.length;&lt;br /&gt;
&lt;br /&gt;
  for (var fileIndex = 0; fileIndex &amp;lt; selectFilesLength; fileIndex++) {&lt;br /&gt;
    var selectedFile = selectedFiles[fileIndex];&lt;br /&gt;
&lt;br /&gt;
    if (selectedFile.type === &amp;quot;text/plain&amp;quot;) {&lt;br /&gt;
      var reader = new FileReader();&lt;br /&gt;
      reader.onload = function (e) {&lt;br /&gt;
        var fileContent = e.target.result;&lt;br /&gt;
        try {&lt;br /&gt;
          var characterDataObject = JSON.parse(fileContent);&lt;br /&gt;
&lt;br /&gt;
          if (characterDataObject.hasOwnProperty(&amp;quot;name&amp;quot;)) {&lt;br /&gt;
            var characterPseudo = String(characterDataObject.name);&lt;br /&gt;
&lt;br /&gt;
            hideElement(characters.characterCreation);&lt;br /&gt;
            characterPseudo = validPseudo(characterPseudo);&lt;br /&gt;
&lt;br /&gt;
            [characterDataObject, characterPseudo] = addUniquePseudo(&lt;br /&gt;
              characterDataObject,&lt;br /&gt;
              Object.keys(characters.savedCharacters)&lt;br /&gt;
            );&lt;br /&gt;
            var selectedCharacter = handleNewCharacter(&lt;br /&gt;
              characters,&lt;br /&gt;
              characterTemplate,&lt;br /&gt;
              charactersContainer,&lt;br /&gt;
              battle,&lt;br /&gt;
              characterPseudo&lt;br /&gt;
            )[0];&lt;br /&gt;
&lt;br /&gt;
            if (selectFilesLength === 1) {&lt;br /&gt;
              updateForm(&lt;br /&gt;
                characterDataObject,&lt;br /&gt;
                characters.characterCreation,&lt;br /&gt;
                characters,&lt;br /&gt;
                selectedCharacter,&lt;br /&gt;
                battle&lt;br /&gt;
              );&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            saveCharacter(&lt;br /&gt;
              characters.savedCharacters,&lt;br /&gt;
              characters.characterCreation,&lt;br /&gt;
              battle,&lt;br /&gt;
              true,&lt;br /&gt;
              characterDataObject&lt;br /&gt;
            );&lt;br /&gt;
          }&lt;br /&gt;
        } catch (error) {&lt;br /&gt;
          console.log(error);&lt;br /&gt;
          if (error.name === &amp;quot;TypeError&amp;quot;) {&lt;br /&gt;
            // delete the character&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
      };&lt;br /&gt;
      reader.readAsText(selectedFile);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleUploadCharacter(&lt;br /&gt;
  characters,&lt;br /&gt;
  characterTemplate,&lt;br /&gt;
  charactersContainer,&lt;br /&gt;
  battle&lt;br /&gt;
) {&lt;br /&gt;
  var characterInput = characters.characterInput;&lt;br /&gt;
  var dropZone = characters.dropZone;&lt;br /&gt;
&lt;br /&gt;
  characterInput.accept = &amp;quot;.txt&amp;quot;;&lt;br /&gt;
  characterInput.multiple = true;&lt;br /&gt;
  dropZone.setAttribute(&amp;quot;tabindex&amp;quot;, &amp;quot;0&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  dropZone.addEventListener(&amp;quot;click&amp;quot;, function () {&lt;br /&gt;
    characterInput.click();&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  dropZone.addEventListener(&amp;quot;dragover&amp;quot;, function (event) {&lt;br /&gt;
    event.preventDefault();&lt;br /&gt;
    dropZone.classList.add(&amp;quot;drop-zone--dragover&amp;quot;);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  [&amp;quot;dragleave&amp;quot;, &amp;quot;dragend&amp;quot;].forEach(function (type) {&lt;br /&gt;
    dropZone.addEventListener(type, function () {&lt;br /&gt;
      dropZone.classList.remove(&amp;quot;drop-zone--dragover&amp;quot;);&lt;br /&gt;
    });&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  dropZone.addEventListener(&amp;quot;drop&amp;quot;, function (event) {&lt;br /&gt;
    event.preventDefault();&lt;br /&gt;
    uploadCharacter(&lt;br /&gt;
      event.dataTransfer.files,&lt;br /&gt;
      characters,&lt;br /&gt;
      characterTemplate,&lt;br /&gt;
      charactersContainer,&lt;br /&gt;
      battle&lt;br /&gt;
    );&lt;br /&gt;
    dropZone.classList.remove(&amp;quot;drop-zone--dragover&amp;quot;);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  characterInput.addEventListener(&amp;quot;change&amp;quot;, function (event) {&lt;br /&gt;
    uploadCharacter(&lt;br /&gt;
      event.target.files,&lt;br /&gt;
      characters,&lt;br /&gt;
      characterTemplate,&lt;br /&gt;
      charactersContainer,&lt;br /&gt;
      battle&lt;br /&gt;
    );&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function deleteCharacter(characters, pseudo, element, battle) {&lt;br /&gt;
  battle.battleForm.reset();&lt;br /&gt;
  delete characters.savedCharacters[pseudo];&lt;br /&gt;
  element.remove();&lt;br /&gt;
&lt;br /&gt;
  updateSavedCharacters(characters.savedCharacters);&lt;br /&gt;
  removeBattleChoice(battle, pseudo);&lt;br /&gt;
&lt;br /&gt;
  if (&lt;br /&gt;
    !Object.keys(characters.savedCharacters).length ||&lt;br /&gt;
    characters.characterCreation.name.value === pseudo&lt;br /&gt;
  ) {&lt;br /&gt;
    saveButtonGreen(characters.saveButton);&lt;br /&gt;
    characters.unsavedChanges = false;&lt;br /&gt;
    hideElement(characters.characterCreation);&lt;br /&gt;
    showElement(characters.characterCreation.previousElementSibling);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function deleteMonster(characters, battle, monsterVnum, monsterElement) {&lt;br /&gt;
  var monsterElement =&lt;br /&gt;
    monsterElement ||&lt;br /&gt;
    characters.monstersContainer.querySelector(&lt;br /&gt;
      &amp;quot;[data-monster-id='&amp;quot; + monsterVnum + &amp;quot;']&amp;quot;&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
  if (monsterElement) {&lt;br /&gt;
    monsterElement.remove();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  battle.battleForm.reset();&lt;br /&gt;
&lt;br /&gt;
  delete characters.savedMonsters[monsterVnum];&lt;br /&gt;
&lt;br /&gt;
  updateSavedMonsters(characters.savedMonsters);&lt;br /&gt;
  removeBattleChoice(battle, monsterVnum);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleStyle(characters, selectedElement) {&lt;br /&gt;
  var currentCharacter = characters.currentCharacter;&lt;br /&gt;
&lt;br /&gt;
  if (currentCharacter) {&lt;br /&gt;
    currentCharacter.classList.remove(&amp;quot;selected-character&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  selectedElement.classList.add(&amp;quot;selected-character&amp;quot;);&lt;br /&gt;
  characters.currentCharacter = selectedElement;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateForm(&lt;br /&gt;
  formData,&lt;br /&gt;
  characterCreation,&lt;br /&gt;
  characters,&lt;br /&gt;
  selectedElement,&lt;br /&gt;
  battle&lt;br /&gt;
) {&lt;br /&gt;
  saveButtonGreen(characters.saveButton);&lt;br /&gt;
  hideElement(characterCreation.previousElementSibling);&lt;br /&gt;
  showElement(characterCreation);&lt;br /&gt;
  handleStyle(characters, selectedElement);&lt;br /&gt;
&lt;br /&gt;
  characterCreation.reset();&lt;br /&gt;
&lt;br /&gt;
  for (var [name, value] of Object.entries(formData)) {&lt;br /&gt;
    var formElement = characterCreation[name];&lt;br /&gt;
&lt;br /&gt;
    if (!formElement) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (formElement.type === &amp;quot;checkbox&amp;quot;) {&lt;br /&gt;
      if (isChecked(value)) {&lt;br /&gt;
        formElement.checked = true;&lt;br /&gt;
      }&lt;br /&gt;
    } else {&lt;br /&gt;
      formElement.value = value;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  var selectedRace = characterCreation.race.value;&lt;br /&gt;
  var classChoice = characterCreation.class;&lt;br /&gt;
  var weaponElement = characterCreation.weapon;&lt;br /&gt;
&lt;br /&gt;
  filterClass(selectedRace, classChoice, true);&lt;br /&gt;
  filterWeapon(&lt;br /&gt;
    selectedRace,&lt;br /&gt;
    weaponElement,&lt;br /&gt;
    characters.weaponCategory,&lt;br /&gt;
    battle.constants.allowedWeaponsPerRace,&lt;br /&gt;
    true&lt;br /&gt;
  );&lt;br /&gt;
  handlePolymorphDisplay(&lt;br /&gt;
    characters.polymorphDisplay,&lt;br /&gt;
    characterCreation.polymorphMonster.value,&lt;br /&gt;
    characterCreation.polymorphMonsterImage.value&lt;br /&gt;
  );&lt;br /&gt;
  handleWeaponDisplay(&lt;br /&gt;
    characters.weaponCategory,&lt;br /&gt;
    characters.weaponDisplay,&lt;br /&gt;
    weaponElement.value&lt;br /&gt;
  );&lt;br /&gt;
  filterUpgrade(&lt;br /&gt;
    characterCreation.weaponUpgrade,&lt;br /&gt;
    weaponElement.value,&lt;br /&gt;
    characters.randomAttackValue,&lt;br /&gt;
    characters.randomMagicAttackValue&lt;br /&gt;
  );&lt;br /&gt;
  filterCheckbox(characterCreation.isPolymorph, characters.polymorphCreation);&lt;br /&gt;
  filterCheckbox(&lt;br /&gt;
    characterCreation.lowRank,&lt;br /&gt;
    characterCreation.playerRank.parentElement&lt;br /&gt;
  );&lt;br /&gt;
  filterCheckbox(characterCreation.onYohara, characters.yoharaCreation);&lt;br /&gt;
  filterCheckbox(characterCreation.isBlessed, characters.blessingCreation);&lt;br /&gt;
  filterCheckbox(characterCreation.isMarried, characters.marriageCreation);&lt;br /&gt;
  filterCheckbox(&lt;br /&gt;
    characterCreation.useBonusVariation,&lt;br /&gt;
    characters.bonusVariation.container&lt;br /&gt;
  );&lt;br /&gt;
  filterSkills(classChoice.value, characters.skillElementsToFilter);&lt;br /&gt;
  handleBonusVariationUpdate(characterCreation, characters.bonusVariation);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleClickOnCharacter(&lt;br /&gt;
  spanInput,&lt;br /&gt;
  target,&lt;br /&gt;
  characters,&lt;br /&gt;
  characterElement,&lt;br /&gt;
  battle,&lt;br /&gt;
  edition&lt;br /&gt;
) {&lt;br /&gt;
  var displayedPseudo = characters.characterCreation.name.value;&lt;br /&gt;
  var pseudo = spanInput.dataset.name;&lt;br /&gt;
&lt;br /&gt;
  if (edition) {&lt;br /&gt;
    if (!characters.unsavedChanges) {&lt;br /&gt;
      updateForm(&lt;br /&gt;
        characters.savedCharacters[pseudo],&lt;br /&gt;
        characters.characterCreation,&lt;br /&gt;
        characters,&lt;br /&gt;
        characterElement,&lt;br /&gt;
        battle&lt;br /&gt;
      );&lt;br /&gt;
    } else if (displayedPseudo === pseudo) {&lt;br /&gt;
      // pass&lt;br /&gt;
    } else {&lt;br /&gt;
      var result = confirm(&lt;br /&gt;
        &amp;quot;Voulez-vous continuer ? Les dernières modifications ne seront pas sauvegardées.&amp;quot;&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      if (result) {&lt;br /&gt;
        updateForm(&lt;br /&gt;
          characters.savedCharacters[pseudo],&lt;br /&gt;
          characters.characterCreation,&lt;br /&gt;
          characters,&lt;br /&gt;
          characterElement,&lt;br /&gt;
          battle&lt;br /&gt;
        );&lt;br /&gt;
        characters.unsavedChanges = false;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    if (target.tagName === &amp;quot;path&amp;quot;) {&lt;br /&gt;
      target = target.parentElement;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    switch (target.dataset.icon) {&lt;br /&gt;
      case &amp;quot;duplicate&amp;quot;:&lt;br /&gt;
        if (!characters.unsavedChanges) {&lt;br /&gt;
          addNewCharacter(&lt;br /&gt;
            characters,&lt;br /&gt;
            characters.newCharacterTemplate,&lt;br /&gt;
            characters.charactersContainer,&lt;br /&gt;
            battle,&lt;br /&gt;
            pseudo&lt;br /&gt;
          );&lt;br /&gt;
        } else {&lt;br /&gt;
          var result = confirm(&lt;br /&gt;
            &amp;quot;Voulez-vous continuer ? Les dernières modifications ne seront pas sauvegardées.&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
&lt;br /&gt;
          if (result) {&lt;br /&gt;
            addNewCharacter(&lt;br /&gt;
              characters,&lt;br /&gt;
              characters.newCharacterTemplate,&lt;br /&gt;
              characters.charactersContainer,&lt;br /&gt;
              battle,&lt;br /&gt;
              pseudo&lt;br /&gt;
            );&lt;br /&gt;
            saveButtonGreen(characters.saveButton);&lt;br /&gt;
            characters.unsavedChanges = false;&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
        break;&lt;br /&gt;
&lt;br /&gt;
      case &amp;quot;download&amp;quot;:&lt;br /&gt;
        var character = characters.savedCharacters[pseudo];&lt;br /&gt;
        downloadData(&lt;br /&gt;
          JSON.stringify(character),&lt;br /&gt;
          &amp;quot;text/plain&amp;quot;,&lt;br /&gt;
          character.name + &amp;quot;.txt&amp;quot;&lt;br /&gt;
        );&lt;br /&gt;
        break;&lt;br /&gt;
&lt;br /&gt;
      case &amp;quot;delete&amp;quot;:&lt;br /&gt;
        var result = confirm(&lt;br /&gt;
          &amp;quot;Voulez-vous vraiment supprimer définitivement le personnage &amp;quot; +&lt;br /&gt;
            pseudo +&lt;br /&gt;
            &amp;quot; ?&amp;quot;&lt;br /&gt;
        );&lt;br /&gt;
        if (result) {&lt;br /&gt;
          deleteCharacter(characters, pseudo, characterElement, battle);&lt;br /&gt;
        }&lt;br /&gt;
        break;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleNewCharacter(&lt;br /&gt;
  characters,&lt;br /&gt;
  characterTemplate,&lt;br /&gt;
  charactersContainer,&lt;br /&gt;
  battle,&lt;br /&gt;
  pseudo&lt;br /&gt;
) {&lt;br /&gt;
  var newCharacterTemplate = characterTemplate.cloneNode(true);&lt;br /&gt;
  var spanInput = newCharacterTemplate.querySelector(&amp;quot;span.input&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  newCharacterTemplate.setAttribute(&amp;quot;tabindex&amp;quot;, &amp;quot;0&amp;quot;);&lt;br /&gt;
  charactersContainer.appendChild(newCharacterTemplate);&lt;br /&gt;
&lt;br /&gt;
  if (pseudo) {&lt;br /&gt;
    spanInput.textContent = pseudo;&lt;br /&gt;
    spanInput.setAttribute(&amp;quot;data-name&amp;quot;, pseudo);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  newCharacterTemplate.addEventListener(&amp;quot;click&amp;quot;, function (event) {&lt;br /&gt;
    var target = event.target;&lt;br /&gt;
&lt;br /&gt;
    if (target.tagName === &amp;quot;path&amp;quot; || target.tagName === &amp;quot;svg&amp;quot;) {&lt;br /&gt;
      handleClickOnCharacter(&lt;br /&gt;
        spanInput,&lt;br /&gt;
        target,&lt;br /&gt;
        characters,&lt;br /&gt;
        newCharacterTemplate,&lt;br /&gt;
        battle&lt;br /&gt;
      );&lt;br /&gt;
    } else {&lt;br /&gt;
      handleClickOnCharacter(&lt;br /&gt;
        spanInput,&lt;br /&gt;
        null,&lt;br /&gt;
        characters,&lt;br /&gt;
        newCharacterTemplate,&lt;br /&gt;
        battle,&lt;br /&gt;
        true&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  newCharacterTemplate.addEventListener(&amp;quot;keydown&amp;quot;, function (event) {&lt;br /&gt;
    if (event.keyCode === 13) {&lt;br /&gt;
      event.target.click();&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  return [newCharacterTemplate, spanInput];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function validPseudo(pseudo) {&lt;br /&gt;
  var newPseudo = pseudoFormat(pseudo);&lt;br /&gt;
&lt;br /&gt;
  if (!newPseudo) {&lt;br /&gt;
    return &amp;quot;Pseudo&amp;quot;;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return newPseudo;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addNewCharacter(&lt;br /&gt;
  characters,&lt;br /&gt;
  characterTemplate,&lt;br /&gt;
  charactersContainer,&lt;br /&gt;
  battle,&lt;br /&gt;
  pseudoToDuplicate&lt;br /&gt;
) {&lt;br /&gt;
  function editAndSetCharacterPseudoInput(selectedCharacter, spanInput) {&lt;br /&gt;
    var maxPseudoLength = 20;&lt;br /&gt;
&lt;br /&gt;
    var selection = window.getSelection();&lt;br /&gt;
    var range = document.createRange();&lt;br /&gt;
&lt;br /&gt;
    if (pseudoToDuplicate) {&lt;br /&gt;
      spanInput.textContent = pseudoToDuplicate;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    spanInput.contentEditable = true;&lt;br /&gt;
    spanInput.focus();&lt;br /&gt;
    range.selectNodeContents(spanInput);&lt;br /&gt;
    selection.removeAllRanges();&lt;br /&gt;
    selection.addRange(range);&lt;br /&gt;
&lt;br /&gt;
    function pseudoValidation() {&lt;br /&gt;
      var characterPseudo = validPseudo(spanInput.textContent);&lt;br /&gt;
      var characterDataObject = { name: characterPseudo };&lt;br /&gt;
&lt;br /&gt;
      if (pseudoToDuplicate) {&lt;br /&gt;
        characterDataObject = copyObject(&lt;br /&gt;
          characters.savedCharacters[pseudoToDuplicate]&lt;br /&gt;
        );&lt;br /&gt;
        characterDataObject.name = characterPseudo;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      [characterDataObject, characterPseudo] = addUniquePseudo(&lt;br /&gt;
        characterDataObject,&lt;br /&gt;
        Object.keys(characters.savedCharacters)&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      selection.removeAllRanges();&lt;br /&gt;
      spanInput.contentEditable = false;&lt;br /&gt;
      spanInput.textContent = characterPseudo;&lt;br /&gt;
      spanInput.setAttribute(&amp;quot;data-name&amp;quot;, characterPseudo);&lt;br /&gt;
&lt;br /&gt;
      updateForm(&lt;br /&gt;
        characterDataObject,&lt;br /&gt;
        characters.characterCreation,&lt;br /&gt;
        characters,&lt;br /&gt;
        selectedCharacter,&lt;br /&gt;
        battle&lt;br /&gt;
      );&lt;br /&gt;
      saveCharacter(&lt;br /&gt;
        characters.savedCharacters,&lt;br /&gt;
        characters.characterCreation,&lt;br /&gt;
        battle,&lt;br /&gt;
        true&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handleMaxLength(event) {&lt;br /&gt;
      if (spanInput.textContent.length &amp;gt; maxPseudoLength) {&lt;br /&gt;
        spanInput.textContent = spanInput.textContent.slice(0, maxPseudoLength);&lt;br /&gt;
        range.setStart(spanInput.childNodes[0], maxPseudoLength);&lt;br /&gt;
        selection.removeAllRanges();&lt;br /&gt;
        selection.addRange(range);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handleBlur() {&lt;br /&gt;
      spanInput.removeEventListener(&amp;quot;blur&amp;quot;, handleBlur);&lt;br /&gt;
      spanInput.removeEventListener(&amp;quot;input&amp;quot;, handleMaxLength);&lt;br /&gt;
      pseudoValidation();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handleKeyDown(event) {&lt;br /&gt;
      if (event.key === &amp;quot;Enter&amp;quot;) {&lt;br /&gt;
        event.preventDefault();&lt;br /&gt;
&lt;br /&gt;
        spanInput.removeEventListener(&amp;quot;keydown&amp;quot;, handleKeyDown);&lt;br /&gt;
        spanInput.removeEventListener(&amp;quot;blur&amp;quot;, handleBlur);&lt;br /&gt;
        spanInput.removeEventListener(&amp;quot;input&amp;quot;, handleMaxLength);&lt;br /&gt;
&lt;br /&gt;
        pseudoValidation();&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    spanInput.addEventListener(&amp;quot;input&amp;quot;, handleMaxLength);&lt;br /&gt;
    spanInput.addEventListener(&amp;quot;keydown&amp;quot;, handleKeyDown);&lt;br /&gt;
    spanInput.addEventListener(&amp;quot;blur&amp;quot;, handleBlur);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  hideElement(characters.characterCreation);&lt;br /&gt;
  var [selectedCharacter, spanInput] = handleNewCharacter(&lt;br /&gt;
    characters,&lt;br /&gt;
    characterTemplate,&lt;br /&gt;
    charactersContainer,&lt;br /&gt;
    battle&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  editAndSetCharacterPseudoInput(selectedCharacter, spanInput);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleFocus() {&lt;br /&gt;
  var tooltipLinks = document.querySelectorAll(&amp;quot;div.tooltip a&amp;quot;);&lt;br /&gt;
  tooltipLinks.forEach(function (link) {&lt;br /&gt;
    link.setAttribute(&amp;quot;tabindex&amp;quot;, -1);&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function resetBonusVariation(bonusVariation) {&lt;br /&gt;
  function resetInput(input) {&lt;br /&gt;
    input.removeAttribute(&amp;quot;min&amp;quot;);&lt;br /&gt;
    input.removeAttribute(&amp;quot;max&amp;quot;);&lt;br /&gt;
    input.defaultValue = 0;&lt;br /&gt;
    input.value = input.defaultValue;&lt;br /&gt;
  }&lt;br /&gt;
  var { minValue, maxValue, checkbox, container, disabledText, selectedText } =&lt;br /&gt;
    bonusVariation;&lt;br /&gt;
&lt;br /&gt;
  resetInput(minValue);&lt;br /&gt;
  resetInput(maxValue);&lt;br /&gt;
  showElement(disabledText);&lt;br /&gt;
  hideElement(selectedText);&lt;br /&gt;
  hideElement(container);&lt;br /&gt;
  checkbox.checked = false;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleBonusVariationUpdate(&lt;br /&gt;
  characterCreation,&lt;br /&gt;
  bonusVariation,&lt;br /&gt;
  resetSkill&lt;br /&gt;
) {&lt;br /&gt;
  var selectedBonus = characterCreation.bonusVariation.value;&lt;br /&gt;
  var displayName = characterCreation.bonusVariationName.value;&lt;br /&gt;
&lt;br /&gt;
  if (&lt;br /&gt;
    resetSkill &amp;amp;&amp;amp;&lt;br /&gt;
    (selectedBonus.startsWith(&amp;quot;attackSkill&amp;quot;) ||&lt;br /&gt;
      selectedBonus.startsWith(&amp;quot;horseSkill&amp;quot;) ||&lt;br /&gt;
      selectedBonus.startsWith(&amp;quot;skillBonus&amp;quot;))&lt;br /&gt;
  ) {&lt;br /&gt;
    resetBonusVariation(bonusVariation);&lt;br /&gt;
    return;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (&lt;br /&gt;
    characterCreation.hasOwnProperty(selectedBonus) &amp;amp;&amp;amp;&lt;br /&gt;
    selectedBonus != 0 &amp;amp;&amp;amp;&lt;br /&gt;
    displayName != 0&lt;br /&gt;
  ) {&lt;br /&gt;
    handleBonusVariation(&lt;br /&gt;
      characterCreation[selectedBonus],&lt;br /&gt;
      bonusVariation,&lt;br /&gt;
      displayName&lt;br /&gt;
    );&lt;br /&gt;
  } else {&lt;br /&gt;
    resetBonusVariation(bonusVariation);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getTargetContent(targetParent, targetName, isSkill) {&lt;br /&gt;
  var targetContent = &amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  if (targetParent.children.length &amp;lt;= 1) {&lt;br /&gt;
    targetContent = targetParent.textContent;&lt;br /&gt;
  } else if (targetName === &amp;quot;weaponUpgrade&amp;quot;) {&lt;br /&gt;
    targetContent = targetParent.children[1].textContent;&lt;br /&gt;
  } else if (targetName === &amp;quot;level&amp;quot;) {&lt;br /&gt;
    targetContent = targetParent.textContent.replace(&amp;quot;Lv&amp;quot;, &amp;quot;&amp;quot;).trim();&lt;br /&gt;
  } else if (isSkill) {&lt;br /&gt;
    var container = targetParent.children[1];&lt;br /&gt;
&lt;br /&gt;
    for (var index = 0; index &amp;lt; container.children.length; index++) {&lt;br /&gt;
      var element = container.children[index];&lt;br /&gt;
&lt;br /&gt;
      if (element.checkVisibility()) {&lt;br /&gt;
        targetContent += element.textContent;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    for (var index = 1; index &amp;lt; targetParent.children.length; index++) {&lt;br /&gt;
      var element = targetParent.children[index];&lt;br /&gt;
&lt;br /&gt;
      if (element.checkVisibility()) {&lt;br /&gt;
        targetContent += element.textContent;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return targetContent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleBonusVariation(target, bonusVariation, displayName) {&lt;br /&gt;
  var {&lt;br /&gt;
    minValue,&lt;br /&gt;
    maxValue,&lt;br /&gt;
    checkbox,&lt;br /&gt;
    container,&lt;br /&gt;
    disabledText,&lt;br /&gt;
    selectedText,&lt;br /&gt;
    displaySpan,&lt;br /&gt;
  } = bonusVariation;&lt;br /&gt;
&lt;br /&gt;
  var {&lt;br /&gt;
    min: targetMin,&lt;br /&gt;
    max: targetMax,&lt;br /&gt;
    name: targetName,&lt;br /&gt;
    value: targetValue,&lt;br /&gt;
    parentElement: targetParent,&lt;br /&gt;
    tagName,&lt;br /&gt;
  } = target;&lt;br /&gt;
&lt;br /&gt;
  targetMin = Number(targetMin);&lt;br /&gt;
  targetMax = Number(targetMax);&lt;br /&gt;
  targetValue = Number(targetValue);&lt;br /&gt;
&lt;br /&gt;
  var isSkill = tagName === &amp;quot;SELECT&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  if (isSkill) {&lt;br /&gt;
    var options = target.options;&lt;br /&gt;
&lt;br /&gt;
    targetMin = options[0].value;&lt;br /&gt;
    targetMax = options[options.length - 1].value;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  minValue.min = targetMin;&lt;br /&gt;
  minValue.max = targetMax;&lt;br /&gt;
  minValue.defaultValue = targetMin;&lt;br /&gt;
&lt;br /&gt;
  maxValue.min = targetMin;&lt;br /&gt;
  maxValue.max = targetMax;&lt;br /&gt;
  maxValue.defaultValue = targetMin;&lt;br /&gt;
&lt;br /&gt;
  hideElement(disabledText);&lt;br /&gt;
  showElement(selectedText);&lt;br /&gt;
&lt;br /&gt;
  if (displayName) {&lt;br /&gt;
    minValue.value = Math.min(Math.max(minValue.value, targetMin), targetMax);&lt;br /&gt;
    maxValue.value = Math.max(Math.min(maxValue.value, targetMax), targetMin);&lt;br /&gt;
&lt;br /&gt;
    displaySpan.textContent = displayName;&lt;br /&gt;
  } else {&lt;br /&gt;
    var { input, inputName, tabButton } = bonusVariation;&lt;br /&gt;
    var targetContent = getTargetContent(targetParent, targetName, isSkill);&lt;br /&gt;
&lt;br /&gt;
    input.value = targetName;&lt;br /&gt;
    inputName.value = targetContent;&lt;br /&gt;
    displaySpan.textContent = targetContent;&lt;br /&gt;
&lt;br /&gt;
    minValue.value = Math.max(targetValue - 10, targetMin);&lt;br /&gt;
    maxValue.value = Math.min(targetValue + 10, targetMax);&lt;br /&gt;
&lt;br /&gt;
    showElement(container);&lt;br /&gt;
    checkbox.checked = true;&lt;br /&gt;
&lt;br /&gt;
    tabButton.click();&lt;br /&gt;
    tabButton.scrollIntoView(true);&lt;br /&gt;
&lt;br /&gt;
    input.dispatchEvent(new Event(&amp;quot;change&amp;quot;, { bubbles: true }));&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function characterManagement(characters, battle) {&lt;br /&gt;
  var {&lt;br /&gt;
    newCharacterTemplate: characterTemplate,&lt;br /&gt;
    charactersContainer,&lt;br /&gt;
    addNewCharacterButton,&lt;br /&gt;
    saveButton,&lt;br /&gt;
    characterCreation,&lt;br /&gt;
    bonusVariation,&lt;br /&gt;
  } = characters;&lt;br /&gt;
&lt;br /&gt;
  Object.keys(characters.savedCharacters).forEach(function (pseudo) {&lt;br /&gt;
    handleNewCharacter(&lt;br /&gt;
      characters,&lt;br /&gt;
      characterTemplate,&lt;br /&gt;
      charactersContainer,&lt;br /&gt;
      battle,&lt;br /&gt;
      pseudo&lt;br /&gt;
    );&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  addNewCharacterButton.addEventListener(&amp;quot;click&amp;quot;, function (event) {&lt;br /&gt;
    if (!characters.unsavedChanges) {&lt;br /&gt;
      addNewCharacter(&lt;br /&gt;
        characters,&lt;br /&gt;
        characterTemplate,&lt;br /&gt;
        charactersContainer,&lt;br /&gt;
        battle&lt;br /&gt;
      );&lt;br /&gt;
    } else {&lt;br /&gt;
      var result = confirm(&lt;br /&gt;
        &amp;quot;Voulez-vous continuer ? Les dernières modifications ne seront pas sauvegardées.&amp;quot;&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      if (result) {&lt;br /&gt;
        addNewCharacter(&lt;br /&gt;
          characters,&lt;br /&gt;
          characterTemplate,&lt;br /&gt;
          charactersContainer,&lt;br /&gt;
          battle&lt;br /&gt;
        );&lt;br /&gt;
        saveButtonGreen(saveButton);&lt;br /&gt;
        characters.unsavedChanges = false;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  handleUploadCharacter(&lt;br /&gt;
    characters,&lt;br /&gt;
    characterTemplate,&lt;br /&gt;
    charactersContainer,&lt;br /&gt;
    battle&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;change&amp;quot;, function () {&lt;br /&gt;
    saveButtonOrange(saveButton);&lt;br /&gt;
    characters.unsavedChanges = true;&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  function handleLongPress(target, characterCreation) {&lt;br /&gt;
    if (target.tagName !== &amp;quot;INPUT&amp;quot; &amp;amp;&amp;amp; target.tagName !== &amp;quot;SELECT&amp;quot;) {&lt;br /&gt;
      target = target.querySelector(&amp;quot;input&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      !target ||&lt;br /&gt;
      (target.type !== &amp;quot;number&amp;quot; &amp;amp;&amp;amp;&lt;br /&gt;
        !target.classList.contains(&amp;quot;skill-select&amp;quot;) &amp;amp;&amp;amp;&lt;br /&gt;
        target.name !== &amp;quot;weaponUpgrade&amp;quot;) ||&lt;br /&gt;
      target.classList.contains(&amp;quot;disabled-variation&amp;quot;)&lt;br /&gt;
    ) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    handleBonusVariation(target, bonusVariation, null);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;click&amp;quot;, function (event) {&lt;br /&gt;
    if (event.shiftKey || event.ctrlKey) {&lt;br /&gt;
      handleLongPress(event.target, characterCreation);&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  var longPressTimer;&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;touchstart&amp;quot;, function (event) {&lt;br /&gt;
    longPressTimer = setTimeout(function () {&lt;br /&gt;
      handleLongPress(event.target, characterCreation);&lt;br /&gt;
    }, 800);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;touchend&amp;quot;, function () {&lt;br /&gt;
    clearTimeout(longPressTimer);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;touchmove&amp;quot;, function () {&lt;br /&gt;
    clearTimeout(longPressTimer);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  filterForm(characters, battle);&lt;br /&gt;
  characterCreationListener(characters, battle);&lt;br /&gt;
  handleFocus();&lt;br /&gt;
&lt;br /&gt;
  window.addEventListener(&amp;quot;beforeunload&amp;quot;, function (event) {&lt;br /&gt;
    if (characters.unsavedChanges) {&lt;br /&gt;
      event.preventDefault();&lt;br /&gt;
      return &amp;quot;&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addMonsterElement(characters, battle, monsterVnum, iframeInfo) {&lt;br /&gt;
  var { monsterTemplate, monstersContainer } = characters;&lt;br /&gt;
  var monsterElement = monsterTemplate.cloneNode(true);&lt;br /&gt;
&lt;br /&gt;
  var spanInput = monsterElement.querySelector(&amp;quot;span.input&amp;quot;);&lt;br /&gt;
  var deleteSvg = monsterElement.querySelector(&amp;quot;svg&amp;quot;);&lt;br /&gt;
  var monsterName = getMonsterName(monsterVnum);&lt;br /&gt;
&lt;br /&gt;
  var link = document.createElement(&amp;quot;a&amp;quot;);&lt;br /&gt;
  link.href = mw.util.getUrl(monsterName);&lt;br /&gt;
  link.title = monsterName;&lt;br /&gt;
  link.textContent = monsterName;&lt;br /&gt;
&lt;br /&gt;
  spanInput.appendChild(link);&lt;br /&gt;
&lt;br /&gt;
  monsterElement.setAttribute(&amp;quot;tabindex&amp;quot;, &amp;quot;0&amp;quot;);&lt;br /&gt;
  monsterElement.setAttribute(&amp;quot;data-monster-id&amp;quot;, monsterVnum);&lt;br /&gt;
&lt;br /&gt;
  monstersContainer.appendChild(monsterElement);&lt;br /&gt;
&lt;br /&gt;
  deleteSvg.addEventListener(&amp;quot;click&amp;quot;, function () {&lt;br /&gt;
    var monster = characters.savedMonsters[monsterVnum];&lt;br /&gt;
    iframeInfo[monster.category].shouldBeUpdated = true;&lt;br /&gt;
&lt;br /&gt;
    deleteMonster(characters, battle, monsterVnum, monsterElement);&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addNewMonster(&lt;br /&gt;
  characters,&lt;br /&gt;
  battle,&lt;br /&gt;
  monsterVnum,&lt;br /&gt;
  monsterImage,&lt;br /&gt;
  iframeInfo,&lt;br /&gt;
  category&lt;br /&gt;
) {&lt;br /&gt;
  if (isValueInArray(monsterVnum, Object.keys(characters.savedMonsters)))&lt;br /&gt;
    return;&lt;br /&gt;
&lt;br /&gt;
  characters.savedMonsters[monsterVnum] = {&lt;br /&gt;
    image: monsterImage,&lt;br /&gt;
    category: category,&lt;br /&gt;
  };&lt;br /&gt;
  addMonsterElement(characters, battle, monsterVnum, iframeInfo);&lt;br /&gt;
  updateSavedMonsters(characters.savedMonsters);&lt;br /&gt;
  addBattleChoice(battle, monsterVnum, true);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addButtonsToCards(characters, iframeDoc, iframeInfo, category) {&lt;br /&gt;
  var buttonTemplates = characters.monsterButtonTemplates.children[0];&lt;br /&gt;
  var cardToEdit = iframeDoc.getElementById(&amp;quot;cards-container&amp;quot;).children;&lt;br /&gt;
  var { nameToVnum } = iframeInfo;&lt;br /&gt;
  var vnumToButtons = iframeInfo[category].vnumToButtons;&lt;br /&gt;
&lt;br /&gt;
  for (var cardIndex = 0; cardIndex &amp;lt; cardToEdit.length; cardIndex++) {&lt;br /&gt;
    var card = cardToEdit[cardIndex];&lt;br /&gt;
    var cardName = card.querySelector(&amp;quot;[data-name]&amp;quot;).firstChild.title;&lt;br /&gt;
    var buttonTemplatesClone = buttonTemplates.cloneNode(true);&lt;br /&gt;
&lt;br /&gt;
    cardName = cardName.replace(/\s/g, &amp;quot; &amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (!nameToVnum.hasOwnProperty(cardName)) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var monsterVnum = nameToVnum[cardName];&lt;br /&gt;
&lt;br /&gt;
    buttonTemplatesClone.dataset.monsterId = monsterVnum;&lt;br /&gt;
    card.lastElementChild.appendChild(buttonTemplatesClone);&lt;br /&gt;
    vnumToButtons[monsterVnum] = buttonTemplatesClone.children;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateiFrameButtons(characters, iframeInfo, category) {&lt;br /&gt;
  var addedMonsters = Object.keys(characters.savedMonsters);&lt;br /&gt;
  var { currentiFrameIsMonster } = iframeInfo;&lt;br /&gt;
  var vnumToButtons = iframeInfo[category].vnumToButtons;&lt;br /&gt;
  var isPolymorphModal = category === &amp;quot;monster&amp;quot; &amp;amp;&amp;amp; !currentiFrameIsMonster;&lt;br /&gt;
&lt;br /&gt;
  for (var monsterVnum in vnumToButtons) {&lt;br /&gt;
    var [addButton, deleteButton, selectButton] = vnumToButtons[monsterVnum];&lt;br /&gt;
&lt;br /&gt;
    if (isPolymorphModal) {&lt;br /&gt;
      hideElement(addButton);&lt;br /&gt;
      hideElement(deleteButton);&lt;br /&gt;
      showElement(selectButton);&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isValueInArray(monsterVnum, addedMonsters)) {&lt;br /&gt;
      hideElement(addButton);&lt;br /&gt;
      showElement(deleteButton);&lt;br /&gt;
      hideElement(selectButton);&lt;br /&gt;
    } else {&lt;br /&gt;
      showElement(addButton);&lt;br /&gt;
      hideElement(deleteButton);&lt;br /&gt;
      hideElement(selectButton);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  iframeInfo.lastiFrameIsMonster = currentiFrameIsMonster;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getMonsterImage(buttonsContainer) {&lt;br /&gt;
  var elder = buttonsContainer.parentElement.firstElementChild;&lt;br /&gt;
  var image = elder.querySelector(&amp;quot;img&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (image) {&lt;br /&gt;
    return image.getAttribute(&amp;quot;src&amp;quot;) || &amp;quot;&amp;quot;;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return &amp;quot;&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleiFrame(iframeInfo, category) {&lt;br /&gt;
  var { characters, battle } = iframeInfo;&lt;br /&gt;
  var iframeInfoCategory = iframeInfo[category];&lt;br /&gt;
  var { iframe, pageName, vnumToButtons } = iframeInfoCategory;&lt;br /&gt;
  var loadingAnimation = iframeInfoCategory.iframe.previousElementSibling;&lt;br /&gt;
&lt;br /&gt;
  iframe.src = mw.util.getUrl(pageName);&lt;br /&gt;
&lt;br /&gt;
  iframe.addEventListener(&amp;quot;load&amp;quot;, function () {&lt;br /&gt;
    var iframeDoc = this.contentDocument || this.contentWindow.document;&lt;br /&gt;
    var iframeBody = iframeDoc.body;&lt;br /&gt;
&lt;br /&gt;
    content = iframeDoc.getElementById(&amp;quot;show-after-loading&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    iframeBody.firstElementChild.replaceWith(content);&lt;br /&gt;
&lt;br /&gt;
    iframeBody.style.background = &amp;quot;transparent&amp;quot;;&lt;br /&gt;
    iframeBody.style.paddingRight = &amp;quot;10px&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    addButtonsToCards(characters, iframeDoc, iframeInfo, category);&lt;br /&gt;
    updateiFrameButtons(characters, iframeInfo, category);&lt;br /&gt;
&lt;br /&gt;
    iframeInfoCategory.loadIsFinished = true;&lt;br /&gt;
&lt;br /&gt;
    hideElement(loadingAnimation);&lt;br /&gt;
    showElement(iframe);&lt;br /&gt;
&lt;br /&gt;
    iframeDoc.addEventListener(&amp;quot;click&amp;quot;, handleButtonClick);&lt;br /&gt;
&lt;br /&gt;
    function handleButtonClick(event) {&lt;br /&gt;
      var target = event.target;&lt;br /&gt;
      var link = target.closest(&amp;quot;a&amp;quot;);&lt;br /&gt;
      var buttonsContainer = target.closest(&amp;quot;.handle-monster&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
      if (link) {&lt;br /&gt;
        event.preventDefault();&lt;br /&gt;
        window.open(link.href, &amp;quot;_blank&amp;quot;);&lt;br /&gt;
      } else if (buttonsContainer) {&lt;br /&gt;
        var { monsterId: monsterVnum } = buttonsContainer.dataset;&lt;br /&gt;
&lt;br /&gt;
        // polymorph iframe&lt;br /&gt;
        if (category === &amp;quot;monster&amp;quot; &amp;amp;&amp;amp; !iframeInfo.currentiFrameIsMonster) {&lt;br /&gt;
          var monsterImage = getMonsterImage(buttonsContainer);&lt;br /&gt;
          changePolymorphValues(&lt;br /&gt;
            characters.characterCreation,&lt;br /&gt;
            monsterVnum,&lt;br /&gt;
            monsterImage&lt;br /&gt;
          );&lt;br /&gt;
          handlePolymorphDisplay(&lt;br /&gt;
            characters.polymorphDisplay,&lt;br /&gt;
            monsterVnum,&lt;br /&gt;
            monsterImage&lt;br /&gt;
          );&lt;br /&gt;
          var changeEvent = new Event(&amp;quot;change&amp;quot;, { bubbles: true });&lt;br /&gt;
          iframe.dispatchEvent(changeEvent);&lt;br /&gt;
        } else {&lt;br /&gt;
          var addedMonsters = Object.keys(characters.savedMonsters);&lt;br /&gt;
          var [addButton, deleteButton] = vnumToButtons[monsterVnum];&lt;br /&gt;
&lt;br /&gt;
          if (isValueInArray(monsterVnum, addedMonsters)) {&lt;br /&gt;
            deleteMonster(characters, battle, monsterVnum);&lt;br /&gt;
            showElement(addButton);&lt;br /&gt;
            hideElement(deleteButton);&lt;br /&gt;
          } else {&lt;br /&gt;
            var monsterImage = getMonsterImage(buttonsContainer);&lt;br /&gt;
            addNewMonster(&lt;br /&gt;
              characters,&lt;br /&gt;
              battle,&lt;br /&gt;
              monsterVnum,&lt;br /&gt;
              monsterImage,&lt;br /&gt;
              iframeInfo,&lt;br /&gt;
              category&lt;br /&gt;
            );&lt;br /&gt;
            hideElement(addButton);&lt;br /&gt;
            showElement(deleteButton);&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getNameToVnumMapping() {&lt;br /&gt;
  var nameToVnum = {};&lt;br /&gt;
&lt;br /&gt;
  for (var monsterVnum in monsterData) {&lt;br /&gt;
    nameToVnum[monsterData[monsterVnum][monsterData[monsterVnum].length - 1]] =&lt;br /&gt;
      monsterVnum;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return nameToVnum;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function monsterManagement(characters, battle) {&lt;br /&gt;
  var { monsteriFrame, stoneiFrame } = characters;&lt;br /&gt;
  var monsterVnums = Object.keys(monsterData);&lt;br /&gt;
&lt;br /&gt;
  var iframeInfo = {&lt;br /&gt;
    lastiFrameIsMonster: false,&lt;br /&gt;
    currentiFrameIsMonster: false,&lt;br /&gt;
    characters: characters,&lt;br /&gt;
    battle: battle,&lt;br /&gt;
    nameToVnum: getNameToVnumMapping(),&lt;br /&gt;
    monster: {&lt;br /&gt;
      isLoaded: false,&lt;br /&gt;
      loadIsFinished: false,&lt;br /&gt;
      shouldBeUpdated: false,&lt;br /&gt;
      vnumToButtons: {},&lt;br /&gt;
      pageName: &amp;quot;Monstres&amp;quot;,&lt;br /&gt;
      iframe: monsteriFrame,&lt;br /&gt;
    },&lt;br /&gt;
    stone: {&lt;br /&gt;
      isLoaded: false,&lt;br /&gt;
      loadIsFinished: false,&lt;br /&gt;
      shouldBeUpdated: false,&lt;br /&gt;
      vnumToButtons: {},&lt;br /&gt;
      pageName: &amp;quot;Pierres Metin&amp;quot;,&lt;br /&gt;
      iframe: stoneiFrame,&lt;br /&gt;
    },&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  document.addEventListener(&amp;quot;modalOpen&amp;quot;, function (event) {&lt;br /&gt;
    var modalName = event.detail.name;&lt;br /&gt;
&lt;br /&gt;
    if (modalName === &amp;quot;monster&amp;quot; || modalName === &amp;quot;stone&amp;quot;) {&lt;br /&gt;
      handleModal(event.target, modalName);&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  function handleModal(target, modalName) {&lt;br /&gt;
    var iframeInfoCategory = iframeInfo[modalName];&lt;br /&gt;
&lt;br /&gt;
    if (modalName === &amp;quot;monster&amp;quot;) {&lt;br /&gt;
      var isMonsteriFrame = target.id === &amp;quot;add-new-monster&amp;quot;;&lt;br /&gt;
      iframeInfo.currentiFrameIsMonster = isMonsteriFrame;&lt;br /&gt;
&lt;br /&gt;
      if (&lt;br /&gt;
        iframeInfoCategory.loadIsFinished &amp;amp;&amp;amp;&lt;br /&gt;
        ((isMonsteriFrame &amp;amp;&amp;amp; !iframeInfo.lastiFrameIsMonster) ||&lt;br /&gt;
          (!isMonsteriFrame &amp;amp;&amp;amp; iframeInfo.lastiFrameIsMonster))&lt;br /&gt;
      ) {&lt;br /&gt;
        iframeInfoCategory.shouldBeUpdated = true;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (!iframeInfoCategory.isLoaded) {&lt;br /&gt;
      handleiFrame(iframeInfo, modalName);&lt;br /&gt;
      iframeInfoCategory.isLoaded = true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      iframeInfoCategory.loadIsFinished &amp;amp;&amp;amp;&lt;br /&gt;
      iframeInfoCategory.shouldBeUpdated&lt;br /&gt;
    ) {&lt;br /&gt;
      updateiFrameButtons(characters, iframeInfo, modalName);&lt;br /&gt;
      iframeInfoCategory.shouldBeUpdated = false;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  Object.keys(characters.savedMonsters)&lt;br /&gt;
    .slice()&lt;br /&gt;
    .forEach(function (monsterVnum) {&lt;br /&gt;
      if (isValueInArray(monsterVnum, monsterVnums)) {&lt;br /&gt;
        addMonsterElement(characters, battle, monsterVnum, iframeInfo);&lt;br /&gt;
      } else {&lt;br /&gt;
        deleteMonster(characters, battle, monsterVnum);&lt;br /&gt;
      }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function removeBattleChoice(battle, name) {&lt;br /&gt;
  var battleSelects = [battle.attackerSelection, battle.victimSelection];&lt;br /&gt;
&lt;br /&gt;
  battleSelects.forEach(function (battleSelect) {&lt;br /&gt;
    for (&lt;br /&gt;
      var optionIndex = 0;&lt;br /&gt;
      optionIndex &amp;lt; battleSelect.options.length;&lt;br /&gt;
      optionIndex++&lt;br /&gt;
    ) {&lt;br /&gt;
      if (battleSelect.options[optionIndex].value === name) {&lt;br /&gt;
        battleSelect.remove(optionIndex);&lt;br /&gt;
        break;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addBattleChoice(battle, name, isMonster = false) {&lt;br /&gt;
  function createOption(text, vnum) {&lt;br /&gt;
    var option = document.createElement(&amp;quot;option&amp;quot;);&lt;br /&gt;
    option.textContent = text;&lt;br /&gt;
    option.value = vnum;&lt;br /&gt;
&lt;br /&gt;
    if (!isMonster) {&lt;br /&gt;
      option.classList.add(&amp;quot;notranslate&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return option;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var vnum = name;&lt;br /&gt;
&lt;br /&gt;
  if (isMonster) {&lt;br /&gt;
    name = getMonsterName(name);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (isMonster &amp;amp;&amp;amp; monsterData[vnum][1]) {&lt;br /&gt;
    // pass&lt;br /&gt;
  } else {&lt;br /&gt;
    battle.attackerSelection.appendChild(createOption(name, vnum));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  battle.victimSelection.appendChild(createOption(name, vnum));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateBattleChoice(characters, battle) {&lt;br /&gt;
  function addChoices(names, isMonster) {&lt;br /&gt;
    for (var index = 0; index &amp;lt; names.length; index++) {&lt;br /&gt;
      addBattleChoice(battle, names[index], isMonster);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var characterNames = Object.keys(characters.savedCharacters);&lt;br /&gt;
  var monsterNames = Object.keys(characters.savedMonsters);&lt;br /&gt;
&lt;br /&gt;
  addChoices(characterNames, false);&lt;br /&gt;
  addChoices(monsterNames, true);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isPC(character) {&lt;br /&gt;
  if (character.race === 0 || character.race === 1) {&lt;br /&gt;
    return false;&lt;br /&gt;
  }&lt;br /&gt;
  return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isBoss(character) {&lt;br /&gt;
  return character.race === 0 &amp;amp;&amp;amp; character.rank &amp;gt;= 5;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isStone(character) {&lt;br /&gt;
  return character.race === 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isMeleeAttacker(monster) {&lt;br /&gt;
  return monster.attack == 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isRangeAttacker(monster) {&lt;br /&gt;
  return monster.attack == 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isMagicAttacker(monster) {&lt;br /&gt;
  return monster.attack == 2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isMagicClass(character) {&lt;br /&gt;
  return character.race === &amp;quot;shaman&amp;quot; || character.class === &amp;quot;black_magic&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isDispell(character, skillId) {&lt;br /&gt;
  return character.class === &amp;quot;weaponary&amp;quot; &amp;amp;&amp;amp; skillId === 6;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isPolymorph(character) {&lt;br /&gt;
  return isChecked(character.isPolymorph);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isRiding(character) {&lt;br /&gt;
  return isChecked(character.isRiding);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isBow(weaponType) {&lt;br /&gt;
  return weaponType === 2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcAttackFactor(attacker, victim) {&lt;br /&gt;
  function calcCoeffK(dex, level) {&lt;br /&gt;
    return Math.min(90, Math.floor((2 * dex + level) / 3));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var K1 = calcCoeffK(attacker.polymorphDex, attacker.level);&lt;br /&gt;
  var K2 = calcCoeffK(victim.polymorphDex, attacker.level);&lt;br /&gt;
&lt;br /&gt;
  var AR = (K1 + 210) / 300;&lt;br /&gt;
  var ER = (((2 * K2 + 5) / (K2 + 95)) * 3) / 10;&lt;br /&gt;
&lt;br /&gt;
  return truncateNumber(AR - ER, 8);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcMainAttackValue(attacker) {&lt;br /&gt;
  var leadership = 0;&lt;br /&gt;
  var weaponGrowth = 0;&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker)) {&lt;br /&gt;
    weaponGrowth = attacker.weapon.growth;&lt;br /&gt;
    leadership = attacker.leadership;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return 2 * (attacker.level + weaponGrowth) + leadership;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcStatAttackValue(character) {&lt;br /&gt;
  switch (character.race) {&lt;br /&gt;
    case &amp;quot;warrior&amp;quot;:&lt;br /&gt;
    case &amp;quot;sura&amp;quot;:&lt;br /&gt;
      return 2 * character.str;&lt;br /&gt;
    case &amp;quot;ninja&amp;quot;:&lt;br /&gt;
      return Math.floor((1 / 4) * (character.str + 7 * character.dex));&lt;br /&gt;
    case &amp;quot;shaman&amp;quot;:&lt;br /&gt;
      return Math.floor((1 / 3) * (5 * character.int + character.dex));&lt;br /&gt;
    case &amp;quot;lycan&amp;quot;:&lt;br /&gt;
      return character.vit + 2 * character.dex;&lt;br /&gt;
    default:&lt;br /&gt;
      return 2 * character.str;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcSecondaryAttackValue(attacker) {&lt;br /&gt;
  var attackValueOther = 0;&lt;br /&gt;
&lt;br /&gt;
  var minAttackValue = 0;&lt;br /&gt;
  var maxAttackValue = 0;&lt;br /&gt;
&lt;br /&gt;
  var minAttackValueSlash = 0;&lt;br /&gt;
  var maxAttackValueSlash = 0;&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker)) {&lt;br /&gt;
    var { type, isSerpent, minAttackValue, maxAttackValue, growth } =&lt;br /&gt;
      attacker.weapon;&lt;br /&gt;
&lt;br /&gt;
    if (isSerpent) {&lt;br /&gt;
      minAttackValue = Math.max(0, attacker.minAttackValueRandom - growth);&lt;br /&gt;
      maxAttackValue = Math.max(&lt;br /&gt;
        minAttackValue,&lt;br /&gt;
        attacker.maxAttackValueRandom - growth&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    minAttackValueSlash = Math.min(&lt;br /&gt;
      attacker.minAttackValueSlash,&lt;br /&gt;
      attacker.maxAttackValueSlash&lt;br /&gt;
    );&lt;br /&gt;
    maxAttackValueSlash = Math.max(&lt;br /&gt;
      attacker.minAttackValueSlash,&lt;br /&gt;
      attacker.maxAttackValueSlash&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    attackValueOther += attacker.attackValue;&lt;br /&gt;
&lt;br /&gt;
    if (isBow(type) &amp;amp;&amp;amp; !isPolymorph(attacker)) {&lt;br /&gt;
      attackValueOther += 25;&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    minAttackValue = attacker.minAttackValue;&lt;br /&gt;
    maxAttackValue = attacker.maxAttackValue;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  minAttackValue += attacker.minAttackValuePolymorph;&lt;br /&gt;
  maxAttackValue += attacker.maxAttackValuePolymorph;&lt;br /&gt;
&lt;br /&gt;
  attackValueOther += attacker.statAttackValue;&lt;br /&gt;
  attackValueOther += attacker.horseAttackValue;&lt;br /&gt;
&lt;br /&gt;
  var weaponInterval = maxAttackValue - minAttackValue + 1;&lt;br /&gt;
  var slashInterval = maxAttackValueSlash - minAttackValueSlash + 1;&lt;br /&gt;
&lt;br /&gt;
  var totalCardinal = weaponInterval * slashInterval * 1_000_000;&lt;br /&gt;
  var minInterval = Math.min(weaponInterval, slashInterval);&lt;br /&gt;
&lt;br /&gt;
  minAttackValue += minAttackValueSlash;&lt;br /&gt;
  maxAttackValue += maxAttackValueSlash;&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    minAttackValue: minAttackValue,&lt;br /&gt;
    maxAttackValue: maxAttackValue,&lt;br /&gt;
    attackValueOther: attackValueOther,&lt;br /&gt;
    totalCardinal: totalCardinal,&lt;br /&gt;
    weights: calcWeights(minAttackValue, maxAttackValue, minInterval),&lt;br /&gt;
    possibleDamagesCount: maxAttackValue - minAttackValue + 1,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcMagicAttackValue(attacker) {&lt;br /&gt;
  var minMagicAttackValueSlash = 0;&lt;br /&gt;
  var maxMagicAttackValueSlash = 0;&lt;br /&gt;
&lt;br /&gt;
  var { isSerpent, minMagicAttackValue, maxMagicAttackValue, growth } =&lt;br /&gt;
    attacker.weapon;&lt;br /&gt;
&lt;br /&gt;
  if (isSerpent) {&lt;br /&gt;
    minMagicAttackValue = Math.max(0, attacker.minMagicAttackValueRandom);&lt;br /&gt;
    maxMagicAttackValue = Math.max(&lt;br /&gt;
      minMagicAttackValue,&lt;br /&gt;
      attacker.maxMagicAttackValueRandom&lt;br /&gt;
    );&lt;br /&gt;
  } else {&lt;br /&gt;
    minMagicAttackValue += growth;&lt;br /&gt;
    maxMagicAttackValue += growth;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  minMagicAttackValueSlash = Math.min(&lt;br /&gt;
    attacker.minMagicAttackValueSlash,&lt;br /&gt;
    attacker.maxMagicAttackValueSlash&lt;br /&gt;
  );&lt;br /&gt;
  maxMagicAttackValueSlash = Math.max(&lt;br /&gt;
    attacker.minMagicAttackValueSlash,&lt;br /&gt;
    attacker.maxMagicAttackValueSlash&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  var weaponInterval = maxMagicAttackValue - minMagicAttackValue + 1;&lt;br /&gt;
  var slashInterval = maxMagicAttackValueSlash - minMagicAttackValueSlash + 1;&lt;br /&gt;
&lt;br /&gt;
  var totalCardinal = weaponInterval * slashInterval * 1_000_000;&lt;br /&gt;
  var minInterval = Math.min(weaponInterval, slashInterval);&lt;br /&gt;
&lt;br /&gt;
  minMagicAttackValue += minMagicAttackValueSlash;&lt;br /&gt;
  maxMagicAttackValue += maxMagicAttackValueSlash;&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    minMagicAttackValue: minMagicAttackValue,&lt;br /&gt;
    maxMagicAttackValue: maxMagicAttackValue,&lt;br /&gt;
    magicAttackValueAugmentation: getMagicAttackValueAugmentation(&lt;br /&gt;
      minMagicAttackValue,&lt;br /&gt;
      maxMagicAttackValue,&lt;br /&gt;
      attacker.magicAttackValue&lt;br /&gt;
    ),&lt;br /&gt;
    totalCardinal: totalCardinal,&lt;br /&gt;
    weights: calcWeights(minMagicAttackValue, maxMagicAttackValue, minInterval),&lt;br /&gt;
    possibleDamagesCount: maxMagicAttackValue - minMagicAttackValue + 1,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getPolymorphPower(polymorphPoint, polymorphPowerTable) {&lt;br /&gt;
  return polymorphPowerTable[polymorphPoint];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSkillPower(skillPoint, skillPowerTable) {&lt;br /&gt;
  return skillPowerTable[skillPoint];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getMarriageBonusValue(character, marriageTable, itemName) {&lt;br /&gt;
  var index;&lt;br /&gt;
  var lovePoint = character.lovePoint;&lt;br /&gt;
&lt;br /&gt;
  if (lovePoint &amp;lt; 65) {&lt;br /&gt;
    index = 0;&lt;br /&gt;
  } else if (lovePoint &amp;lt; 80) {&lt;br /&gt;
    index = 1;&lt;br /&gt;
  } else if (lovePoint &amp;lt; 100) {&lt;br /&gt;
    index = 2;&lt;br /&gt;
  } else {&lt;br /&gt;
    index = 3;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return marriageTable[itemName][index];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcDamageWithPrimaryBonuses(damages, bonusValues) {&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.attackValueCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  damages += bonusValues.attackValueMarriage;&lt;br /&gt;
&lt;br /&gt;
  damages = Math.floor(&lt;br /&gt;
    (damages * bonusValues.monsterResistanceMarriageCoeff) / 100&lt;br /&gt;
  );&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.monsterResistanceCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  damages += Math.floor((damages * bonusValues.typeBonusCoeff) / 100);&lt;br /&gt;
  damages +=&lt;br /&gt;
    Math.floor((damages * bonusValues.raceBonusCoeff) / 100) -&lt;br /&gt;
    Math.floor((damages * bonusValues.raceResistanceCoeff) / 100);&lt;br /&gt;
  damages += Math.floor((damages * bonusValues.stoneBonusCoeff) / 100);&lt;br /&gt;
  damages += Math.floor((damages * bonusValues.monsterBonusCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  var elementBonusCoeff = bonusValues.elementBonusCoeff;&lt;br /&gt;
&lt;br /&gt;
  damages +=&lt;br /&gt;
    Math.trunc((damages * elementBonusCoeff[0]) / 10000) +&lt;br /&gt;
    Math.trunc((damages * elementBonusCoeff[1]) / 10000) +&lt;br /&gt;
    Math.trunc((damages * elementBonusCoeff[2]) / 10000) +&lt;br /&gt;
    Math.trunc((damages * elementBonusCoeff[3]) / 10000) +&lt;br /&gt;
    Math.trunc((damages * elementBonusCoeff[4]) / 10000) +&lt;br /&gt;
    Math.trunc((damages * elementBonusCoeff[5]) / 10000);&lt;br /&gt;
&lt;br /&gt;
  damages = Math.floor(damages * bonusValues.damageMultiplier);&lt;br /&gt;
&lt;br /&gt;
  return damages;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcDamageWithSecondaryBonuses(&lt;br /&gt;
  damages,&lt;br /&gt;
  bonusValues,&lt;br /&gt;
  damagesType,&lt;br /&gt;
  minPiercingDamages,&lt;br /&gt;
  damagesWithPrimaryBonuses&lt;br /&gt;
) {&lt;br /&gt;
  damages = Math.floor(damages * bonusValues.magicResistanceCoeff);&lt;br /&gt;
  damages = Math.trunc((damages * bonusValues.weaponDefenseCoeff) / 100);&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.tigerStrengthCoeff) / 100);&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.blessingBonusCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  if (damagesType.criticalHit) {&lt;br /&gt;
    damages *= 2;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (damagesType.piercingHit) {&lt;br /&gt;
    damages += bonusValues.defenseBoost + Math.min(0, minPiercingDamages);&lt;br /&gt;
    damages += Math.floor(&lt;br /&gt;
      (damagesWithPrimaryBonuses * bonusValues.extraPiercingHitCoeff) / 1000&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.averageDamageCoeff) / 100);&lt;br /&gt;
  damages = Math.floor(&lt;br /&gt;
    (damages * bonusValues.averageDamageResistanceCoeff) / 100&lt;br /&gt;
  );&lt;br /&gt;
  damages = Math.floor(&lt;br /&gt;
    (damages * bonusValues.skillDamageResistanceCoeff) / 100&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.rankBonusCoeff) / 100);&lt;br /&gt;
  damages = Math.max(0, damages + bonusValues.defensePercent);&lt;br /&gt;
  damages += Math.min(&lt;br /&gt;
    300,&lt;br /&gt;
    Math.floor((damages * bonusValues.damageBonusCoeff) / 100)&lt;br /&gt;
  );&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.empireMalusCoeff) / 10);&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.sungMaStrBonusCoeff) / 10000);&lt;br /&gt;
  damages -= Math.floor(damages * bonusValues.sungmaStrMalusCoeff);&lt;br /&gt;
&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.whiteDragonElixirCoeff) / 100);&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.steelDragonElixirCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  return damages;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcSkillDamageWithSecondaryBonuses(&lt;br /&gt;
  damages,&lt;br /&gt;
  bonusValues,&lt;br /&gt;
  damagesType,&lt;br /&gt;
  minPiercingDamages&lt;br /&gt;
) {&lt;br /&gt;
  damages = Math.floor(damages * bonusValues.magicResistanceCoeff);&lt;br /&gt;
  damages = Math.trunc((damages * bonusValues.weaponDefenseCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  damages -= bonusValues.defense;&lt;br /&gt;
&lt;br /&gt;
  damages = floorMultiplication(damages, bonusValues.skillWardCoeff);&lt;br /&gt;
  damages = floorMultiplication(damages, bonusValues.skillBonusCoeff);&lt;br /&gt;
&lt;br /&gt;
  var tempDamages = Math.floor(&lt;br /&gt;
    (damages * bonusValues.skillBonusByBonusCoeff) / 100&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  damages = Math.floor(&lt;br /&gt;
    (tempDamages * bonusValues.magicAttackValueCoeff) / 100 + 0.5&lt;br /&gt;
  );&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.tigerStrengthCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  if (damagesType.criticalHit) {&lt;br /&gt;
    damages *= 2;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (damagesType.piercingHit) {&lt;br /&gt;
    damages += bonusValues.defenseBoost + Math.min(0, minPiercingDamages);&lt;br /&gt;
    damages += Math.floor(&lt;br /&gt;
      (tempDamages * bonusValues.extraPiercingHitCoeff) / 1000&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.skillDamageCoeff) / 100);&lt;br /&gt;
  damages = Math.floor(&lt;br /&gt;
    (damages * bonusValues.skillDamageResistanceCoeff) / 100&lt;br /&gt;
  );&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.rankBonusCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  damages = Math.max(0, damages + bonusValues.defensePercent);&lt;br /&gt;
  damages += Math.min(&lt;br /&gt;
    300,&lt;br /&gt;
    Math.floor((damages * bonusValues.damageBonusCoeff) / 100)&lt;br /&gt;
  );&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.empireMalusCoeff) / 10);&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.sungMaStrBonusCoeff) / 10000);&lt;br /&gt;
  damages -= Math.floor(damages * bonusValues.sungmaStrMalusCoeff);&lt;br /&gt;
&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.whiteDragonElixirCoeff) / 100);&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.steelDragonElixirCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  return damages;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function computePolymorphPoint(attacker, victim, polymorphPowerTable) {&lt;br /&gt;
  attacker.statAttackValue = 0;&lt;br /&gt;
&lt;br /&gt;
  attacker.polymorphDex = attacker.dex;&lt;br /&gt;
  victim.polymorphDex = victim.dex;&lt;br /&gt;
&lt;br /&gt;
  attacker.minAttackValuePolymorph = 0;&lt;br /&gt;
  attacker.maxAttackValuePolymorph = 0;&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker) &amp;amp;&amp;amp; isPolymorph(attacker)) {&lt;br /&gt;
    var polymorphPowerPct =&lt;br /&gt;
      getPolymorphPower(attacker.polymorphPoint, polymorphPowerTable) / 100;&lt;br /&gt;
    var polymorphMonster = createMonster(attacker.polymorphMonster, null, true);&lt;br /&gt;
&lt;br /&gt;
    var polymorphStr = floorMultiplication(&lt;br /&gt;
      polymorphPowerPct,&lt;br /&gt;
      polymorphMonster.str&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    attacker.polymorphDex += floorMultiplication(&lt;br /&gt;
      polymorphPowerPct,&lt;br /&gt;
      polymorphMonster.dex&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    attacker.minAttackValuePolymorph = floorMultiplication(&lt;br /&gt;
      polymorphPowerPct,&lt;br /&gt;
      polymorphMonster.minAttackValue&lt;br /&gt;
    );&lt;br /&gt;
    attacker.maxAttackValuePolymorph = floorMultiplication(&lt;br /&gt;
      polymorphPowerPct,&lt;br /&gt;
      polymorphMonster.maxAttackValue&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    if (!attacker.weapon) {&lt;br /&gt;
      attacker.maxAttackValuePolymorph += 1;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    attacker.attackValue = 0;&lt;br /&gt;
&lt;br /&gt;
    if (isMagicClass(attacker)) {&lt;br /&gt;
      attacker.statAttackValue = 2 * (polymorphStr + attacker.int);&lt;br /&gt;
    } else {&lt;br /&gt;
      attacker.statAttackValue = 2 * (polymorphStr + attacker.str);&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    attacker.statAttackValue = calcStatAttackValue(attacker);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function computeHorse(attacker) {&lt;br /&gt;
  attacker.horseAttackValue = 0;&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker) &amp;amp;&amp;amp; isRiding(attacker)) {&lt;br /&gt;
    var horseConstant = 30;&lt;br /&gt;
&lt;br /&gt;
    if (attacker.class === &amp;quot;weaponary&amp;quot;) {&lt;br /&gt;
      horseConstant = 60;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    attacker.horseAttackValue = floorMultiplication(&lt;br /&gt;
      2 * attacker.level + attacker.statAttackValue,&lt;br /&gt;
      attacker.horsePoint / horseConstant&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getRankBonus(attacker) {&lt;br /&gt;
  if (!isChecked(attacker.lowRank)) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  switch (attacker.playerRank) {&lt;br /&gt;
    case &amp;quot;aggressive&amp;quot;:&lt;br /&gt;
      return 1;&lt;br /&gt;
    case &amp;quot;fraudulent&amp;quot;:&lt;br /&gt;
      return 2;&lt;br /&gt;
    case &amp;quot;malicious&amp;quot;:&lt;br /&gt;
      return 3;&lt;br /&gt;
    case &amp;quot;cruel&amp;quot;:&lt;br /&gt;
      return 5;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcElementCoeffPvP(elementBonus, mapping, attacker, victim) {&lt;br /&gt;
  var minElementMalus = 0;&lt;br /&gt;
  var maxDifference = 0;&lt;br /&gt;
  var savedElementDifferences = [];&lt;br /&gt;
  var elementBonusIndex = 0;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; elementBonus.length; index++) {&lt;br /&gt;
    if (!attacker[mapping.elementBonus[index]]) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var elementDifference =&lt;br /&gt;
      attacker[mapping.elementBonus[index]] -&lt;br /&gt;
      victim[mapping.elementResistance[index]];&lt;br /&gt;
&lt;br /&gt;
    if (elementDifference &amp;gt;= 0) {&lt;br /&gt;
      elementBonus[elementBonusIndex] = 10 * elementDifference;&lt;br /&gt;
      minElementMalus -= elementDifference;&lt;br /&gt;
      maxDifference = Math.max(maxDifference, elementDifference);&lt;br /&gt;
      elementBonusIndex++;&lt;br /&gt;
    } else {&lt;br /&gt;
      savedElementDifferences.push(elementDifference);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (!savedElementDifferences.length) {&lt;br /&gt;
    return;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  minElementMalus += maxDifference;&lt;br /&gt;
  savedElementDifferences.sort(compareNumbers);&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; savedElementDifferences.length; index++) {&lt;br /&gt;
    var elementDifference = savedElementDifferences[index];&lt;br /&gt;
&lt;br /&gt;
    elementBonus[elementBonusIndex + index] =&lt;br /&gt;
      10 * Math.max(minElementMalus, elementDifference);&lt;br /&gt;
&lt;br /&gt;
    minElementMalus = Math.min(&lt;br /&gt;
      0,&lt;br /&gt;
      Math.max(minElementMalus, minElementMalus - elementDifference)&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function skillChanceReduction(value) {&lt;br /&gt;
  if (value &amp;lt;= 9) {&lt;br /&gt;
    return Math.floor(value / 2);&lt;br /&gt;
  }&lt;br /&gt;
  return 5 + Math.floor((value - 10) / 4);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function magicResistanceToCoeff(magicResistance) {&lt;br /&gt;
  if (magicResistance) {&lt;br /&gt;
    return 2000 / (6 * magicResistance + 1000) - 1;&lt;br /&gt;
  }&lt;br /&gt;
  return 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createBattleValues(attacker, victim, battle, skillType) {&lt;br /&gt;
  var { mapping, constants } = battle;&lt;br /&gt;
  var calcAttackValues;&lt;br /&gt;
&lt;br /&gt;
  var missPercentage = 0;&lt;br /&gt;
  var attackValueMeleeMagic = 0;&lt;br /&gt;
  var attackValueMarriage = 0;&lt;br /&gt;
  var monsterResistanceMarriage = 0;&lt;br /&gt;
  var monsterResistance = 0;&lt;br /&gt;
  var typeBonus = 0;&lt;br /&gt;
  var raceBonus = 0;&lt;br /&gt;
  var raceResistance = 0;&lt;br /&gt;
  var stoneBonus = 0;&lt;br /&gt;
  var monsterBonus = 0;&lt;br /&gt;
  var elementBonus = [0, 0, 0, 0, 0, 0]; // fire, ice, lightning, earth, darkness, wind, order doesn't matter&lt;br /&gt;
  var defenseMarriage = 0;&lt;br /&gt;
  var damageMultiplier = 1;&lt;br /&gt;
  var useDamages = 1;&lt;br /&gt;
  var defense = victim.defense;&lt;br /&gt;
  var defenseBoost = defense;&lt;br /&gt;
  var magicResistance = 0;&lt;br /&gt;
  var weaponDefense = 0;&lt;br /&gt;
  var tigerStrength = 0;&lt;br /&gt;
  var blessingBonus = 0;&lt;br /&gt;
  var magicAttackValueMeleeMagic = 0;&lt;br /&gt;
  var criticalHitPercentage = attacker.criticalHit;&lt;br /&gt;
  var piercingHitPercentage = attacker.piercingHit;&lt;br /&gt;
  var extraPiercingHitPercentage = Math.max(0, piercingHitPercentage - 100);&lt;br /&gt;
  var averageDamage = 0;&lt;br /&gt;
  var averageDamageResistance = 0;&lt;br /&gt;
  var skillDamage = 0;&lt;br /&gt;
  var skillDamageResistance = 0;&lt;br /&gt;
  var rankBonus = 0;&lt;br /&gt;
  var defensePercent = 0;&lt;br /&gt;
  var damageBonus = 0;&lt;br /&gt;
  var empireMalus = 0;&lt;br /&gt;
  var sungMaStrBonus = 0;&lt;br /&gt;
  var sungmaStrMalus = 0;&lt;br /&gt;
  var whiteDragonElixir = 0;&lt;br /&gt;
  var steelDragonElixir = 0;&lt;br /&gt;
&lt;br /&gt;
  computePolymorphPoint(attacker, victim, constants.polymorphPowerTable);&lt;br /&gt;
  computeHorse(attacker);&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker)) {&lt;br /&gt;
    if (weaponData.hasOwnProperty(attacker.weapon)) {&lt;br /&gt;
      attacker.weapon = createWeapon(attacker.weapon);&lt;br /&gt;
    } else {&lt;br /&gt;
      attacker.weapon = createWeapon(0);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    attacker.weapon.getValues(attacker.weaponUpgrade);&lt;br /&gt;
&lt;br /&gt;
    attackValueMeleeMagic =&lt;br /&gt;
      attacker.attackValuePercent + Math.min(100, attacker.attackMeleeMagic);&lt;br /&gt;
&lt;br /&gt;
    var weaponType = attacker.weapon.type;&lt;br /&gt;
&lt;br /&gt;
    if (skillType &amp;amp;&amp;amp; attacker.class === &amp;quot;archery&amp;quot;) {&lt;br /&gt;
      if (weaponType !== 2) {&lt;br /&gt;
        useDamages = 0;&lt;br /&gt;
        weaponType = 2;&lt;br /&gt;
      }&lt;br /&gt;
      defense = 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var weaponDefenseName = mapping.defenseWeapon[weaponType];&lt;br /&gt;
    var weaponDefenseBreakName = mapping.breakWeapon[weaponType];&lt;br /&gt;
&lt;br /&gt;
    if (victim.hasOwnProperty(weaponDefenseName)) {&lt;br /&gt;
      weaponDefense = victim[weaponDefenseName];&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isChecked(attacker.whiteDragonElixir)) {&lt;br /&gt;
      whiteDragonElixir = 10;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isPC(victim)) {&lt;br /&gt;
      if (!skillType) {&lt;br /&gt;
        if (weaponType === 2 &amp;amp;&amp;amp; !isPolymorph(attacker)) {&lt;br /&gt;
          missPercentage = victim.arrowBlock;&lt;br /&gt;
        } else {&lt;br /&gt;
          missPercentage = victim.meleeBlock;&lt;br /&gt;
        }&lt;br /&gt;
        missPercentage +=&lt;br /&gt;
          victim.meleeArrowBlock -&lt;br /&gt;
          (missPercentage * victim.meleeArrowBlock) / 100;&lt;br /&gt;
&lt;br /&gt;
        blessingBonus = calcBlessingBonus(constants.skillPowerTable, victim);&lt;br /&gt;
        averageDamageResistance = victim.averageDamageResistance;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      typeBonus = Math.max(1, attacker.humanBonus - victim.humanResistance);&lt;br /&gt;
      raceBonus = attacker[mapping.raceBonus[victim.race]];&lt;br /&gt;
      raceResistance = victim[mapping.raceResistance[attacker.race]];&lt;br /&gt;
&lt;br /&gt;
      calcElementCoeffPvP(elementBonus, mapping, attacker, victim);&lt;br /&gt;
&lt;br /&gt;
      if (weaponType !== 2 &amp;amp;&amp;amp; attacker.hasOwnProperty(weaponDefenseBreakName)) {&lt;br /&gt;
        weaponDefense -= attacker[weaponDefenseBreakName];&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      criticalHitPercentage = 0;&lt;br /&gt;
    } else {&lt;br /&gt;
      if (isChecked(attacker.isMarried)) {&lt;br /&gt;
        if (isChecked(attacker.loveNecklace)) {&lt;br /&gt;
          attackValueMarriage = getMarriageBonusValue(&lt;br /&gt;
            attacker,&lt;br /&gt;
            constants.marriageTable,&lt;br /&gt;
            &amp;quot;loveNecklace&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isChecked(attacker.loveEarrings)) {&lt;br /&gt;
          criticalHitPercentage += getMarriageBonusValue(&lt;br /&gt;
            attacker,&lt;br /&gt;
            constants.marriageTable,&lt;br /&gt;
            &amp;quot;loveEarrings&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isChecked(attacker.harmonyEarrings)) {&lt;br /&gt;
          piercingHitPercentage += getMarriageBonusValue(&lt;br /&gt;
            attacker,&lt;br /&gt;
            constants.marriageTable,&lt;br /&gt;
            &amp;quot;harmonyEarrings&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (isChecked(attacker.tigerStrength)) {&lt;br /&gt;
        tigerStrength = 40;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      for (var index = 0; index &amp;lt; elementBonus.length; index++) {&lt;br /&gt;
        var elementBonusName = mapping.elementBonus[index];&lt;br /&gt;
        var elementResistanceName = mapping.elementResistance[index];&lt;br /&gt;
&lt;br /&gt;
        if (attacker[elementBonusName] &amp;amp;&amp;amp; victim[elementBonusName]) {&lt;br /&gt;
          elementBonus[index] =&lt;br /&gt;
            50 * (attacker[elementBonusName] - victim[elementResistanceName]);&lt;br /&gt;
        } else {&lt;br /&gt;
          elementBonus[index] = 5 * attacker[elementBonusName];&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      var victimType = victim.type;&lt;br /&gt;
&lt;br /&gt;
      if (victimType !== -1) {&lt;br /&gt;
        typeBonus = attacker[mapping.typeFlag[victimType]];&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      monsterBonus = attacker.monsterBonus;&lt;br /&gt;
&lt;br /&gt;
      if (isStone(victim)) {&lt;br /&gt;
        stoneBonus = attacker.stoneBonus;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (isBoss(victim)) {&lt;br /&gt;
        if (skillType) {&lt;br /&gt;
          skillDamage += attacker.skillBossDamage;&lt;br /&gt;
        } else {&lt;br /&gt;
          averageDamage += attacker.bossDamage;&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (isChecked(attacker.onYohara)) {&lt;br /&gt;
        var sungmaStrDifference = attacker.sungmaStr - attacker.sungmaStrMalus;&lt;br /&gt;
&lt;br /&gt;
        if (sungmaStrDifference &amp;gt;= 0) {&lt;br /&gt;
          sungMaStrBonus = sungmaStrDifference;&lt;br /&gt;
        } else {&lt;br /&gt;
          sungmaStrMalus = 0.5;&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (skillType) {&lt;br /&gt;
      skillDamage += attacker.skillDamage;&lt;br /&gt;
    } else {&lt;br /&gt;
      averageDamage += attacker.averageDamage;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    rankBonus = getRankBonus(attacker);&lt;br /&gt;
    damageBonus = attacker.damageBonus;&lt;br /&gt;
&lt;br /&gt;
    if (isChecked(attacker.empireMalus)) {&lt;br /&gt;
      empireMalus = 1;&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    if (isPC(victim)) {&lt;br /&gt;
      if (isChecked(victim.isMarried)) {&lt;br /&gt;
        if (isChecked(victim.harmonyBracelet)) {&lt;br /&gt;
          monsterResistanceMarriage = getMarriageBonusValue(&lt;br /&gt;
            victim,&lt;br /&gt;
            constants.marriageTable,&lt;br /&gt;
            &amp;quot;harmonyBracelet&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isChecked(victim.harmonyNecklace) &amp;amp;&amp;amp; !skillType) {&lt;br /&gt;
          defenseMarriage = getMarriageBonusValue(&lt;br /&gt;
            victim,&lt;br /&gt;
            constants.marriageTable,&lt;br /&gt;
            &amp;quot;harmonyNecklace&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      monsterResistance = victim.monsterResistance;&lt;br /&gt;
&lt;br /&gt;
      for (var index = 0; index &amp;lt; elementBonus.length; index++) {&lt;br /&gt;
        var elementBonusName = mapping.elementBonus[index];&lt;br /&gt;
        var elementResistanceName = mapping.elementResistance[index];&lt;br /&gt;
&lt;br /&gt;
        if (attacker[elementBonusName]) {&lt;br /&gt;
          elementBonus[index] =&lt;br /&gt;
            80 * (attacker[elementBonusName] - victim[elementResistanceName]);&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (!skillType) {&lt;br /&gt;
        if (isMeleeAttacker(attacker)) {&lt;br /&gt;
          missPercentage = victim.meleeBlock;&lt;br /&gt;
          averageDamageResistance = victim.averageDamageResistance;&lt;br /&gt;
          blessingBonus = calcBlessingBonus(constants.skillPowerTable, victim);&lt;br /&gt;
        } else if (isRangeAttacker(attacker)) {&lt;br /&gt;
          missPercentage = victim.arrowBlock;&lt;br /&gt;
          weaponDefense = victim.arrowDefense;&lt;br /&gt;
          averageDamageResistance = victim.averageDamageResistance;&lt;br /&gt;
          blessingBonus = calcBlessingBonus(constants.skillPowerTable, victim);&lt;br /&gt;
        } else if (isMagicAttacker(attacker)) {&lt;br /&gt;
          missPercentage = victim.arrowBlock;&lt;br /&gt;
          skillDamageResistance = victim.skillDamageResistance;&lt;br /&gt;
          magicResistance = victim.magicResistance;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        missPercentage +=&lt;br /&gt;
          victim.meleeArrowBlock -&lt;br /&gt;
          (missPercentage * victim.meleeArrowBlock) / 100;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    typeBonus = 1;&lt;br /&gt;
    damageMultiplier = attacker.damageMultiplier;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillType) {&lt;br /&gt;
    criticalHitPercentage = skillChanceReduction(criticalHitPercentage);&lt;br /&gt;
    piercingHitPercentage = skillChanceReduction(piercingHitPercentage);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (isPC(victim)) {&lt;br /&gt;
    if (!skillType &amp;amp;&amp;amp; isChecked(victim.biologist70)) {&lt;br /&gt;
      defenseBoost = Math.floor((defenseBoost * 110) / 100);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    criticalHitPercentage = Math.max(&lt;br /&gt;
      0,&lt;br /&gt;
      criticalHitPercentage - victim.criticalHitResistance&lt;br /&gt;
    );&lt;br /&gt;
    piercingHitPercentage = Math.max(&lt;br /&gt;
      0,&lt;br /&gt;
      piercingHitPercentage - victim.piercingHitResistance&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    if (skillType) {&lt;br /&gt;
      skillDamageResistance = victim.skillDamageResistance;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isMagicClass(victim)) {&lt;br /&gt;
      defensePercent = (-2 * victim.magicDefense * victim.defensePercent) / 100;&lt;br /&gt;
    } else {&lt;br /&gt;
      defensePercent = (-2 * defenseBoost * victim.defensePercent) / 100;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isChecked(victim.steelDragonElixir)) {&lt;br /&gt;
      steelDragonElixir = 10;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillType === &amp;quot;magic&amp;quot;) {&lt;br /&gt;
    attackValueMeleeMagic = 0;&lt;br /&gt;
    magicAttackValueMeleeMagic =&lt;br /&gt;
      attacker.attackMagic + Math.min(100, attacker.attackMeleeMagic);&lt;br /&gt;
    attackValueMarriage = 0;&lt;br /&gt;
    defense = 0;&lt;br /&gt;
    if (isDispell(attacker, 6)) {&lt;br /&gt;
      typeBonus = 0;&lt;br /&gt;
      raceBonus = 0;&lt;br /&gt;
      raceResistance = 0;&lt;br /&gt;
      stoneBonus = 0;&lt;br /&gt;
      monsterBonus = 0;&lt;br /&gt;
      for (var index = 0; index &amp;lt; elementBonus.length; index++) {&lt;br /&gt;
        elementBonus[index] = 0;&lt;br /&gt;
      }&lt;br /&gt;
    } else {&lt;br /&gt;
      magicResistance = victim.magicResistance;&lt;br /&gt;
    }&lt;br /&gt;
    weaponDefense = 0;&lt;br /&gt;
    calcAttackValues = calcMagicAttackValue;&lt;br /&gt;
  } else {&lt;br /&gt;
    calcAttackValues = calcSecondaryAttackValue;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  missPercentage = Math.min(100, missPercentage);&lt;br /&gt;
&lt;br /&gt;
  var bonusValues = {&lt;br /&gt;
    missPercentage: missPercentage,&lt;br /&gt;
    weaponBonusCoeff: 1,&lt;br /&gt;
    attackValueCoeff: 100 + attackValueMeleeMagic,&lt;br /&gt;
    attackValueMarriage: attackValueMarriage,&lt;br /&gt;
    monsterResistanceMarriageCoeff: 100 - monsterResistanceMarriage,&lt;br /&gt;
    monsterResistanceCoeff: 100 - monsterResistance,&lt;br /&gt;
    typeBonusCoeff: typeBonus,&lt;br /&gt;
    raceBonusCoeff: raceBonus,&lt;br /&gt;
    raceResistanceCoeff: raceResistance,&lt;br /&gt;
    stoneBonusCoeff: stoneBonus,&lt;br /&gt;
    monsterBonusCoeff: monsterBonus,&lt;br /&gt;
    elementBonusCoeff: elementBonus,&lt;br /&gt;
    damageMultiplier: damageMultiplier,&lt;br /&gt;
    useDamages: useDamages,&lt;br /&gt;
    defense: defense,&lt;br /&gt;
    defenseBoost: defenseBoost,&lt;br /&gt;
    defenseMarriage: defenseMarriage,&lt;br /&gt;
    tigerStrengthCoeff: 100 + tigerStrength,&lt;br /&gt;
    magicResistanceCoeff: magicResistanceToCoeff(magicResistance),&lt;br /&gt;
    weaponDefenseCoeff: 100 - weaponDefense,&lt;br /&gt;
    blessingBonusCoeff: 100 - blessingBonus,&lt;br /&gt;
    magicAttackValueCoeff: 100 + magicAttackValueMeleeMagic,&lt;br /&gt;
    extraPiercingHitCoeff: 5 * extraPiercingHitPercentage,&lt;br /&gt;
    averageDamageCoeff: 100 + averageDamage,&lt;br /&gt;
    averageDamageResistanceCoeff: 100 - Math.min(99, averageDamageResistance),&lt;br /&gt;
    skillDamageCoeff: 100 + skillDamage,&lt;br /&gt;
    skillDamageResistanceCoeff: 100 - Math.min(99, skillDamageResistance),&lt;br /&gt;
    rankBonusCoeff: 100 + rankBonus,&lt;br /&gt;
    defensePercent: Math.floor(defensePercent),&lt;br /&gt;
    damageBonusCoeff: damageBonus,&lt;br /&gt;
    empireMalusCoeff: 10 - empireMalus,&lt;br /&gt;
    sungMaStrBonusCoeff: 10000 + sungMaStrBonus,&lt;br /&gt;
    sungmaStrMalusCoeff: sungmaStrMalus,&lt;br /&gt;
    whiteDragonElixirCoeff: 100 + whiteDragonElixir,&lt;br /&gt;
    steelDragonElixirCoeff: 100 - steelDragonElixir,&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  criticalHitPercentage = Math.min(criticalHitPercentage, 100);&lt;br /&gt;
  piercingHitPercentage = Math.min(piercingHitPercentage, 100);&lt;br /&gt;
&lt;br /&gt;
  var damagesTypeCombinaison = [&lt;br /&gt;
    {&lt;br /&gt;
      criticalHit: false,&lt;br /&gt;
      piercingHit: false,&lt;br /&gt;
      weight:&lt;br /&gt;
        (100 - criticalHitPercentage) *&lt;br /&gt;
        (100 - piercingHitPercentage) *&lt;br /&gt;
        (100 - missPercentage),&lt;br /&gt;
      name: &amp;quot;normalHit&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      criticalHit: true,&lt;br /&gt;
      piercingHit: false,&lt;br /&gt;
      weight:&lt;br /&gt;
        criticalHitPercentage *&lt;br /&gt;
        (100 - piercingHitPercentage) *&lt;br /&gt;
        (100 - missPercentage),&lt;br /&gt;
      name: &amp;quot;criticalHit&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      criticalHit: false,&lt;br /&gt;
      piercingHit: true,&lt;br /&gt;
      weight:&lt;br /&gt;
        (100 - criticalHitPercentage) *&lt;br /&gt;
        piercingHitPercentage *&lt;br /&gt;
        (100 - missPercentage),&lt;br /&gt;
      name: &amp;quot;piercingHit&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      criticalHit: true,&lt;br /&gt;
      piercingHit: true,&lt;br /&gt;
      weight:&lt;br /&gt;
        criticalHitPercentage * piercingHitPercentage * (100 - missPercentage),&lt;br /&gt;
      name: &amp;quot;criticalPiercingHit&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
  ];&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    attacker: attacker,&lt;br /&gt;
    victim: victim,&lt;br /&gt;
    attackFactor: calcAttackFactor(attacker, victim),&lt;br /&gt;
    mainAttackValue: calcMainAttackValue(attacker),&lt;br /&gt;
    attackValues: calcAttackValues(attacker),&lt;br /&gt;
    bonusValues: bonusValues,&lt;br /&gt;
    damagesTypeCombinaison: damagesTypeCombinaison,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateBattleValues(battleValues, skillFormula, skillInfo) {&lt;br /&gt;
  var weaponBonus = 0;&lt;br /&gt;
  var skillWard = 0;&lt;br /&gt;
  var skillBonus = 0;&lt;br /&gt;
  var skillBonusByBonus = 0;&lt;br /&gt;
  var { attacker: attacker, bonusValues: bonusValues } = battleValues;&lt;br /&gt;
  var {&lt;br /&gt;
    range: [minVariation, maxVariation],&lt;br /&gt;
  } = skillInfo;&lt;br /&gt;
  var variationLength = maxVariation - minVariation + 1;&lt;br /&gt;
&lt;br /&gt;
  if (skillInfo.hasOwnProperty(&amp;quot;weaponBonus&amp;quot;)) {&lt;br /&gt;
    var [weaponType, weaponBonusValue] = skillInfo.weaponBonus;&lt;br /&gt;
&lt;br /&gt;
    if (weaponType === attacker.weapon.type) {&lt;br /&gt;
      weaponBonus = weaponBonusValue;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillInfo.skillBonus) {&lt;br /&gt;
    skillBonus = skillInfo.skillBonus;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillInfo.skillWard) {&lt;br /&gt;
    skillWard = skillInfo.skillWard;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillInfo.skillBonusByBonus) {&lt;br /&gt;
    skillBonusByBonus = skillInfo.skillBonusByBonus;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillInfo.removeWeaponReduction) {&lt;br /&gt;
    bonusValues.weaponDefenseCoeff = 100;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  bonusValues.weaponBonusCoeff = 100 + weaponBonus;&lt;br /&gt;
  bonusValues.skillWardCoeff = 1 - skillWard / 100;&lt;br /&gt;
  bonusValues.skillBonusCoeff = 1 + skillBonus / 100;&lt;br /&gt;
  bonusValues.skillBonusByBonusCoeff = 100 + skillBonusByBonus;&lt;br /&gt;
&lt;br /&gt;
  battleValues.skillFormula = skillFormula;&lt;br /&gt;
  battleValues.skillRange = skillInfo.range;&lt;br /&gt;
  battleValues.attackValues.totalCardinal *= variationLength;&lt;br /&gt;
  battleValues.attackValues.possibleDamagesCount *= variationLength;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcWeights(minValue, maxValue, minInterval) {&lt;br /&gt;
  var firstWeightLimit = minValue + minInterval - 1;&lt;br /&gt;
  var lastWeightsLimit = maxValue - minInterval + 1;&lt;br /&gt;
  var weights = [];&lt;br /&gt;
&lt;br /&gt;
  for (var value = minValue; value &amp;lt; firstWeightLimit; value++) {&lt;br /&gt;
    weights.push(value - minValue + 1);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (var value = firstWeightLimit; value &amp;lt;= lastWeightsLimit; value++) {&lt;br /&gt;
    weights.push(minInterval);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (var value = lastWeightsLimit + 1; value &amp;lt;= maxValue; value++) {&lt;br /&gt;
    weights.push(maxValue - value + 1);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return weights;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcBlessingBonus(skillPowerTable, victim) {&lt;br /&gt;
  if (!isChecked(victim.isBlessed)) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var int = victim.intBlessing;&lt;br /&gt;
  var dex = victim.dexBlessing;&lt;br /&gt;
  var skillPower = getSkillPower(victim[&amp;quot;skillBlessing&amp;quot;], skillPowerTable);&lt;br /&gt;
&lt;br /&gt;
  if (!skillPower) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var blessingBonus = floorMultiplication(&lt;br /&gt;
    ((int * 0.3 + 5) * (2 * skillPower + 0.5) + 0.3 * dex) / (skillPower + 2.3),&lt;br /&gt;
    1&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  if (victim.class === &amp;quot;dragon&amp;quot; &amp;amp;&amp;amp; isChecked(ictim.blessingOnself)) {&lt;br /&gt;
    blessingBonus = floorMultiplication(blessingBonus, 1.1);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return blessingBonus;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSkillFormula(battle, skillId, battleValues, removeSkillVariation) {&lt;br /&gt;
  var { attacker, victim, attackFactor } = battleValues;&lt;br /&gt;
  var skillPowerTable = battle.constants.skillPowerTable;&lt;br /&gt;
&lt;br /&gt;
  var skillFormula;&lt;br /&gt;
  var skillInfo = { range: [0, 0] };&lt;br /&gt;
&lt;br /&gt;
  var { class: attackerClass, level: lv, vit, str, int, dex } = attacker;&lt;br /&gt;
&lt;br /&gt;
  if (skillId &amp;lt;= 9) {&lt;br /&gt;
    var skillPower = getSkillPower(&lt;br /&gt;
      attacker[&amp;quot;attackSkill&amp;quot; + skillId],&lt;br /&gt;
      skillPowerTable&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    var improvedBySkillBonus = false;&lt;br /&gt;
    var improvedByBonus = false;&lt;br /&gt;
&lt;br /&gt;
    if (attackerClass === &amp;quot;body&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Triple lacération&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.1 * atk + (0.5 * atk + 1.5 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Moulinet à l'épée&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              3 * atk + (0.8 * atk + 5 * str + 3 * dex + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Accélération&lt;br /&gt;
        case 5:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * atk + (atk + dex * 3 + str * 7 + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Volonté de vivre&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              (3 * atk + (atk + 1.5 * str) * skillPower) * 1.07,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          break;&lt;br /&gt;
        // Tremblement de terre&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              3 * atk +&lt;br /&gt;
                (0.9 * atk + variation + 5 * str + 3 * dex + lv) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;mental&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Attaque de l'esprit&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2.3 * atk + (4 * atk + 4 * str + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Attaque de la paume&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2.3 * atk + (3 * atk + 4 * str + 3 * vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Charge&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * atk + (2 * atk + 2 * dex + 2 * vit + 4 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          break;&lt;br /&gt;
        // Coup d'épée&lt;br /&gt;
        case 5:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * atk + (atk + 3 * dex + 5 * str + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Orbe de l'épée&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              (2 * atk + (2 * atk + 2 * dex + 2 * vit + 4 * str) * skillPower) *&lt;br /&gt;
                1.1,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          break;&lt;br /&gt;
        // Tremblement de terre&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              3 * atk +&lt;br /&gt;
                (0.9 * atk + variation + 5 * str + 3 * dex + lv) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;blade_fight&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Embuscade&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk + (1.2 * atk + variation + 4 * dex + 4 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [1, 50];&lt;br /&gt;
          skillInfo.range = [500, 700];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Attaque rapide&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk + (1.6 * atk + variation + 7 * dex + 7 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [1, 35];&lt;br /&gt;
          skillInfo.range = [200, 300];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Dague filante&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * atk + (0.5 * atk + 9 * dex + 7 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Brume empoisonnée&lt;br /&gt;
        case 5:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * lv + (atk + 3 * str + 18 * dex) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Poison insidieux&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              (2 * lv + (atk + 3 * str + 18 * dex) * skillPower) * 1.1,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          break;&lt;br /&gt;
        // Étoiles brillantes&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk + (1.7 * atk + variation + 6 * dex + 5 * lv) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;archery&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Tir à répétition&lt;br /&gt;
        // case 1:&lt;br /&gt;
        //   skillFormula = function (atk) {&lt;br /&gt;
        //     return floorMultiplication(&lt;br /&gt;
        //       atk + 0.2 * atk * Math.floor(2 + 6 * skillPower) + (0.8 * atk + 8 * dex * attackFactor + 2 * int) * skillPower,&lt;br /&gt;
        //       1&lt;br /&gt;
        //     );&lt;br /&gt;
        //   };&lt;br /&gt;
        //   improvedByBonus = true;&lt;br /&gt;
        //   break;&lt;br /&gt;
        // Pluie de flèches&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk + (1.7 * atk + 5 * dex + str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Flèche de feu&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.5 * atk + (2.6 * atk + 0.9 * int + variation) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [100, 300];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Foulée de plume&lt;br /&gt;
        case 4:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              (3 * dex + 200 + 2 * str + 2 * int) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.removeWeaponReduction = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Flèche empoisonnée&lt;br /&gt;
        case 5:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk +&lt;br /&gt;
                (1.4 * atk + variation + 7 * dex + 4 * str + 4 * int) *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [100, 200];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Coup étincelant&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              (atk +&lt;br /&gt;
                (1.2 * atk + variation + 6 * dex + 3 * str + 3 * int) *&lt;br /&gt;
                  skillPower) *&lt;br /&gt;
                1.2,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [100, 200];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Tir tempête&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.9 * atk + (2.6 * atk + variation) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;weaponary&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Toucher brûlant&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk +&lt;br /&gt;
                2 * lv +&lt;br /&gt;
                2 * int +&lt;br /&gt;
                (2 * atk + 4 * str + 14 * int) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Tourbillon du dragon&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.1 * atk +&lt;br /&gt;
                2 * lv +&lt;br /&gt;
                2 * int +&lt;br /&gt;
                (1.5 * atk + str + 12 * int) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Contre-sort&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              40 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                2 * int +&lt;br /&gt;
                (10 * int + 7 * mav + variation) * attackFactor * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [50, 100];&lt;br /&gt;
          break;&lt;br /&gt;
        // Coup démoniaque&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.9 * atk + (2.6 * atk + variation) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;black_magic&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Attaque des ténèbres&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              40 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                2 * int +&lt;br /&gt;
                (13 * int + 6 * mav + variation) * attackFactor * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [50, 100];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Attaque de flammes&lt;br /&gt;
        // case 2:&lt;br /&gt;
        //   skillFormula = function (mav, variation) {&lt;br /&gt;
        //     return floorMultiplication(&lt;br /&gt;
        //       5 * lv + 2 * int + (7 * int + 8 * mav + 4 * str + 2 * vit + variation) * skillPower,&lt;br /&gt;
        //       1&lt;br /&gt;
        //     );&lt;br /&gt;
        //   };&lt;br /&gt;
        //   skillInfo.range = [180, 100];&lt;br /&gt;
        //   improvedByBonus = true;&lt;br /&gt;
        //   break;&lt;br /&gt;
        // Esprit de flammes&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              30 +&lt;br /&gt;
                2 * lv +&lt;br /&gt;
                2 * int +&lt;br /&gt;
                (7 * int + 6 * mav + variation) * attackFactor * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [200, 500];&lt;br /&gt;
          break;&lt;br /&gt;
        // Frappe de l'esprit&lt;br /&gt;
        // case 5:&lt;br /&gt;
        //   skillFormula = function (mav, variation) {&lt;br /&gt;
        //     return floorMultiplication(&lt;br /&gt;
        //       40 + 2 * lv + 2 * int + (2 * vit + 2 * dex + 13 * int + 6 * mav + variation) * attackFactor * skillPower,&lt;br /&gt;
        //       1&lt;br /&gt;
        //     );&lt;br /&gt;
        //   };&lt;br /&gt;
        //   skillInfo.range = [180, 200];&lt;br /&gt;
        //   break;&lt;br /&gt;
        // Orbe des ténèbres&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (mav) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              120 +&lt;br /&gt;
                6 * lv +&lt;br /&gt;
                (5 * vit + 5 * dex + 29 * int + 9 * mav) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Vague mortelle&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              120 +&lt;br /&gt;
                6 * lv +&lt;br /&gt;
                (5 * vit + 5 * dex + 30 * int + variation + 9 * mav) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;dragon&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Talisman volant&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (mav) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              70 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                (18 * int + 7 * str + 5 * mav + 50) * attackFactor * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [4, 10];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Dragon chassant&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (mav) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              60 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                (16 * int + 6 * dex + 6 * mav + 120) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [4, 10];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Rugissement du dragon&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (mav) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              70 +&lt;br /&gt;
                3 * lv +&lt;br /&gt;
                (20 * int + 3 * str + 10 * mav + 100) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [4, 10];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Météore&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              120 +&lt;br /&gt;
                6 * lv +&lt;br /&gt;
                (5 * vit + 5 * dex + 30 * int + variation + 9 * mav) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;heal&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Jet de foudre&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              60 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                (8 * int + 2 * dex + 8 * mav + variation) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [6, 10];&lt;br /&gt;
          skillInfo.range = [5 * int, 15 * int];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Invocation de foudre&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              40 +&lt;br /&gt;
                4 * lv +&lt;br /&gt;
                (13 * int + 2 * str + 10 * mav + variation) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [6, 10];&lt;br /&gt;
          skillInfo.range = [5 * int, 16 * int];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Griffe de foudre&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              50 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                (8 * int + 2 * str + 8 * mav + variation) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 800];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;lycan&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Déchiqueter&lt;br /&gt;
        // case 1:&lt;br /&gt;
        //   skillFormula = function (atk) {&lt;br /&gt;
        //     return floorMultiplication(&lt;br /&gt;
        //       1.1 * atk + (0.3 * atk + 1.5 * str) * skillPower,&lt;br /&gt;
        //       1&lt;br /&gt;
        //     );&lt;br /&gt;
        //   };&lt;br /&gt;
        //   skillInfo.weaponBonus = [5, 54];&lt;br /&gt;
        //   improvedByBonus = true;&lt;br /&gt;
        //   break;&lt;br /&gt;
        // Souffle de loup&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * atk + (atk + 3 * dex + 5 * str + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [5, 35];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Bond de loup&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk + (1.6 * atk + 200 + 7 * dex + 7 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [5, 35];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Griffe de loup&lt;br /&gt;
        case 4:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              3 * atk + (0.8 * atk + 6 * str + 2 * dex + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Tempête cinglante&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.8 * atk +&lt;br /&gt;
                (atk + 6 * dex + variation + 3 * str + lv) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
    if (improvedBySkillBonus) {&lt;br /&gt;
      skillInfo.skillBonus =&lt;br /&gt;
        16 * getSkillPower(attacker.skillBonus, skillPowerTable);&lt;br /&gt;
&lt;br /&gt;
      var skillWardChoice = victim.skillWardChoice;&lt;br /&gt;
&lt;br /&gt;
      if (skillWardChoice &amp;amp;&amp;amp; skillWardChoice === attackerClass) {&lt;br /&gt;
        skillInfo.skillWard =&lt;br /&gt;
          24 * getSkillPower(victim.skillWard, skillPowerTable);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (improvedByBonus) {&lt;br /&gt;
      skillInfo.skillBonusByBonus = attacker[&amp;quot;skillBonus&amp;quot; + skillId];&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (removeSkillVariation) {&lt;br /&gt;
      var averageVariation = (skillInfo.range[0] + skillInfo.range[0]) / 2;&lt;br /&gt;
      skillInfo.range = [averageVariation, averageVariation];&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    var skillPower = getSkillPower(&lt;br /&gt;
      attacker[&amp;quot;horseSkill&amp;quot; + skillId],&lt;br /&gt;
      skillPowerTable&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    switch (skillId) {&lt;br /&gt;
      // Combat équestre&lt;br /&gt;
      case 137:&lt;br /&gt;
        skillFormula = function (atk) {&lt;br /&gt;
          return floorMultiplication(atk + 2 * atk * skillPower, 1);&lt;br /&gt;
        };&lt;br /&gt;
        break;&lt;br /&gt;
      // Charge à cheval&lt;br /&gt;
      case 138:&lt;br /&gt;
        skillFormula = function (atk) {&lt;br /&gt;
          return floorMultiplication(&lt;br /&gt;
            2.4 * (200 + 1.5 * lv) + 600 * skillPower,&lt;br /&gt;
            1&lt;br /&gt;
          );&lt;br /&gt;
        };&lt;br /&gt;
        break;&lt;br /&gt;
      // Vague de Pouvoir&lt;br /&gt;
      case 139:&lt;br /&gt;
        skillFormula = function (atk) {&lt;br /&gt;
          return floorMultiplication(&lt;br /&gt;
            2 * (200 + 1.5 * lv) + 600 * skillPower,&lt;br /&gt;
            1&lt;br /&gt;
          );&lt;br /&gt;
        };&lt;br /&gt;
        break;&lt;br /&gt;
      // Grêle de flèches&lt;br /&gt;
      case 140:&lt;br /&gt;
        skillFormula = function (atk) {&lt;br /&gt;
          return floorMultiplication(atk + 2 * atk * skillPower, 1);&lt;br /&gt;
        };&lt;br /&gt;
        break;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  updateBattleValues(battleValues, skillFormula, skillInfo);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcMagicAttackValueAugmentation(&lt;br /&gt;
  magicAttackValueWeapon,&lt;br /&gt;
  magicAttackValueBonus&lt;br /&gt;
) {&lt;br /&gt;
  if (magicAttackValueBonus) {&lt;br /&gt;
    return Math.max(&lt;br /&gt;
      1,&lt;br /&gt;
      0.0025056 *&lt;br /&gt;
        magicAttackValueBonus ** 0.602338 *&lt;br /&gt;
        magicAttackValueWeapon ** 1.20476&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
  return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getMagicAttackValueAugmentation(&lt;br /&gt;
  minMagicAttackValue,&lt;br /&gt;
  maxMagicAttackValue,&lt;br /&gt;
  magicAttackValueBonus&lt;br /&gt;
) {&lt;br /&gt;
  var magicAttackValueAugmentation = [];&lt;br /&gt;
&lt;br /&gt;
  for (&lt;br /&gt;
    var magicAttackValue = minMagicAttackValue;&lt;br /&gt;
    magicAttackValue &amp;lt;= maxMagicAttackValue;&lt;br /&gt;
    magicAttackValue++&lt;br /&gt;
  ) {&lt;br /&gt;
    magicAttackValueAugmentation.push(&lt;br /&gt;
      calcMagicAttackValueAugmentation(magicAttackValue, magicAttackValueBonus)&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return magicAttackValueAugmentation;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcPhysicalDamages(battleValues) {&lt;br /&gt;
  var {&lt;br /&gt;
    attackFactor,&lt;br /&gt;
    mainAttackValue,&lt;br /&gt;
    attackValues: { minAttackValue, maxAttackValue, attackValueOther, weights },&lt;br /&gt;
    bonusValues,&lt;br /&gt;
    damagesTypeCombinaison,&lt;br /&gt;
  } = battleValues;&lt;br /&gt;
&lt;br /&gt;
  var damagesWeightedByType = {};&lt;br /&gt;
&lt;br /&gt;
  if (bonusValues.missPercentage) {&lt;br /&gt;
    damagesWeightedByType.miss = bonusValues.missPercentage / 100;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (var damagesType of damagesTypeCombinaison) {&lt;br /&gt;
    if (!damagesType.weight) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var damagesWeighted = {};&lt;br /&gt;
    damagesWeightedByType[damagesType.name] = damagesWeighted;&lt;br /&gt;
&lt;br /&gt;
    for (&lt;br /&gt;
      var attackValue = minAttackValue;&lt;br /&gt;
      attackValue &amp;lt;= maxAttackValue;&lt;br /&gt;
      attackValue++&lt;br /&gt;
    ) {&lt;br /&gt;
      var weight = weights[attackValue - minAttackValue] * damagesType.weight;&lt;br /&gt;
&lt;br /&gt;
      var secondaryAttackValue = 2 * attackValue + attackValueOther;&lt;br /&gt;
      var rawDamages =&lt;br /&gt;
        mainAttackValue +&lt;br /&gt;
        floorMultiplication(attackFactor, secondaryAttackValue);&lt;br /&gt;
&lt;br /&gt;
      var damagesWithPrimaryBonuses = calcDamageWithPrimaryBonuses(&lt;br /&gt;
        rawDamages,&lt;br /&gt;
        bonusValues&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      var minPiercingDamages =&lt;br /&gt;
        damagesWithPrimaryBonuses -&lt;br /&gt;
        bonusValues.defenseBoost +&lt;br /&gt;
        bonusValues.defenseMarriage;&lt;br /&gt;
&lt;br /&gt;
      if (minPiercingDamages &amp;lt;= 2) {&lt;br /&gt;
        for (var damages = 1; damages &amp;lt;= 5; damages++) {&lt;br /&gt;
          var finalDamages = calcDamageWithSecondaryBonuses(&lt;br /&gt;
            damages,&lt;br /&gt;
            bonusValues,&lt;br /&gt;
            damagesType,&lt;br /&gt;
            minPiercingDamages,&lt;br /&gt;
            damagesWithPrimaryBonuses&lt;br /&gt;
          );&lt;br /&gt;
&lt;br /&gt;
          addKeyValue(damagesWeighted, finalDamages, weight / 5);&lt;br /&gt;
        }&lt;br /&gt;
      } else {&lt;br /&gt;
        var finalDamages = calcDamageWithSecondaryBonuses(&lt;br /&gt;
          minPiercingDamages,&lt;br /&gt;
          bonusValues,&lt;br /&gt;
          damagesType,&lt;br /&gt;
          minPiercingDamages,&lt;br /&gt;
          damagesWithPrimaryBonuses&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        addKeyValue(damagesWeighted, finalDamages, weight);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return damagesWeightedByType;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcPhysicalSkillDamages(battleValues) {&lt;br /&gt;
  var {&lt;br /&gt;
    attackFactor,&lt;br /&gt;
    mainAttackValue,&lt;br /&gt;
    attackValues: { minAttackValue, maxAttackValue, attackValueOther, weights },&lt;br /&gt;
    bonusValues,&lt;br /&gt;
    damagesTypeCombinaison,&lt;br /&gt;
    skillFormula,&lt;br /&gt;
    skillRange: [minVariation, maxVariation],&lt;br /&gt;
  } = battleValues;&lt;br /&gt;
&lt;br /&gt;
  var damagesWeightedByType = {};&lt;br /&gt;
&lt;br /&gt;
  for (var damagesType of damagesTypeCombinaison) {&lt;br /&gt;
    if (!damagesType.weight) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var damagesWeighted = {};&lt;br /&gt;
    var savedDamages = {};&lt;br /&gt;
&lt;br /&gt;
    damagesWeightedByType[damagesType.name] = damagesWeighted;&lt;br /&gt;
&lt;br /&gt;
    for (&lt;br /&gt;
      var attackValue = minAttackValue;&lt;br /&gt;
      attackValue &amp;lt;= maxAttackValue;&lt;br /&gt;
      attackValue++&lt;br /&gt;
    ) {&lt;br /&gt;
      var weight = weights[attackValue - minAttackValue] * damagesType.weight;&lt;br /&gt;
&lt;br /&gt;
      var secondaryAttackValue = 2 * attackValue + attackValueOther;&lt;br /&gt;
      var rawDamages =&lt;br /&gt;
        mainAttackValue +&lt;br /&gt;
        floorMultiplication(attackFactor, secondaryAttackValue);&lt;br /&gt;
&lt;br /&gt;
      var damagesWithPrimaryBonuses = calcDamageWithPrimaryBonuses(&lt;br /&gt;
        rawDamages,&lt;br /&gt;
        bonusValues&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      for (&lt;br /&gt;
        var variation = minVariation;&lt;br /&gt;
        variation &amp;lt;= maxVariation;&lt;br /&gt;
        variation++&lt;br /&gt;
      ) {&lt;br /&gt;
        if (damagesWithPrimaryBonuses &amp;lt;= 2) {&lt;br /&gt;
          for (var damages = 1; damages &amp;lt;= 5; damages++) {&lt;br /&gt;
            damages *= bonusValues.useDamages;&lt;br /&gt;
&lt;br /&gt;
            var damagesWithFormula = skillFormula(damages, variation);&lt;br /&gt;
&lt;br /&gt;
            damagesWithFormula = Math.floor(&lt;br /&gt;
              (damagesWithFormula * bonusValues.weaponBonusCoeff) / 100&lt;br /&gt;
            );&lt;br /&gt;
&lt;br /&gt;
            var finalDamages = calcSkillDamageWithSecondaryBonuses(&lt;br /&gt;
              damagesWithFormula,&lt;br /&gt;
              bonusValues,&lt;br /&gt;
              damagesType,&lt;br /&gt;
              damagesWithPrimaryBonuses&lt;br /&gt;
            );&lt;br /&gt;
&lt;br /&gt;
            addKeyValue(damagesWeighted, finalDamages, weight / 5);&lt;br /&gt;
          }&lt;br /&gt;
        } else {&lt;br /&gt;
          damagesWithPrimaryBonuses *= bonusValues.useDamages;&lt;br /&gt;
&lt;br /&gt;
          var damagesWithFormula = skillFormula(&lt;br /&gt;
            damagesWithPrimaryBonuses,&lt;br /&gt;
            variation&lt;br /&gt;
          );&lt;br /&gt;
&lt;br /&gt;
          if (savedDamages.hasOwnProperty(damagesWithFormula)) {&lt;br /&gt;
            var finalDamages = savedDamages[damagesWithFormula];&lt;br /&gt;
            damagesWeighted[finalDamages] += weight;&lt;br /&gt;
            continue;&lt;br /&gt;
          }&lt;br /&gt;
&lt;br /&gt;
          var finalDamages = Math.floor(&lt;br /&gt;
            (damagesWithFormula * bonusValues.weaponBonusCoeff) / 100&lt;br /&gt;
          );&lt;br /&gt;
&lt;br /&gt;
          finalDamages = calcSkillDamageWithSecondaryBonuses(&lt;br /&gt;
            finalDamages,&lt;br /&gt;
            bonusValues,&lt;br /&gt;
            damagesType,&lt;br /&gt;
            damagesWithPrimaryBonuses&lt;br /&gt;
          );&lt;br /&gt;
&lt;br /&gt;
          savedDamages[damagesWithFormula] = finalDamages;&lt;br /&gt;
          addKeyValue(damagesWeighted, finalDamages, weight);&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return damagesWeightedByType;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcMagicSkillDamages(battleValues) {&lt;br /&gt;
  var {&lt;br /&gt;
    attackValues: {&lt;br /&gt;
      minMagicAttackValue,&lt;br /&gt;
      maxMagicAttackValue,&lt;br /&gt;
      magicAttackValueAugmentation,&lt;br /&gt;
      weights,&lt;br /&gt;
    },&lt;br /&gt;
    bonusValues,&lt;br /&gt;
    damagesTypeCombinaison,&lt;br /&gt;
    skillFormula,&lt;br /&gt;
    skillRange: [minVariation, maxVariation],&lt;br /&gt;
  } = battleValues;&lt;br /&gt;
&lt;br /&gt;
  var damagesWeightedByType = {};&lt;br /&gt;
&lt;br /&gt;
  for (var damagesType of damagesTypeCombinaison) {&lt;br /&gt;
    if (!damagesType.weight) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var damagesWeighted = {};&lt;br /&gt;
    var savedDamages = {};&lt;br /&gt;
&lt;br /&gt;
    damagesWeightedByType[damagesType.name] = damagesWeighted;&lt;br /&gt;
&lt;br /&gt;
    for (&lt;br /&gt;
      var magicAttackValue = minMagicAttackValue;&lt;br /&gt;
      magicAttackValue &amp;lt;= maxMagicAttackValue;&lt;br /&gt;
      magicAttackValue++&lt;br /&gt;
    ) {&lt;br /&gt;
      var index = magicAttackValue - minMagicAttackValue;&lt;br /&gt;
      var weight = weights[index] * damagesType.weight;&lt;br /&gt;
&lt;br /&gt;
      for (&lt;br /&gt;
        var variation = minVariation;&lt;br /&gt;
        variation &amp;lt;= maxVariation;&lt;br /&gt;
        variation++&lt;br /&gt;
      ) {&lt;br /&gt;
        var rawDamages = skillFormula(&lt;br /&gt;
          magicAttackValue + magicAttackValueAugmentation[index],&lt;br /&gt;
          variation&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        if (savedDamages.hasOwnProperty(rawDamages)) {&lt;br /&gt;
          var finalDamages = savedDamages[rawDamages];&lt;br /&gt;
          damagesWeighted[finalDamages] += weight;&lt;br /&gt;
          continue;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var damagesWithPrimaryBonuses = Math.floor(&lt;br /&gt;
          (rawDamages * bonusValues.weaponBonusCoeff) / 100&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        damagesWithPrimaryBonuses = calcDamageWithPrimaryBonuses(&lt;br /&gt;
          damagesWithPrimaryBonuses,&lt;br /&gt;
          bonusValues&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        if (damagesWithPrimaryBonuses &amp;lt;= 2) {&lt;br /&gt;
          for (var damages = 1; damages &amp;lt;= 5; damages++) {&lt;br /&gt;
            var finalDamages = calcSkillDamageWithSecondaryBonuses(&lt;br /&gt;
              damages,&lt;br /&gt;
              bonusValues,&lt;br /&gt;
              damagesType,&lt;br /&gt;
              damagesWithPrimaryBonuses&lt;br /&gt;
            );&lt;br /&gt;
            addKeyValue(damagesWeighted, finalDamages, weight / 5);&lt;br /&gt;
          }&lt;br /&gt;
        } else {&lt;br /&gt;
          var finalDamages = calcSkillDamageWithSecondaryBonuses(&lt;br /&gt;
            damagesWithPrimaryBonuses,&lt;br /&gt;
            bonusValues,&lt;br /&gt;
            damagesType,&lt;br /&gt;
            damagesWithPrimaryBonuses&lt;br /&gt;
          );&lt;br /&gt;
&lt;br /&gt;
          savedDamages[rawDamages] = finalDamages;&lt;br /&gt;
          addKeyValue(damagesWeighted, finalDamages, weight);&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return damagesWeightedByType;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcDamages(&lt;br /&gt;
  attacker,&lt;br /&gt;
  victim,&lt;br /&gt;
  attackType,&lt;br /&gt;
  battle,&lt;br /&gt;
  removeSkillVariation&lt;br /&gt;
) {&lt;br /&gt;
  var damagesCalculator, skillId, skillType;&lt;br /&gt;
&lt;br /&gt;
  if (attackType === &amp;quot;physical&amp;quot;) {&lt;br /&gt;
    damagesCalculator = calcPhysicalDamages;&lt;br /&gt;
  } else if (attackType.startsWith(&amp;quot;attackSkill&amp;quot;)) {&lt;br /&gt;
    skillId = Number(attackType.split(&amp;quot;attackSkill&amp;quot;)[1]);&lt;br /&gt;
&lt;br /&gt;
    if (isMagicClass(attacker) || isDispell(attacker, skillId)) {&lt;br /&gt;
      skillType = &amp;quot;magic&amp;quot;;&lt;br /&gt;
      damagesCalculator = calcMagicSkillDamages;&lt;br /&gt;
    } else {&lt;br /&gt;
      skillType = &amp;quot;physical&amp;quot;;&lt;br /&gt;
      damagesCalculator = calcPhysicalSkillDamages;&lt;br /&gt;
    }&lt;br /&gt;
  } else if (attackType.startsWith(&amp;quot;horseSkill&amp;quot;)) {&lt;br /&gt;
    skillType = &amp;quot;physical&amp;quot;;&lt;br /&gt;
    skillId = Number(attackType.split(&amp;quot;horseSkill&amp;quot;)[1]);&lt;br /&gt;
    damagesCalculator = calcPhysicalSkillDamages;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var battleValues = createBattleValues(attacker, victim, battle, skillType);&lt;br /&gt;
&lt;br /&gt;
  if (skillId) {&lt;br /&gt;
    getSkillFormula(battle, skillId, battleValues, removeSkillVariation);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var {&lt;br /&gt;
    attackValues: { totalCardinal, possibleDamagesCount },&lt;br /&gt;
  } = battleValues;&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    damagesWeightedByType: damagesCalculator(battleValues),&lt;br /&gt;
    totalCardinal: totalCardinal,&lt;br /&gt;
    possibleDamagesCount: possibleDamagesCount,&lt;br /&gt;
    skillType: skillType,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function damagesWithoutVariation(&lt;br /&gt;
  attacker,&lt;br /&gt;
  victim,&lt;br /&gt;
  attackType,&lt;br /&gt;
  battle,&lt;br /&gt;
  characters&lt;br /&gt;
) {&lt;br /&gt;
  startDamagesTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
  var {&lt;br /&gt;
    damagesWeightedByType,&lt;br /&gt;
    totalCardinal,&lt;br /&gt;
    possibleDamagesCount,&lt;br /&gt;
    skillType,&lt;br /&gt;
  } = calcDamages(attacker, victim, attackType, battle);&lt;br /&gt;
&lt;br /&gt;
  endDamagesTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
  possibleDamagesCount = displayResults(&lt;br /&gt;
    possibleDamagesCount,&lt;br /&gt;
    totalCardinal,&lt;br /&gt;
    damagesWeightedByType,&lt;br /&gt;
    battle,&lt;br /&gt;
    attacker.name,&lt;br /&gt;
    victim.name&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  endDisplayTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
  displayFightInfo(&lt;br /&gt;
    possibleDamagesCount,&lt;br /&gt;
    endDamagesTime - startDamagesTime,&lt;br /&gt;
    endDisplayTime - endDamagesTime,&lt;br /&gt;
    battle&lt;br /&gt;
  );&lt;br /&gt;
  addPotentialErrorInformation(&lt;br /&gt;
    battle.errorInformation,&lt;br /&gt;
    attacker,&lt;br /&gt;
    victim,&lt;br /&gt;
    skillType,&lt;br /&gt;
    characters&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  hideElement(battle.bonusVariationResultContainer);&lt;br /&gt;
  showElement(battle.fightResultContainer);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function damagesWithVariation(&lt;br /&gt;
  attacker,&lt;br /&gt;
  victim,&lt;br /&gt;
  attackType,&lt;br /&gt;
  battle,&lt;br /&gt;
  entity,&lt;br /&gt;
  entityVariation&lt;br /&gt;
) {&lt;br /&gt;
  startTime = performance.now();&lt;br /&gt;
  var damagesByBonus = [];&lt;br /&gt;
  var augmentationByBonus = [];&lt;br /&gt;
  var {&lt;br /&gt;
    bonusVariationMinValue: minVariation,&lt;br /&gt;
    bonusVariationMaxValue: maxVariation,&lt;br /&gt;
  } = entity;&lt;br /&gt;
  var step = Math.ceil((maxVariation - minVariation + 1) / 500);&lt;br /&gt;
  var simulationCount = 0;&lt;br /&gt;
  var simulationTime;&lt;br /&gt;
&lt;br /&gt;
  for (&lt;br /&gt;
    var bonusValue = minVariation;&lt;br /&gt;
    bonusValue &amp;lt;= maxVariation;&lt;br /&gt;
    bonusValue += step&lt;br /&gt;
  ) {&lt;br /&gt;
    entity[entityVariation] = bonusValue;&lt;br /&gt;
&lt;br /&gt;
    var { damagesWeightedByType, totalCardinal } = calcDamages(&lt;br /&gt;
      copyObject(attacker),&lt;br /&gt;
      copyObject(victim),&lt;br /&gt;
      attackType,&lt;br /&gt;
      battle,&lt;br /&gt;
      true&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    var meanDamages = calcMeanDamages(damagesWeightedByType, totalCardinal);&lt;br /&gt;
&lt;br /&gt;
    if (bonusValue === minVariation) {&lt;br /&gt;
      var firstDamages = Math.max(meanDamages, 1e-3);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    damagesByBonus.push({ x: bonusValue, y: meanDamages });&lt;br /&gt;
    augmentationByBonus.push({&lt;br /&gt;
      x: bonusValue,&lt;br /&gt;
      y: meanDamages / firstDamages - 1,&lt;br /&gt;
    });&lt;br /&gt;
    simulationCount++;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  endTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
  battle.damagesByBonus = damagesByBonus.concat(entityVariation);&lt;br /&gt;
&lt;br /&gt;
  addToBonusVariationChart(&lt;br /&gt;
    damagesByBonus,&lt;br /&gt;
    augmentationByBonus,&lt;br /&gt;
    entity.bonusVariationDisplay,&lt;br /&gt;
    battle.bonusVariationChart&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  simulationCount = battle.numberFormats.default.format(simulationCount);&lt;br /&gt;
  simulationTime = battle.numberFormats.second.format(&lt;br /&gt;
    (endTime - startTime) / 1000&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  battle.simulationCounter.textContent = simulationCount;&lt;br /&gt;
  battle.simulationTime.textContent = simulationTime;&lt;br /&gt;
&lt;br /&gt;
  hideElement(battle.fightResultContainer);&lt;br /&gt;
  showElement(battle.bonusVariationResultContainer);&lt;br /&gt;
&lt;br /&gt;
  if (&lt;br /&gt;
    isChecked(attacker.useBonusVariation) &amp;amp;&amp;amp;&lt;br /&gt;
    isChecked(victim.useBonusVariation)&lt;br /&gt;
  ) {&lt;br /&gt;
    showElement(battle.errorInformation[&amp;quot;attacker-victim-variation&amp;quot;]);&lt;br /&gt;
  } else {&lt;br /&gt;
    hideElement(battle.errorInformation[&amp;quot;attacker-victim-variation&amp;quot;]);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function changeMonsterValues(monster, instance, attacker) {&lt;br /&gt;
  switch (instance) {&lt;br /&gt;
    case &amp;quot;SungMahiTower&amp;quot;:&lt;br /&gt;
      var sungMahiFloor = 1;&lt;br /&gt;
      var sungMahiStep = 1;&lt;br /&gt;
      var rawDefense = 120;&lt;br /&gt;
&lt;br /&gt;
      if (isPC(attacker)) {&lt;br /&gt;
        sungMahiFloor = attacker.sungMahiFloor;&lt;br /&gt;
        sungMahiStep = attacker.sungMahiStep;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (monster.rank === 5) {&lt;br /&gt;
        monster.level = 121;&lt;br /&gt;
        monster.dex = 75;&lt;br /&gt;
        rawDefense += 1;&lt;br /&gt;
      } else if (monster.rank === 6) {&lt;br /&gt;
        monster.level = 123;&lt;br /&gt;
        monster.dex = 75;&lt;br /&gt;
        rawDefense += 1;&lt;br /&gt;
      } else {&lt;br /&gt;
        monster.level = 120;&lt;br /&gt;
        monster.dex = 68;&lt;br /&gt;
      }&lt;br /&gt;
      monster.vit = 100;&lt;br /&gt;
      monster.rawDefense = rawDefense + (sungMahiStep - 1) * 6;&lt;br /&gt;
      monster.fistDefense = 0;&lt;br /&gt;
      monster.swordDefense = 0;&lt;br /&gt;
      monster.twoHandedSwordDefense = 0;&lt;br /&gt;
      monster.daggerDefense = 0;&lt;br /&gt;
      monster.bellDefense = 0;&lt;br /&gt;
      monster.fanDefense = 0;&lt;br /&gt;
      monster.arrowDefense = 0;&lt;br /&gt;
      monster.clawDefense = 0;&lt;br /&gt;
      monster.magicResistance = 0;&lt;br /&gt;
      monster.fireResistance = -20;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  // Alastor&lt;br /&gt;
  if (monster.vnum === 6790) {&lt;br /&gt;
    monster.iceResistance = 0;&lt;br /&gt;
    monster.iceBonus = 0;&lt;br /&gt;
    monster.lightningResistance = -10;&lt;br /&gt;
    monster.lightningBonus = 65;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createWeapon(vnum) {&lt;br /&gt;
  var weapon = copyObject(weaponData[vnum]);&lt;br /&gt;
  var serpentVnums = [360, 380, 1210, 2230, 3250, 5200, 6150, 7330];&lt;br /&gt;
  var weaponValues = weapon[1];&lt;br /&gt;
  var isSerpent = isValueInArray(Number(vnum), serpentVnums);&lt;br /&gt;
  var isSpecial = Array.isArray(weaponValues[0]);&lt;br /&gt;
  var isMagic;&lt;br /&gt;
&lt;br /&gt;
  if (isSpecial) {&lt;br /&gt;
    isMagic = weaponValues[0][1] &amp;gt; 0;&lt;br /&gt;
  } else {&lt;br /&gt;
    isMagic = weaponValues[1] &amp;gt; 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    type: weapon[0],&lt;br /&gt;
    maxUpgrade: weapon[2].length - 1,&lt;br /&gt;
    isSerpent: isSerpent,&lt;br /&gt;
    isMagic: isMagic,&lt;br /&gt;
    getValues: function (upgrade) {&lt;br /&gt;
      var currentWeaponValues = weaponValues;&lt;br /&gt;
&lt;br /&gt;
      if (upgrade === undefined) {&lt;br /&gt;
        // rare bug when weaponUpgrade is deleted&lt;br /&gt;
        console.warn(&amp;quot;WeaponUpgrade is missing.&amp;quot;);&lt;br /&gt;
        upgrade = this.maxUpgrade;&lt;br /&gt;
      }&lt;br /&gt;
      upgrade = Math.min(upgrade, this.maxUpgrade);&lt;br /&gt;
&lt;br /&gt;
      if (isSpecial) {&lt;br /&gt;
        currentWeaponValues = weaponValues[upgrade];&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      this.minAttackValue = currentWeaponValues[2];&lt;br /&gt;
      this.maxAttackValue = currentWeaponValues[3];&lt;br /&gt;
      this.minMagicAttackValue = currentWeaponValues[0];&lt;br /&gt;
      this.maxMagicAttackValue = currentWeaponValues[1];&lt;br /&gt;
      this.growth = weapon[2][upgrade];&lt;br /&gt;
    },&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createMonster(monsterVnum, attacker, polymorphMonster) {&lt;br /&gt;
  var monsterAttributes = monsterData[monsterVnum];&lt;br /&gt;
&lt;br /&gt;
  var monster = {&lt;br /&gt;
    vnum: Number(monsterVnum),&lt;br /&gt;
    name: monsterAttributes[36],&lt;br /&gt;
    rank: monsterAttributes[0],&lt;br /&gt;
    race: monsterAttributes[1],&lt;br /&gt;
    attack: monsterAttributes[2],&lt;br /&gt;
    level: monsterAttributes[3],&lt;br /&gt;
    type: monsterAttributes[4],&lt;br /&gt;
    str: monsterAttributes[5],&lt;br /&gt;
    dex: monsterAttributes[6],&lt;br /&gt;
    vit: monsterAttributes[7],&lt;br /&gt;
    int: monsterAttributes[8],&lt;br /&gt;
    minAttackValue: monsterAttributes[9],&lt;br /&gt;
    maxAttackValue: monsterAttributes[10],&lt;br /&gt;
    rawDefense: monsterAttributes[11],&lt;br /&gt;
    criticalHit: monsterAttributes[12],&lt;br /&gt;
    piercingHit: monsterAttributes[13],&lt;br /&gt;
    fistDefense: monsterAttributes[14],&lt;br /&gt;
    swordDefense: monsterAttributes[15],&lt;br /&gt;
    twoHandedSwordDefense: monsterAttributes[16],&lt;br /&gt;
    daggerDefense: monsterAttributes[17],&lt;br /&gt;
    bellDefense: monsterAttributes[18],&lt;br /&gt;
    fanDefense: monsterAttributes[19],&lt;br /&gt;
    arrowDefense: monsterAttributes[20],&lt;br /&gt;
    clawDefense: monsterAttributes[21],&lt;br /&gt;
    fireResistance: monsterAttributes[22],&lt;br /&gt;
    lightningResistance: monsterAttributes[23],&lt;br /&gt;
    magicResistance: monsterAttributes[24],&lt;br /&gt;
    windResistance: monsterAttributes[25],&lt;br /&gt;
    lightningBonus: monsterAttributes[26],&lt;br /&gt;
    fireBonus: monsterAttributes[27],&lt;br /&gt;
    iceBonus: monsterAttributes[28],&lt;br /&gt;
    windBonus: monsterAttributes[29],&lt;br /&gt;
    earthBonus: monsterAttributes[30],&lt;br /&gt;
    darknessBonus: monsterAttributes[31],&lt;br /&gt;
    darknessResistance: monsterAttributes[32],&lt;br /&gt;
    iceResistance: monsterAttributes[33],&lt;br /&gt;
    earthResistance: monsterAttributes[34],&lt;br /&gt;
    damageMultiplier: monsterAttributes[35],&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  // monster.instance = 0;&lt;br /&gt;
&lt;br /&gt;
  // if (attacker &amp;amp;&amp;amp; monster.instance === 0) {&lt;br /&gt;
  //   changeMonsterValues(monster, &amp;quot;SungMahiTower&amp;quot;, attacker);&lt;br /&gt;
  // }&lt;br /&gt;
  if (!polymorphMonster) {&lt;br /&gt;
    changeMonsterValues(monster);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  monster.defense = monster.rawDefense + monster.level + monster.vit;&lt;br /&gt;
&lt;br /&gt;
  return monster;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addPotentialErrorInformation(&lt;br /&gt;
  errorInformation,&lt;br /&gt;
  attacker,&lt;br /&gt;
  victim,&lt;br /&gt;
  skillType,&lt;br /&gt;
  characters&lt;br /&gt;
) {&lt;br /&gt;
  for (var error of Object.values(errorInformation)) {&lt;br /&gt;
    hideElement(error);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker)) {&lt;br /&gt;
    if (isRiding(attacker)) {&lt;br /&gt;
      if (attacker.horsePoint === 0) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;horse-level&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
      showElement(errorInformation[&amp;quot;horse-stat&amp;quot;]);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isPolymorph(attacker)) {&lt;br /&gt;
      if (attacker.polymorphPoint === 0) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;polymorph-level&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (&lt;br /&gt;
        (attacker.polymorphPoint &amp;lt;= 39 &amp;amp;&amp;amp; attacker.attackValuePercent &amp;lt;= 199) ||&lt;br /&gt;
        (attacker.polymorphPoint === 40 &amp;amp;&amp;amp; attacker.attackValuePercent &amp;lt;= 299)&lt;br /&gt;
      ) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;polymorph-bonus&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
    if (skillType === &amp;quot;magic&amp;quot;) {&lt;br /&gt;
      if (attacker.magicAttackValue) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;magic-attack-value-bonus&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
      if (victim.magicResistance) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;magic-resistance&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    showElement(errorInformation[&amp;quot;monster-attacker&amp;quot;]);&lt;br /&gt;
    if (isMagicAttacker(attacker) &amp;amp;&amp;amp; victim.magicResistance) {&lt;br /&gt;
      showElement(errorInformation[&amp;quot;magic-resistance&amp;quot;]);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (isPC(victim)) {&lt;br /&gt;
    if (isRiding(victim)) {&lt;br /&gt;
      showElement(errorInformation[&amp;quot;horse-stat&amp;quot;]);&lt;br /&gt;
    }&lt;br /&gt;
    if (isPolymorph(victim)) {&lt;br /&gt;
      if (attacker.polymorphPoint === 0) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;polymorph-level&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
      showElement(errorInformation[&amp;quot;polymorph-defense&amp;quot;]);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (characters.unsavedChanges) {&lt;br /&gt;
    showElement(errorInformation[&amp;quot;save&amp;quot;]);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function reduceChartPointsListener(battle) {&lt;br /&gt;
  var {&lt;br /&gt;
    reduceChartPointsContainer,&lt;br /&gt;
    reduceChartPoints,&lt;br /&gt;
    numberFormats: { second: numberFormat },&lt;br /&gt;
    displayTime,&lt;br /&gt;
  } = battle;&lt;br /&gt;
&lt;br /&gt;
  reduceChartPoints.addEventListener(&amp;quot;change&amp;quot;, function () {&lt;br /&gt;
    reduceChartPoints.disabled = true;&lt;br /&gt;
&lt;br /&gt;
    var startDisplayTime = performance.now();&lt;br /&gt;
    var scatterDataByType = battle.scatterDataByType;&lt;br /&gt;
    var {&lt;br /&gt;
      chart,&lt;br /&gt;
      maxPoints,&lt;br /&gt;
      chart: {&lt;br /&gt;
        data: { datasets },&lt;br /&gt;
      },&lt;br /&gt;
    } = battle.damagesChart;&lt;br /&gt;
    var addAnimations = false;&lt;br /&gt;
&lt;br /&gt;
    for (var index = 0; index &amp;lt; datasets.length; index++) {&lt;br /&gt;
      var dataset = datasets[index];&lt;br /&gt;
      var scatterData = scatterDataByType[dataset.name];&lt;br /&gt;
&lt;br /&gt;
      if (dataset.canBeReduced &amp;amp;&amp;amp; reduceChartPoints.checked) {&lt;br /&gt;
        dataset.data = aggregateDamages(scatterData, maxPoints);&lt;br /&gt;
        addAnimations = true;&lt;br /&gt;
      } else {&lt;br /&gt;
        dataset.data = scatterData;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    handleChartAnimations(chart, addAnimations);&lt;br /&gt;
    chart.update();&lt;br /&gt;
&lt;br /&gt;
    displayTime.textContent = numberFormat.format(&lt;br /&gt;
      (performance.now() - startDisplayTime) / 1000&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    setTimeout(function () {&lt;br /&gt;
      reduceChartPoints.disabled = false;&lt;br /&gt;
    }, 1000);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  reduceChartPointsContainer.addEventListener(&amp;quot;pointerup&amp;quot;, function (event) {&lt;br /&gt;
    if (event.pointerType === &amp;quot;mouse&amp;quot;) {&lt;br /&gt;
      if (event.target.closest(&amp;quot;label&amp;quot;)) {&lt;br /&gt;
        return;&lt;br /&gt;
      }&lt;br /&gt;
      reduceChartPoints.click();&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function downloadRawDataListener(battle) {&lt;br /&gt;
  var { downLoadRawData, downLoadRawDataVariation } = battle;&lt;br /&gt;
  var fileType = &amp;quot;text/csv;charset=utf-8;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  downLoadRawData.addEventListener(&amp;quot;click&amp;quot;, function () {&lt;br /&gt;
    var damagesWeightedByType = battle.damagesWeightedByType;&lt;br /&gt;
    var filename = &amp;quot;raw_damages.csv&amp;quot;;&lt;br /&gt;
    var csvContent = &amp;quot;damage,probabilities,damageType\n&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    for (var damagesType in damagesWeightedByType) {&lt;br /&gt;
      var damagesWeighted = damagesWeightedByType[damagesType];&lt;br /&gt;
&lt;br /&gt;
      for (var damages in damagesWeighted) {&lt;br /&gt;
        csvContent +=&lt;br /&gt;
          damages + &amp;quot;,&amp;quot; + damagesWeighted[damages] + &amp;quot;,&amp;quot; + damagesType + &amp;quot;\n&amp;quot;;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    downloadData(csvContent, fileType, filename);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  downLoadRawDataVariation.addEventListener(&amp;quot;click&amp;quot;, function () {&lt;br /&gt;
    var damagesByBonus = battle.damagesByBonus;&lt;br /&gt;
    var damagesByBonusLength = damagesByBonus.length;&lt;br /&gt;
    var filename = &amp;quot;damages_variation.csv&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    if (!damagesByBonusLength) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var csvContent =&lt;br /&gt;
      damagesByBonus[damagesByBonusLength - 1] + &amp;quot;,averageDamage\n&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    for (var index = 0; index &amp;lt; damagesByBonusLength - 1; index++) {&lt;br /&gt;
      var row = damagesByBonus[index];&lt;br /&gt;
&lt;br /&gt;
      csvContent += row.x + &amp;quot;,&amp;quot; + row.y + &amp;quot;\n&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    downloadData(csvContent, fileType, filename);&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function displayResults(&lt;br /&gt;
  possibleDamagesCount,&lt;br /&gt;
  totalCardinal,&lt;br /&gt;
  damagesWeightedByType,&lt;br /&gt;
  battle,&lt;br /&gt;
  attackerName,&lt;br /&gt;
  victimName&lt;br /&gt;
) {&lt;br /&gt;
  var [&lt;br /&gt;
    meanDamages,&lt;br /&gt;
    minDamages,&lt;br /&gt;
    maxDamages,&lt;br /&gt;
    scatterDataByType,&lt;br /&gt;
    possibleDamagesCount,&lt;br /&gt;
    uniqueDamagesCount,&lt;br /&gt;
  ] = prepareDamagesData(&lt;br /&gt;
    damagesWeightedByType,&lt;br /&gt;
    possibleDamagesCount,&lt;br /&gt;
    totalCardinal&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  addToDamagesChart(&lt;br /&gt;
    scatterDataByType,&lt;br /&gt;
    battle.damagesChart,&lt;br /&gt;
    battle.reduceChartPoints.checked&lt;br /&gt;
  );&lt;br /&gt;
  updateDamagesChartDescription(&lt;br /&gt;
    battle.uniqueDamagesCounters,&lt;br /&gt;
    uniqueDamagesCount,&lt;br /&gt;
    battle.numberFormats.default&lt;br /&gt;
  );&lt;br /&gt;
  displayFightResults(&lt;br /&gt;
    battle,&lt;br /&gt;
    attackerName,&lt;br /&gt;
    victimName,&lt;br /&gt;
    meanDamages,&lt;br /&gt;
    minDamages,&lt;br /&gt;
    maxDamages&lt;br /&gt;
  );&lt;br /&gt;
  battle.damagesWeightedByType = damagesWeightedByType;&lt;br /&gt;
  battle.scatterDataByType = scatterDataByType;&lt;br /&gt;
&lt;br /&gt;
  return possibleDamagesCount;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function displayFightResults(&lt;br /&gt;
  battle,&lt;br /&gt;
  attackerName,&lt;br /&gt;
  victimName,&lt;br /&gt;
  meanDamages,&lt;br /&gt;
  minDamages,&lt;br /&gt;
  maxDamages&lt;br /&gt;
) {&lt;br /&gt;
  var {&lt;br /&gt;
    tableResultFight,&lt;br /&gt;
    tableResultHistory,&lt;br /&gt;
    attackTypeSelection,&lt;br /&gt;
    savedFights,&lt;br /&gt;
    numberFormats: { default: numberFormat },&lt;br /&gt;
    deleteFightTemplate,&lt;br /&gt;
  } = battle;&lt;br /&gt;
&lt;br /&gt;
  hideElement(tableResultHistory.rows[1]);&lt;br /&gt;
&lt;br /&gt;
  var valuesToDisplay = [&lt;br /&gt;
    attackerName,&lt;br /&gt;
    victimName,&lt;br /&gt;
    attackTypeSelection.options[attackTypeSelection.selectedIndex].textContent,&lt;br /&gt;
    meanDamages,&lt;br /&gt;
    minDamages,&lt;br /&gt;
    maxDamages,&lt;br /&gt;
  ];&lt;br /&gt;
&lt;br /&gt;
  savedFights.push(valuesToDisplay);&lt;br /&gt;
  updateSavedFights(savedFights);&lt;br /&gt;
&lt;br /&gt;
  editTableResultRow(tableResultFight.rows[1], valuesToDisplay, numberFormat);&lt;br /&gt;
  addRowToTableResultHistory(&lt;br /&gt;
    tableResultHistory,&lt;br /&gt;
    valuesToDisplay,&lt;br /&gt;
    deleteFightTemplate,&lt;br /&gt;
    numberFormat&lt;br /&gt;
  );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function displayFightInfo(&lt;br /&gt;
  possibleDamagesCount,&lt;br /&gt;
  damagesTime,&lt;br /&gt;
  displayTime,&lt;br /&gt;
  battle&lt;br /&gt;
) {&lt;br /&gt;
  var container = battle.possibleDamagesCounter.parentElement;&lt;br /&gt;
&lt;br /&gt;
  if (possibleDamagesCount &amp;lt;= 1) {&lt;br /&gt;
    hideElement(container);&lt;br /&gt;
    return;&lt;br /&gt;
  } else {&lt;br /&gt;
    showElement(container);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  possibleDamagesCount =&lt;br /&gt;
    battle.numberFormats.default.format(possibleDamagesCount);&lt;br /&gt;
  damagesTime = battle.numberFormats.second.format(damagesTime / 1000);&lt;br /&gt;
  displayTime = battle.numberFormats.second.format(displayTime / 1000);&lt;br /&gt;
&lt;br /&gt;
  battle.possibleDamagesCounter.textContent = possibleDamagesCount;&lt;br /&gt;
  battle.damagesTime.textContent = damagesTime;&lt;br /&gt;
  battle.displayTime.textContent = displayTime;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isPseudoSaved(characters, pseudo) {&lt;br /&gt;
  return characters.savedCharacters.hasOwnProperty(pseudo);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function useBonusVariationMode(character, variation) {&lt;br /&gt;
  return isChecked(character.useBonusVariation) &amp;amp;&amp;amp;&lt;br /&gt;
  character.hasOwnProperty(variation) &amp;amp;&amp;amp;&lt;br /&gt;
  character.bonusVariationMinValue &amp;lt; character.bonusVariationMaxValue&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createBattle(characters, battle) {&lt;br /&gt;
  battle.battleForm.addEventListener(&amp;quot;submit&amp;quot;, function (event) {&lt;br /&gt;
    event.preventDefault();&lt;br /&gt;
&lt;br /&gt;
    // auto save&lt;br /&gt;
    if (characters.unsavedChanges) {&lt;br /&gt;
      characters.saveButton.click();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var battleInfo = new FormData(event.target);&lt;br /&gt;
    var attackerName = battleInfo.get(&amp;quot;attacker&amp;quot;);&lt;br /&gt;
    var attackType = battleInfo.get(&amp;quot;attackTypeSelection&amp;quot;);&lt;br /&gt;
    var victimName = battleInfo.get(&amp;quot;victim&amp;quot;);&lt;br /&gt;
    var attackerVariation;&lt;br /&gt;
    var victimVariation;&lt;br /&gt;
&lt;br /&gt;
    if (!attackerName &amp;amp;&amp;amp; !attackType &amp;amp;&amp;amp; !victimName) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isPseudoSaved(characters, attackerName)) {&lt;br /&gt;
      var attacker = copyObject(characters.savedCharacters[attackerName]);&lt;br /&gt;
      attackerVariation = attacker.bonusVariation;&lt;br /&gt;
    } else {&lt;br /&gt;
      var attacker = createMonster(attackerName);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isPseudoSaved(characters, victimName)) {&lt;br /&gt;
      var victim = copyObject(characters.savedCharacters[victimName]);&lt;br /&gt;
      victimVariation = victim.bonusVariation;&lt;br /&gt;
    } else {&lt;br /&gt;
      var victim = createMonster(victimName, attacker);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (useBonusVariationMode(attacker, attackerVariation)) {&lt;br /&gt;
      damagesWithVariation(&lt;br /&gt;
        attacker,&lt;br /&gt;
        victim,&lt;br /&gt;
        attackType,&lt;br /&gt;
        battle,&lt;br /&gt;
        attacker,&lt;br /&gt;
        attackerVariation&lt;br /&gt;
      );&lt;br /&gt;
    } else if (useBonusVariationMode(victim, victimVariation)) {&lt;br /&gt;
      damagesWithVariation(&lt;br /&gt;
        attacker,&lt;br /&gt;
        victim,&lt;br /&gt;
        attackType,&lt;br /&gt;
        battle,&lt;br /&gt;
        victim,&lt;br /&gt;
        victimVariation&lt;br /&gt;
      );&lt;br /&gt;
    } else {&lt;br /&gt;
      damagesWithoutVariation(attacker, victim, attackType, battle, characters);&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createMapping() {&lt;br /&gt;
  mapping = {&lt;br /&gt;
    typeFlag: [&lt;br /&gt;
      &amp;quot;animalBonus&amp;quot;, // 0&lt;br /&gt;
      &amp;quot;humanBonus&amp;quot;, // 1&lt;br /&gt;
      &amp;quot;orcBonus&amp;quot;, // 2&lt;br /&gt;
      &amp;quot;mysticBonus&amp;quot;, // 3&lt;br /&gt;
      &amp;quot;undeadBonus&amp;quot;, // 4&lt;br /&gt;
      &amp;quot;insectBonus&amp;quot;, // 5&lt;br /&gt;
      &amp;quot;desertBonus&amp;quot;, // 6&lt;br /&gt;
      &amp;quot;devilBonus&amp;quot;, // 7&lt;br /&gt;
    ],&lt;br /&gt;
    raceBonus: {&lt;br /&gt;
      warrior: &amp;quot;warriorBonus&amp;quot;,&lt;br /&gt;
      sura: &amp;quot;suraBonus&amp;quot;,&lt;br /&gt;
      ninja: &amp;quot;ninjaBonus&amp;quot;,&lt;br /&gt;
      shaman: &amp;quot;shamanBonus&amp;quot;,&lt;br /&gt;
      lycan: &amp;quot;lycanBonus&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    raceResistance: {&lt;br /&gt;
      warrior: &amp;quot;warriorResistance&amp;quot;,&lt;br /&gt;
      sura: &amp;quot;suraResistance&amp;quot;,&lt;br /&gt;
      ninja: &amp;quot;ninjaResistance&amp;quot;,&lt;br /&gt;
      shaman: &amp;quot;shamanResistance&amp;quot;,&lt;br /&gt;
      lycan: &amp;quot;lycanResistance&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    defenseWeapon: [&lt;br /&gt;
      &amp;quot;swordDefense&amp;quot;, // 0&lt;br /&gt;
      &amp;quot;daggerDefense&amp;quot;, // 1&lt;br /&gt;
      &amp;quot;arrowDefense&amp;quot;, // 2&lt;br /&gt;
      &amp;quot;twoHandedSwordDefense&amp;quot;, // 3&lt;br /&gt;
      &amp;quot;bellDefense&amp;quot;, // 4&lt;br /&gt;
      &amp;quot;clawDefense&amp;quot;, // 5&lt;br /&gt;
      &amp;quot;fanDefense&amp;quot;, // 6&lt;br /&gt;
      &amp;quot;swordDefense&amp;quot;, // 7&lt;br /&gt;
      &amp;quot;fistDefense&amp;quot;, // 8&lt;br /&gt;
    ],&lt;br /&gt;
    breakWeapon: [&lt;br /&gt;
      &amp;quot;breakSwordDefense&amp;quot;, // 0&lt;br /&gt;
      &amp;quot;breakDaggerDefense&amp;quot;, // 1&lt;br /&gt;
      &amp;quot;breakArrowDefense&amp;quot;, // 2&lt;br /&gt;
      &amp;quot;breakTwoHandedSwordDefense&amp;quot;, // 3&lt;br /&gt;
      &amp;quot;breakBellDefense&amp;quot;, // 4&lt;br /&gt;
      &amp;quot;breakClawDefense&amp;quot;, // 5&lt;br /&gt;
      &amp;quot;breakFanDefense&amp;quot;, // 6&lt;br /&gt;
      &amp;quot;breakSwordDefense&amp;quot;, // 7&lt;br /&gt;
    ],&lt;br /&gt;
    elementBonus: [&lt;br /&gt;
      &amp;quot;fireBonus&amp;quot;, // 0&lt;br /&gt;
      &amp;quot;iceBonus&amp;quot;, // 1&lt;br /&gt;
      &amp;quot;windBonus&amp;quot;, // 2&lt;br /&gt;
      &amp;quot;lightningBonus&amp;quot;, // 3&lt;br /&gt;
      &amp;quot;earthBonus&amp;quot;, // 4&lt;br /&gt;
      &amp;quot;darknessBonus&amp;quot;, // 5&lt;br /&gt;
    ],&lt;br /&gt;
    elementResistance: [&lt;br /&gt;
      &amp;quot;fireResistance&amp;quot;, // 0&lt;br /&gt;
      &amp;quot;iceResistance&amp;quot;, // 1&lt;br /&gt;
      &amp;quot;windResistance&amp;quot;, // 2&lt;br /&gt;
      &amp;quot;lightningResistance&amp;quot;, // 3&lt;br /&gt;
      &amp;quot;earthResistance&amp;quot;, // 4&lt;br /&gt;
      &amp;quot;darknessResistance&amp;quot;, // 5&lt;br /&gt;
    ],&lt;br /&gt;
  };&lt;br /&gt;
  return mapping;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createConstants() {&lt;br /&gt;
  var constants = {&lt;br /&gt;
    polymorphPowerTable: [&lt;br /&gt;
      10, 11, 11, 12, 13, 13, 14, 15, 16, 17, 18, 19, 20, 22, 23, 24, 26, 27,&lt;br /&gt;
      29, 31, 33, 35, 37, 39, 41, 44, 46, 49, 52, 55, 59, 62, 66, 70, 74, 79,&lt;br /&gt;
      84, 89, 94, 100, 0,&lt;br /&gt;
    ],&lt;br /&gt;
    skillPowerTable: [&lt;br /&gt;
      0, 0.05, 0.06, 0.08, 0.1, 0.12, 0.14, 0.16, 0.18, 0.2, 0.22, 0.24, 0.26,&lt;br /&gt;
      0.28, 0.3, 0.32, 0.34, 0.36, 0.38, 0.4, 0.5, 0.52, 0.54, 0.56, 0.58, 0.6,&lt;br /&gt;
      0.63, 0.66, 0.69, 0.72, 0.82, 0.85, 0.88, 0.91, 0.94, 0.98, 1.02, 1.06,&lt;br /&gt;
      1.1, 1.15, 1.25,&lt;br /&gt;
    ],&lt;br /&gt;
    marriageTable: {&lt;br /&gt;
      harmonyEarrings: [4, 5, 6, 8],&lt;br /&gt;
      loveEarrings: [4, 5, 6, 8],&lt;br /&gt;
      harmonyBracelet: [4, 5, 6, 8],&lt;br /&gt;
      loveNecklace: [20, 25, 30, 40],&lt;br /&gt;
      harmonyNecklace: [12, 16, 20, 30],&lt;br /&gt;
    },&lt;br /&gt;
    allowedWeaponsPerRace: {&lt;br /&gt;
      warrior: [0, 3, 8],&lt;br /&gt;
      ninja: [0, 1, 2, 8],&lt;br /&gt;
      sura: [0, 7, 8],&lt;br /&gt;
      shaman: [4, 6, 8],&lt;br /&gt;
      lycan: [5, 8],&lt;br /&gt;
    },&lt;br /&gt;
    translation: {&lt;br /&gt;
      fr: {&lt;br /&gt;
        damages: &amp;quot;Dégâts&amp;quot;,&lt;br /&gt;
        percentage: &amp;quot;Pourcentage&amp;quot;,&lt;br /&gt;
        miss: &amp;quot;Miss&amp;quot;,&lt;br /&gt;
        normalHit: &amp;quot;Coup classique&amp;quot;,&lt;br /&gt;
        criticalHit: &amp;quot;Coup critique&amp;quot;,&lt;br /&gt;
        piercingHit: &amp;quot;Coup perçant&amp;quot;,&lt;br /&gt;
        criticalPiercingHit: &amp;quot;Coup critique perçant&amp;quot;,&lt;br /&gt;
        damagesRepartition: &amp;quot;Distribution des dégâts&amp;quot;,&lt;br /&gt;
        averageDamages: &amp;quot;Dégâts moyens&amp;quot;,&lt;br /&gt;
        damagesAugmentation: &amp;quot;Augmentation des dégâts&amp;quot;,&lt;br /&gt;
        bonusVariationTitle: [&lt;br /&gt;
          &amp;quot;Évolution des dégâts moyens&amp;quot;,&lt;br /&gt;
          &amp;quot;par rapport à la valeur d'un bonus&amp;quot;,&lt;br /&gt;
        ],&lt;br /&gt;
      },&lt;br /&gt;
      en: {&lt;br /&gt;
        damages: &amp;quot;Damage&amp;quot;,&lt;br /&gt;
        percentage: &amp;quot;Percentage&amp;quot;,&lt;br /&gt;
        miss: &amp;quot;Miss&amp;quot;,&lt;br /&gt;
        normalHit: &amp;quot;Normal Hit&amp;quot;,&lt;br /&gt;
        criticalHit: &amp;quot;Critical Hit&amp;quot;,&lt;br /&gt;
        piercingHit: &amp;quot;Piercing Hit&amp;quot;,&lt;br /&gt;
        criticalPiercingHit: &amp;quot;Critical Piercing Hit&amp;quot;,&lt;br /&gt;
        damagesRepartition: &amp;quot;Damage Repartition&amp;quot;,&lt;br /&gt;
        averageDamages: &amp;quot;Average Damage&amp;quot;,&lt;br /&gt;
        damagesAugmentation: &amp;quot;Damage Augmentation&amp;quot;,&lt;br /&gt;
        bonusVariationTitle: [&lt;br /&gt;
          &amp;quot;Evolution of Average Damage&amp;quot;,&lt;br /&gt;
          &amp;quot;Relative to a Bonus Value&amp;quot;,&lt;br /&gt;
        ],&lt;br /&gt;
      },&lt;br /&gt;
      tr: {&lt;br /&gt;
        damages: &amp;quot;Hasar&amp;quot;,&lt;br /&gt;
        percentage: &amp;quot;Yüzde&amp;quot;,&lt;br /&gt;
        miss: &amp;quot;Miss Vuruş&amp;quot;,&lt;br /&gt;
        normalHit: &amp;quot;Düz Vuruş&amp;quot;,&lt;br /&gt;
        criticalHit: &amp;quot;Kritik Vuruş&amp;quot;,&lt;br /&gt;
        piercingHit: &amp;quot;Delici Vuruş&amp;quot;,&lt;br /&gt;
        criticalPiercingHit: &amp;quot;Kritikli Delici Vuruş&amp;quot;,&lt;br /&gt;
        damagesRepartition: &amp;quot;Hasar Dağılımı&amp;quot;,&lt;br /&gt;
        averageDamages: &amp;quot;Ortalama Hasar&amp;quot;,&lt;br /&gt;
        damagesAugmentation: &amp;quot;Ortalama Hasar Artışı&amp;quot;,&lt;br /&gt;
        bonusVariationTitle: [&lt;br /&gt;
          &amp;quot;Bir bonusun değerine kıyasla&amp;quot;,&lt;br /&gt;
          &amp;quot;Ortalama Hasar Çizelgesi&amp;quot;,&lt;br /&gt;
        ],&lt;br /&gt;
      },&lt;br /&gt;
      ro: {&lt;br /&gt;
        damages: &amp;quot;Daune&amp;quot;,&lt;br /&gt;
        percentage: &amp;quot;Procent&amp;quot;,&lt;br /&gt;
        miss: &amp;quot;Miss&amp;quot;,&lt;br /&gt;
        normalHit: &amp;quot;Lovitura normala&amp;quot;,&lt;br /&gt;
        criticalHit: &amp;quot;Lovitura critica&amp;quot;,&lt;br /&gt;
        piercingHit: &amp;quot;Lovitura patrunzatoare&amp;quot;,&lt;br /&gt;
        criticalPiercingHit: &amp;quot;Lovitura critica si patrunzatoare&amp;quot;,&lt;br /&gt;
        damagesRepartition: &amp;quot;Distribuția daunelor&amp;quot;,&lt;br /&gt;
        averageDamages: &amp;quot;Media damageului&amp;quot;,&lt;br /&gt;
        damagesAugmentation: &amp;quot;Damage imbunatatit&amp;quot;,&lt;br /&gt;
        bonusVariationTitle: [&lt;br /&gt;
          &amp;quot;Evolutia mediei damageului&amp;quot;,&lt;br /&gt;
          &amp;quot;relativ la o valoare bonus&amp;quot;,&lt;br /&gt;
        ],&lt;br /&gt;
      },&lt;br /&gt;
      de: {&lt;br /&gt;
        damages: &amp;quot;Schäden&amp;quot;,&lt;br /&gt;
        percentage: &amp;quot;Prozentsatz&amp;quot;,&lt;br /&gt;
        miss: &amp;quot;Verfehlen&amp;quot;,&lt;br /&gt;
        normalHit: &amp;quot;Normaler Treffer&amp;quot;,&lt;br /&gt;
        criticalHit: &amp;quot;Kritischer Treffer&amp;quot;,&lt;br /&gt;
        piercingHit: &amp;quot;Durchdringender Treffer&amp;quot;,&lt;br /&gt;
        criticalPiercingHit: &amp;quot;Kritischer durchdringender Treffer&amp;quot;,&lt;br /&gt;
        damagesRepartition: &amp;quot;Schadensverteilung&amp;quot;,&lt;br /&gt;
        averageDamages: &amp;quot;Durchschnittlicher Schaden&amp;quot;,&lt;br /&gt;
        damagesAugmentation: &amp;quot;Schadenserhöhung&amp;quot;,&lt;br /&gt;
        bonusVariationTitle: [&lt;br /&gt;
          &amp;quot;Entwicklung des durchschnittlichen Schadens&amp;quot;,&lt;br /&gt;
          &amp;quot;im Verhältnis zu einem Bonus&amp;quot;,&lt;br /&gt;
        ],&lt;br /&gt;
      },&lt;br /&gt;
      pt: {&lt;br /&gt;
        damages: &amp;quot;Dano&amp;quot;,&lt;br /&gt;
        percentage: &amp;quot;Percentagem&amp;quot;,&lt;br /&gt;
        miss: &amp;quot;Miss&amp;quot;,&lt;br /&gt;
        normalHit: &amp;quot;Dano normal&amp;quot;,&lt;br /&gt;
        criticalHit: &amp;quot;Dano crítico&amp;quot;,&lt;br /&gt;
        piercingHit: &amp;quot;Dano perfurante&amp;quot;,&lt;br /&gt;
        criticalPiercingHit: &amp;quot;Dano crítico perfurante&amp;quot;,&lt;br /&gt;
        damagesRepartition: &amp;quot;Repartição de dano&amp;quot;,&lt;br /&gt;
        averageDamages: &amp;quot;Dano médio&amp;quot;,&lt;br /&gt;
        damagesAugmentation: &amp;quot;Aumento de dano&amp;quot;,&lt;br /&gt;
        bonusVariationTitle: [&amp;quot;Evolução do dano médio&amp;quot;, &amp;quot;relativo a um bónus&amp;quot;],&lt;br /&gt;
      },&lt;br /&gt;
      // es: {&lt;br /&gt;
      //   damages: &amp;quot;Daño&amp;quot;,&lt;br /&gt;
      //   percentage: &amp;quot;Porcentaje&amp;quot;,&lt;br /&gt;
      //   miss: &amp;quot;Miss&amp;quot;,&lt;br /&gt;
      //   normalHit: &amp;quot;Daño normal&amp;quot;,&lt;br /&gt;
      //   criticalHit: &amp;quot;Daño crítico&amp;quot;,&lt;br /&gt;
      //   piercingHit: &amp;quot;Daño perforante&amp;quot;,&lt;br /&gt;
      //   criticalPiercingHit: &amp;quot;Daño crítico perforante&amp;quot;,&lt;br /&gt;
      //   damagesRepartition: &amp;quot;Repartición de daños&amp;quot;,&lt;br /&gt;
      //   averageDamages: &amp;quot;Daño medio&amp;quot;,&lt;br /&gt;
      //   damagesAugmentation: &amp;quot;Aumento de daño&amp;quot;,&lt;br /&gt;
      //   bonusVariationTitle: [&amp;quot;Evolución del daño medio&amp;quot;, &amp;quot;Relativo a una bonificación&amp;quot;]&lt;br /&gt;
      // },&lt;br /&gt;
    },&lt;br /&gt;
  };&lt;br /&gt;
  return constants;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initResultTableHistory(battle) {&lt;br /&gt;
  var {&lt;br /&gt;
    tableResultHistory,&lt;br /&gt;
    savedFights,&lt;br /&gt;
    deleteFightTemplate,&lt;br /&gt;
    numberFormats: { default: numberFormat },&lt;br /&gt;
  } = battle;&lt;br /&gt;
  var startIndex = 3;&lt;br /&gt;
&lt;br /&gt;
  if (savedFights.length) {&lt;br /&gt;
    hideElement(tableResultHistory.rows[1]);&lt;br /&gt;
&lt;br /&gt;
    for (var savedFight of savedFights) {&lt;br /&gt;
      addRowToTableResultHistory(&lt;br /&gt;
        tableResultHistory,&lt;br /&gt;
        savedFight,&lt;br /&gt;
        deleteFightTemplate,&lt;br /&gt;
        numberFormat&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  tableResultHistory.addEventListener(&amp;quot;click&amp;quot;, function (event) {&lt;br /&gt;
    var deleteButton = event.target.closest(&amp;quot;.svg-icon-delete&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (deleteButton) {&lt;br /&gt;
      var row = deleteButton.closest(&amp;quot;tr&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
      if (row) {&lt;br /&gt;
        savedFights.splice(row.rowIndex - startIndex, 1);&lt;br /&gt;
        updateSavedFights(savedFights);&lt;br /&gt;
&lt;br /&gt;
        row.remove();&lt;br /&gt;
&lt;br /&gt;
        if (tableResultHistory.rows.length === startIndex) {&lt;br /&gt;
          showElement(tableResultHistory.rows[1]);&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initDamagesChart(battle) {&lt;br /&gt;
  var { translation, reduceChartPointsContainer, reduceChartPoints } = battle;&lt;br /&gt;
  var percentFormat = battle.numberFormats.percent;&lt;br /&gt;
  var customPlugins = {&lt;br /&gt;
    id: &amp;quot;customPlugins&amp;quot;,&lt;br /&gt;
    afterDraw(chart) {&lt;br /&gt;
      var missPercentage = chart.data.missPercentage;&lt;br /&gt;
&lt;br /&gt;
      if (!missPercentage) {&lt;br /&gt;
        return;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      var {&lt;br /&gt;
        ctx,&lt;br /&gt;
        chartArea: { top, right },&lt;br /&gt;
      } = chart;&lt;br /&gt;
      ctx.save();&lt;br /&gt;
      var text =&lt;br /&gt;
        translation.miss + &amp;quot; : &amp;quot; + percentFormat.format(missPercentage);&lt;br /&gt;
      var padding = 4;&lt;br /&gt;
      var fontSize = 14;&lt;br /&gt;
&lt;br /&gt;
      ctx.font = fontSize + &amp;quot;px Helvetica Neue&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
      var textWidth = ctx.measureText(text).width;&lt;br /&gt;
      var xPosition = right - textWidth - 5;&lt;br /&gt;
      var yPosition = top + 5;&lt;br /&gt;
&lt;br /&gt;
      ctx.fillStyle = &amp;quot;rgba(255, 0, 0, 0.2)&amp;quot;;&lt;br /&gt;
      ctx.fillRect(&lt;br /&gt;
        xPosition - padding,&lt;br /&gt;
        yPosition - padding,&lt;br /&gt;
        textWidth + 2 * padding,&lt;br /&gt;
        fontSize + 2 * padding&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      ctx.strokeStyle = &amp;quot;red&amp;quot;;&lt;br /&gt;
      ctx.strokeRect(&lt;br /&gt;
        xPosition - padding,&lt;br /&gt;
        yPosition - padding,&lt;br /&gt;
        textWidth + 2 * padding,&lt;br /&gt;
        fontSize + 2 * padding&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      ctx.fillStyle = &amp;quot;#666&amp;quot;;&lt;br /&gt;
      ctx.textBaseline = &amp;quot;top&amp;quot;;&lt;br /&gt;
      ctx.fillText(text, xPosition, yPosition + 1);&lt;br /&gt;
&lt;br /&gt;
      ctx.restore();&lt;br /&gt;
    },&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  Chart.register(customPlugins);&lt;br /&gt;
&lt;br /&gt;
  var ctx = battle.plotDamages.getContext(&amp;quot;2d&amp;quot;);&lt;br /&gt;
  var maxLabelsInTooltip = 10;&lt;br /&gt;
  var nullLabelText = &amp;quot; ...&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  var chart = new Chart(ctx, {&lt;br /&gt;
    type: &amp;quot;scatter&amp;quot;,&lt;br /&gt;
    data: {&lt;br /&gt;
      missPercentage: 0,&lt;br /&gt;
      datasets: [],&lt;br /&gt;
    },&lt;br /&gt;
    options: {&lt;br /&gt;
      responsive: true,&lt;br /&gt;
      maintainAspectRatio: false,&lt;br /&gt;
      plugins: {&lt;br /&gt;
        legend: {&lt;br /&gt;
          display: true,&lt;br /&gt;
          onHover: function (e) {&lt;br /&gt;
            e.native.target.style.cursor = &amp;quot;pointer&amp;quot;;&lt;br /&gt;
          },&lt;br /&gt;
          onLeave: function (e) {&lt;br /&gt;
            e.native.target.style.cursor = &amp;quot;default&amp;quot;;&lt;br /&gt;
          },&lt;br /&gt;
          onClick: function (e, legendItem, legend) {&lt;br /&gt;
            var currentIndex = legendItem.datasetIndex;&lt;br /&gt;
            var ci = legend.chart;&lt;br /&gt;
            var isCurrentDatasetVisible = ci.isDatasetVisible(currentIndex);&lt;br /&gt;
            var datasets = ci.data.datasets;&lt;br /&gt;
            var hideReducePoints = true;&lt;br /&gt;
            var isReducePointsChecked = reduceChartPoints.checked;&lt;br /&gt;
&lt;br /&gt;
            datasets[currentIndex].hidden = isCurrentDatasetVisible;&lt;br /&gt;
            legendItem.hidden = isCurrentDatasetVisible;&lt;br /&gt;
&lt;br /&gt;
            for (var index in datasets) {&lt;br /&gt;
              if (ci.isDatasetVisible(index) &amp;amp;&amp;amp; datasets[index].canBeReduced) {&lt;br /&gt;
                showElement(reduceChartPointsContainer);&lt;br /&gt;
                hideReducePoints = false;&lt;br /&gt;
                break;&lt;br /&gt;
              }&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            if (hideReducePoints) {&lt;br /&gt;
              hideElement(reduceChartPointsContainer);&lt;br /&gt;
              handleChartAnimations(ci, true);&lt;br /&gt;
            } else {&lt;br /&gt;
              handleChartAnimations(ci, isReducePointsChecked);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            ci.update();&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        title: {&lt;br /&gt;
          display: true,&lt;br /&gt;
          text: translation.damagesRepartition,&lt;br /&gt;
          font: {&lt;br /&gt;
            size: 20,&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        tooltip: {&lt;br /&gt;
          callbacks: {&lt;br /&gt;
            label: function (context) {&lt;br /&gt;
              if (context.label === null) {&lt;br /&gt;
                return nullLabelText;&lt;br /&gt;
              }&lt;br /&gt;
&lt;br /&gt;
              var xValue = battle.numberFormats.default.format(&lt;br /&gt;
                context.parsed.x&lt;br /&gt;
              );&lt;br /&gt;
              var yValue = battle.numberFormats.percent.format(&lt;br /&gt;
                context.parsed.y&lt;br /&gt;
              );&lt;br /&gt;
&lt;br /&gt;
              label =&lt;br /&gt;
                &amp;quot; &amp;quot; +&lt;br /&gt;
                context.dataset.label +&lt;br /&gt;
                &amp;quot; : (&amp;quot; +&lt;br /&gt;
                xValue +&lt;br /&gt;
                &amp;quot;, &amp;quot; +&lt;br /&gt;
                yValue +&lt;br /&gt;
                &amp;quot;)&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
              return label;&lt;br /&gt;
            },&lt;br /&gt;
            beforeBody: function (tooltipItems) {&lt;br /&gt;
              if (tooltipItems.length &amp;gt; maxLabelsInTooltip + 1) {&lt;br /&gt;
                tooltipItems.splice(maxLabelsInTooltip + 1);&lt;br /&gt;
                tooltipItems[maxLabelsInTooltip].label = null;&lt;br /&gt;
              }&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          caretPadding: 10,&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
      scales: {&lt;br /&gt;
        x: {&lt;br /&gt;
          type: &amp;quot;linear&amp;quot;,&lt;br /&gt;
          position: &amp;quot;bottom&amp;quot;,&lt;br /&gt;
          title: {&lt;br /&gt;
            display: true,&lt;br /&gt;
            text: translation.damages,&lt;br /&gt;
            font: {&lt;br /&gt;
              size: 16,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        y: {&lt;br /&gt;
          title: {&lt;br /&gt;
            display: true,&lt;br /&gt;
            text: translation.percentage,&lt;br /&gt;
            font: {&lt;br /&gt;
              size: 16,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          ticks: {&lt;br /&gt;
            format: {&lt;br /&gt;
              style: &amp;quot;percent&amp;quot;,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
      elements: {&lt;br /&gt;
        point: {&lt;br /&gt;
          borderWidth: 1,&lt;br /&gt;
          radius: 3,&lt;br /&gt;
          hitRadius: 3,&lt;br /&gt;
          hoverRadius: 6,&lt;br /&gt;
          hoverBorderWidth: 2,&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
    },&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  var datasetsStyle = [&lt;br /&gt;
    {&lt;br /&gt;
      name: &amp;quot;normalHit&amp;quot;,&lt;br /&gt;
      canBeReduced: false,&lt;br /&gt;
      label: translation.normalHit,&lt;br /&gt;
      backgroundColor: &amp;quot;rgba(75, 192, 192, 0.2)&amp;quot;,&lt;br /&gt;
      borderColor: &amp;quot;rgba(75, 192, 192, 1)&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      name: &amp;quot;piercingHit&amp;quot;,&lt;br /&gt;
      canBeReduced: false,&lt;br /&gt;
      label: translation.piercingHit,&lt;br /&gt;
      backgroundColor: &amp;quot;rgba(192, 192, 75, 0.2)&amp;quot;,&lt;br /&gt;
      borderColor: &amp;quot;rgba(192, 192, 75, 1)&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      name: &amp;quot;criticalHit&amp;quot;,&lt;br /&gt;
      canBeReduced: false,&lt;br /&gt;
      label: translation.criticalHit,&lt;br /&gt;
      backgroundColor: &amp;quot;rgba(192, 75, 192, 0.2)&amp;quot;,&lt;br /&gt;
      borderColor: &amp;quot;rgba(192, 75, 192, 1)&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      name: &amp;quot;criticalPiercingHit&amp;quot;,&lt;br /&gt;
      canBeReduced: false,&lt;br /&gt;
      label: translation.criticalPiercingHit,&lt;br /&gt;
      backgroundColor: &amp;quot;rgba(75, 75, 192, 0.2)&amp;quot;,&lt;br /&gt;
      borderColor: &amp;quot;rgba(75, 75, 192, 1)&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
  ];&lt;br /&gt;
  battle.damagesChart = {&lt;br /&gt;
    chart: chart,&lt;br /&gt;
    datasetsStyle: datasetsStyle,&lt;br /&gt;
    maxPoints: 500,&lt;br /&gt;
    reduceChartPointsContainer: reduceChartPointsContainer,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initBonusVariationChart(battle) {&lt;br /&gt;
  var translation = battle.translation;&lt;br /&gt;
&lt;br /&gt;
  var ctx = battle.plotBonusVariation.getContext(&amp;quot;2d&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  var chart = new Chart(ctx, {&lt;br /&gt;
    type: &amp;quot;line&amp;quot;,&lt;br /&gt;
    data: {&lt;br /&gt;
      datasets: [&lt;br /&gt;
        {&lt;br /&gt;
          label: translation.averageDamages,&lt;br /&gt;
          backgroundColor: &amp;quot;rgba(75, 192, 192, 0.2)&amp;quot;,&lt;br /&gt;
          borderColor: &amp;quot;rgba(75, 192, 192, 1)&amp;quot;,&lt;br /&gt;
          fill: true,&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          label: translation.damagesAugmentation,&lt;br /&gt;
          backgroundColor: &amp;quot;rgba(192, 192, 75, 0.2)&amp;quot;,&lt;br /&gt;
          borderColor: &amp;quot;rgba(192, 192, 75, 1)&amp;quot;,&lt;br /&gt;
          hidden: true,&lt;br /&gt;
          yTicksFormat: { style: &amp;quot;percent&amp;quot; },&lt;br /&gt;
          fill: true,&lt;br /&gt;
        },&lt;br /&gt;
      ],&lt;br /&gt;
    },&lt;br /&gt;
    options: {&lt;br /&gt;
      responsive: true,&lt;br /&gt;
      maintainAspectRatio: false,&lt;br /&gt;
      plugins: {&lt;br /&gt;
        legend: {&lt;br /&gt;
          display: true,&lt;br /&gt;
          onHover: function (e) {&lt;br /&gt;
            e.native.target.style.cursor = &amp;quot;pointer&amp;quot;;&lt;br /&gt;
          },&lt;br /&gt;
          onLeave: function (e) {&lt;br /&gt;
            e.native.target.style.cursor = &amp;quot;default&amp;quot;;&lt;br /&gt;
          },&lt;br /&gt;
          onClick: function (e, legendItem, legend) {&lt;br /&gt;
            var currentIndex = legendItem.datasetIndex;&lt;br /&gt;
            var ci = legend.chart;&lt;br /&gt;
            var datasets = ci.data.datasets;&lt;br /&gt;
            var isCurrentDatasetVisible = ci.isDatasetVisible(currentIndex);&lt;br /&gt;
            var yAxis = ci.options.scales.y;&lt;br /&gt;
&lt;br /&gt;
            var otherIndex = currentIndex === 0 ? 1 : 0;&lt;br /&gt;
            var visibleDataset = isCurrentDatasetVisible&lt;br /&gt;
              ? datasets[otherIndex]&lt;br /&gt;
              : datasets[currentIndex];&lt;br /&gt;
&lt;br /&gt;
            datasets[currentIndex].hidden = isCurrentDatasetVisible;&lt;br /&gt;
            datasets[otherIndex].hidden = !isCurrentDatasetVisible;&lt;br /&gt;
&lt;br /&gt;
            yAxis.title.text = visibleDataset.label;&lt;br /&gt;
            yAxis.ticks.format = visibleDataset.yTicksFormat;&lt;br /&gt;
&lt;br /&gt;
            ci.update();&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        title: {&lt;br /&gt;
          display: true,&lt;br /&gt;
          text: translation.bonusVariationTitle,&lt;br /&gt;
          font: {&lt;br /&gt;
            size: 18,&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        tooltip: {&lt;br /&gt;
          caretPadding: 10,&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
      scales: {&lt;br /&gt;
        x: {&lt;br /&gt;
          type: &amp;quot;linear&amp;quot;,&lt;br /&gt;
          position: &amp;quot;bottom&amp;quot;,&lt;br /&gt;
          title: {&lt;br /&gt;
            display: true,&lt;br /&gt;
            text: &amp;quot;Bonus&amp;quot;,&lt;br /&gt;
            font: {&lt;br /&gt;
              size: 16,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          ticks: {&lt;br /&gt;
            callback: function (value) {&lt;br /&gt;
              if (Number.isInteger(value)) {&lt;br /&gt;
                return Number(value);&lt;br /&gt;
              }&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        y: {&lt;br /&gt;
          title: {&lt;br /&gt;
            display: true,&lt;br /&gt;
            text: translation.averageDamages,&lt;br /&gt;
            font: {&lt;br /&gt;
              size: 16,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
      elements: {&lt;br /&gt;
        point: {&lt;br /&gt;
          borderWidth: 1,&lt;br /&gt;
          radius: 3,&lt;br /&gt;
          hitRadius: 3,&lt;br /&gt;
          hoverRadius: 6,&lt;br /&gt;
          hoverBorderWidth: 2,&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
    },&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  battle.bonusVariationChart = chart;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function attackSelectonListener(&lt;br /&gt;
  characters,&lt;br /&gt;
  attackerSelection,&lt;br /&gt;
  attackTypeSelection&lt;br /&gt;
) {&lt;br /&gt;
  attackerSelection.addEventListener(&amp;quot;change&amp;quot;, function (event) {&lt;br /&gt;
    var attackerName = event.target.value;&lt;br /&gt;
&lt;br /&gt;
    if (isPseudoSaved(characters, attackerName)) {&lt;br /&gt;
      var attacker = characters.savedCharacters[attackerName];&lt;br /&gt;
      filterAttackTypeSelection(attacker, attackTypeSelection);&lt;br /&gt;
    } else {&lt;br /&gt;
      filterAttackTypeSelectionMonster(attackTypeSelection);&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getTranslation(translation) {&lt;br /&gt;
  var userLanguage = navigator.language;&lt;br /&gt;
  var langToUse = &amp;quot;en&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  for (var lang in translation) {&lt;br /&gt;
    if (userLanguage.startsWith(lang)) {&lt;br /&gt;
      langToUse = lang;&lt;br /&gt;
      break;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return translation[langToUse];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createDamageCalculatorInformation(chartSource) {&lt;br /&gt;
  var characters = {&lt;br /&gt;
    unsavedChanges: false,&lt;br /&gt;
    savedCharacters: {},&lt;br /&gt;
    currentCharacter: null,&lt;br /&gt;
    savedMonsters: getSavedMonsters(),&lt;br /&gt;
    characterCreation: document.getElementById(&amp;quot;character-creation&amp;quot;),&lt;br /&gt;
    addNewCharacterButton: document.getElementById(&amp;quot;add-new-character&amp;quot;),&lt;br /&gt;
    dropZone: document.getElementById(&amp;quot;character-drop-zone&amp;quot;),&lt;br /&gt;
    characterInput: document.getElementById(&amp;quot;character-input&amp;quot;),&lt;br /&gt;
    newCharacterTemplate: document.getElementById(&amp;quot;new-character-template&amp;quot;)&lt;br /&gt;
      .children[0],&lt;br /&gt;
    charactersContainer: document.getElementById(&amp;quot;characters-container&amp;quot;),&lt;br /&gt;
    monsterButtonTemplates: document.getElementById(&amp;quot;monster-button-templates&amp;quot;),&lt;br /&gt;
    monsterTemplate: document.getElementById(&amp;quot;new-monster-template&amp;quot;)&lt;br /&gt;
      .children[0],&lt;br /&gt;
    monstersContainer: document.getElementById(&amp;quot;monsters-container&amp;quot;),&lt;br /&gt;
    monsteriFrame: document.getElementById(&amp;quot;monster-iframe&amp;quot;),&lt;br /&gt;
    stoneiFrame: document.getElementById(&amp;quot;stone-iframe&amp;quot;),&lt;br /&gt;
    saveButton: document.getElementById(&amp;quot;save-character&amp;quot;),&lt;br /&gt;
    weaponCategory: document.getElementById(&amp;quot;weapon-category&amp;quot;),&lt;br /&gt;
    weaponDisplay: document.getElementById(&amp;quot;weapon-display&amp;quot;),&lt;br /&gt;
    randomAttackValue: document.getElementById(&amp;quot;random-attack-value&amp;quot;),&lt;br /&gt;
    randomMagicAttackValue: document.getElementById(&lt;br /&gt;
      &amp;quot;random-magic-attack-value&amp;quot;&lt;br /&gt;
    ),&lt;br /&gt;
    polymorphDisplay: document.getElementById(&amp;quot;polymorph-display&amp;quot;),&lt;br /&gt;
    polymorphCreation: document.getElementById(&amp;quot;polymorph-creation&amp;quot;),&lt;br /&gt;
    yoharaCreation: document.getElementById(&amp;quot;yohara-creation&amp;quot;),&lt;br /&gt;
    blessingCreation: document.getElementById(&amp;quot;blessing-creation&amp;quot;),&lt;br /&gt;
    marriageCreation: document.getElementById(&amp;quot;marriage-creation&amp;quot;),&lt;br /&gt;
    bonusVariation: {&lt;br /&gt;
      tabButton: document.getElementById(&amp;quot;Variation&amp;quot;),&lt;br /&gt;
      checkbox: document.getElementById(&amp;quot;use-bonus-variation&amp;quot;),&lt;br /&gt;
      input: document.getElementById(&amp;quot;bonus-variation&amp;quot;),&lt;br /&gt;
      inputName: document.getElementById(&amp;quot;bonus-variation-name&amp;quot;),&lt;br /&gt;
      container: document.getElementById(&amp;quot;bonus-variation-creation&amp;quot;),&lt;br /&gt;
      minValue: document.getElementById(&amp;quot;bonus-variation-min-value&amp;quot;),&lt;br /&gt;
      maxValue: document.getElementById(&amp;quot;bonus-variation-max-value&amp;quot;),&lt;br /&gt;
      disabledText: document.getElementById(&amp;quot;bonus-variation-disabled&amp;quot;),&lt;br /&gt;
      selectedText: document.getElementById(&amp;quot;bonus-variation-selected&amp;quot;),&lt;br /&gt;
      displaySpan: document.getElementById(&amp;quot;bonus-variation-display&amp;quot;),&lt;br /&gt;
    },&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  for (var [pseudo, character] of Object.entries(getSavedCharacters())) {&lt;br /&gt;
    characters.savedCharacters[pseudo] = character;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var skillContainer = document.getElementById(&amp;quot;skill-container&amp;quot;);&lt;br /&gt;
  characters.skillElementsToFilter =&lt;br /&gt;
    skillContainer.querySelectorAll(&amp;quot;[data-class]&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  var mapping = createMapping();&lt;br /&gt;
  var constants = createConstants();&lt;br /&gt;
&lt;br /&gt;
  var battle = {&lt;br /&gt;
    resetAttackType: false,&lt;br /&gt;
    savedFights: getSavedFights(),&lt;br /&gt;
    battleForm: document.getElementById(&amp;quot;create-battle&amp;quot;),&lt;br /&gt;
    attackerSelection: document.getElementById(&amp;quot;attacker-selection&amp;quot;),&lt;br /&gt;
    attackTypeSelection: document.getElementById(&amp;quot;attack-type-selection&amp;quot;),&lt;br /&gt;
    victimSelection: document.getElementById(&amp;quot;victim-selection&amp;quot;),&lt;br /&gt;
    damagesWeightedByType: {},&lt;br /&gt;
    scatterDataByType: {},&lt;br /&gt;
    damagesByBonus: [],&lt;br /&gt;
    tableResultFight: document.getElementById(&amp;quot;result-table-fight&amp;quot;),&lt;br /&gt;
    tableResultHistory: document.getElementById(&amp;quot;result-table-history&amp;quot;),&lt;br /&gt;
    deleteFightTemplate: document.getElementById(&amp;quot;delete-fight-template&amp;quot;)&lt;br /&gt;
      .children[0],&lt;br /&gt;
    errorInformation: {},&lt;br /&gt;
    fightResultContainer: document.getElementById(&amp;quot;fight-result-container&amp;quot;),&lt;br /&gt;
    downLoadRawData: document.getElementById(&amp;quot;download-raw-data&amp;quot;),&lt;br /&gt;
    downLoadRawDataVariation: document.getElementById(&lt;br /&gt;
      &amp;quot;download-raw-data-variation&amp;quot;&lt;br /&gt;
    ),&lt;br /&gt;
    bonusVariationResultContainer: document.getElementById(&lt;br /&gt;
      &amp;quot;bonus-variation-result-container&amp;quot;&lt;br /&gt;
    ),&lt;br /&gt;
    reduceChartPointsContainer: document.getElementById(&lt;br /&gt;
      &amp;quot;reduce-chart-points-container&amp;quot;&lt;br /&gt;
    ),&lt;br /&gt;
    reduceChartPoints: document.getElementById(&amp;quot;reduce-chart-points&amp;quot;),&lt;br /&gt;
    plotDamages: document.getElementById(&amp;quot;plot-damages&amp;quot;),&lt;br /&gt;
    plotBonusVariation: document.getElementById(&amp;quot;plot-bonus-variation&amp;quot;),&lt;br /&gt;
    uniqueDamagesCounters: document.querySelectorAll(&amp;quot;.unique-damages-counter&amp;quot;),&lt;br /&gt;
    possibleDamagesCounter: document.getElementById(&amp;quot;possible-damages-counter&amp;quot;),&lt;br /&gt;
    damagesTime: document.getElementById(&amp;quot;damages-time&amp;quot;),&lt;br /&gt;
    displayTime: document.getElementById(&amp;quot;display-time&amp;quot;),&lt;br /&gt;
    simulationCounter: document.getElementById(&amp;quot;simulation-counter&amp;quot;),&lt;br /&gt;
    simulationTime: document.getElementById(&amp;quot;simulation-time&amp;quot;),&lt;br /&gt;
    numberFormats: {&lt;br /&gt;
      default: new Intl.NumberFormat(undefined, {&lt;br /&gt;
        minimumFractionDigits: 0,&lt;br /&gt;
        maximumFractionDigits: 1,&lt;br /&gt;
      }),&lt;br /&gt;
      percent: new Intl.NumberFormat(undefined, {&lt;br /&gt;
        style: &amp;quot;percent&amp;quot;,&lt;br /&gt;
        maximumFractionDigits: 3,&lt;br /&gt;
      }),&lt;br /&gt;
      second: new Intl.NumberFormat(undefined, {&lt;br /&gt;
        style: &amp;quot;unit&amp;quot;,&lt;br /&gt;
        unit: &amp;quot;second&amp;quot;,&lt;br /&gt;
        unitDisplay: &amp;quot;long&amp;quot;,&lt;br /&gt;
        maximumFractionDigits: 3,&lt;br /&gt;
      }),&lt;br /&gt;
    },&lt;br /&gt;
    mapping: mapping,&lt;br /&gt;
    constants: constants,&lt;br /&gt;
    translation: getTranslation(constants.translation),&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  attackSelectonListener(&lt;br /&gt;
    characters,&lt;br /&gt;
    battle.attackerSelection,&lt;br /&gt;
    battle.attackTypeSelection&lt;br /&gt;
  );&lt;br /&gt;
  initResultTableHistory(battle);&lt;br /&gt;
  addScript(chartSource, function () {&lt;br /&gt;
    initDamagesChart(battle);&lt;br /&gt;
    initBonusVariationChart(battle);&lt;br /&gt;
  });&lt;br /&gt;
  reduceChartPointsListener(battle);&lt;br /&gt;
  downloadRawDataListener(battle);&lt;br /&gt;
&lt;br /&gt;
  var errorElements = document.querySelectorAll(&amp;quot;[data-error]&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; errorElements.length; index++) {&lt;br /&gt;
    var errorElement = errorElements[index];&lt;br /&gt;
    battle.errorInformation[errorElement.dataset.error] = errorElement;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return [characters, battle];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadStyle(src) {&lt;br /&gt;
  var link = document.createElement(&amp;quot;link&amp;quot;);&lt;br /&gt;
  link.href = src;&lt;br /&gt;
  link.rel = &amp;quot;stylesheet&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  document.head.appendChild(link);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
(function () {&lt;br /&gt;
  var javascriptSource =&lt;br /&gt;
    &amp;quot;/index.php?title=Utilisateur:Ankhseram/Calculator.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&amp;quot;;&lt;br /&gt;
  var cssSource =&lt;br /&gt;
    &amp;quot;/index.php?title=Utilisateur:Ankhseram/Style.css&amp;amp;action=raw&amp;amp;ctype=text/css&amp;quot;;&lt;br /&gt;
  var chartSource = &amp;quot;https://cdn.jsdelivr.net/npm/chart.js&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  loadStyle(cssSource);&lt;br /&gt;
&lt;br /&gt;
  function main() {&lt;br /&gt;
    var [characters, battle] = createDamageCalculatorInformation(chartSource);&lt;br /&gt;
&lt;br /&gt;
    characterManagement(characters, battle);&lt;br /&gt;
    monsterManagement(characters, battle);&lt;br /&gt;
&lt;br /&gt;
    updateBattleChoice(characters, battle);&lt;br /&gt;
    createBattle(characters, battle);&lt;br /&gt;
  }&lt;br /&gt;
  addScript(javascriptSource, main);&lt;br /&gt;
})();&lt;/div&gt;</summary>
		<author><name>Dexter</name></author>
		
	</entry>
	<entry>
		<id>https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Script/Filter.js&amp;diff=105979</id>
		<title>MediaWiki:Script/Filter.js</title>
		<link rel="alternate" type="text/html" href="https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Script/Filter.js&amp;diff=105979"/>
		<updated>2024-12-23T20:05:33Z</updated>

		<summary type="html">&lt;p&gt;Dexter : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;function removeAccent(str) {&lt;br /&gt;
  return str&lt;br /&gt;
    .normalize(&amp;quot;NFD&amp;quot;)&lt;br /&gt;
    .replace(/[\u0300-\u036f]/g, &amp;quot;&amp;quot;)&lt;br /&gt;
    .toLowerCase();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function toNormalForm(str) {&lt;br /&gt;
  return removeAccent(str)&lt;br /&gt;
    .replace(/-/g, &amp;quot; &amp;quot;)&lt;br /&gt;
    .replace(/[^a-zA-Z0-9 ]/g, &amp;quot;&amp;quot;)&lt;br /&gt;
    .replace(/\s+/g, &amp;quot; &amp;quot;)&lt;br /&gt;
    .trim();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function editCardData(cardsData) {&lt;br /&gt;
  for (let cardIndex = 0; cardIndex &amp;lt; cardsData.length; cardIndex++) {&lt;br /&gt;
    const cardData = cardsData[cardIndex];&lt;br /&gt;
    const cardName = cardData.card.querySelector(&amp;quot;[data-name]&amp;quot;).textContent;&lt;br /&gt;
&lt;br /&gt;
    cardData.name = toNormalForm(cardName);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function observeLanguageChange(filterName, cardsData) {&lt;br /&gt;
  if (!filterName) {&lt;br /&gt;
    return;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  const observer = new MutationObserver(function (mutation) {&lt;br /&gt;
    editCardData(cardsData);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  observer.observe(filterName, { attributes: true });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function openFilter() {&lt;br /&gt;
  const filterButton = document.getElementById(&amp;quot;open-filter&amp;quot;);&lt;br /&gt;
  const filterDropdown = filterButton.nextElementSibling;&lt;br /&gt;
&lt;br /&gt;
  hideElement(filterDropdown);&lt;br /&gt;
&lt;br /&gt;
  filterButton.addEventListener(&amp;quot;click&amp;quot;, handleDropdown);&lt;br /&gt;
&lt;br /&gt;
  function handleDropdown() {&lt;br /&gt;
    toggleElement(filterDropdown);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  document.addEventListener(&amp;quot;mousedown&amp;quot;, function (event) {&lt;br /&gt;
    if (&lt;br /&gt;
      !filterButton.contains(event.target) &amp;amp;&amp;amp;&lt;br /&gt;
      !filterDropdown.contains(event.target)&lt;br /&gt;
    ) {&lt;br /&gt;
      hideElement(filterDropdown);&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function fillData(filter, filterData) {&lt;br /&gt;
  const { filter: category, value } = filter.dataset;&lt;br /&gt;
&lt;br /&gt;
  if (filter.type === &amp;quot;checkbox&amp;quot;) {&lt;br /&gt;
    const span = filter.parentElement.querySelector(&amp;quot;span.counter&amp;quot;);&lt;br /&gt;
    const filterInfo = { value: 0, span };&lt;br /&gt;
    const { checkbox } = filterData;&lt;br /&gt;
&lt;br /&gt;
    checkbox[category] = checkbox[category] || {};&lt;br /&gt;
    checkbox[category][value] = filterInfo;&lt;br /&gt;
  } else if (filter.type === &amp;quot;number&amp;quot;) {&lt;br /&gt;
    const { range } = filterData;&lt;br /&gt;
    if (range.hasOwnProperty(category)) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
    const init = { min: Number(filter.min), max: Number(filter.max) };&lt;br /&gt;
    range[category] = { init: init };&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function extractInitData(card, cardData) {&lt;br /&gt;
  const cardNameElement = card.querySelector(&amp;quot;[data-name]&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  cardData.card = card;&lt;br /&gt;
  cardData.name = toNormalForm(cardNameElement.textContent);&lt;br /&gt;
  cardData.trueName = cardNameElement.firstChild.title;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function extractLevelData(card, cardData) {&lt;br /&gt;
  const levelElement = card.querySelector(&amp;quot;[data-level]&amp;quot;);&lt;br /&gt;
  const [level, rank] = levelElement.textContent.slice(1, -1).split(&amp;quot;, &amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  cardData[&amp;quot;level&amp;quot;] = Number(level);&lt;br /&gt;
  cardData[&amp;quot;rank&amp;quot;] = removeAccent(rank);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function extractElementData(card, cardData) {&lt;br /&gt;
  const elementChild = card.querySelector(&amp;quot;[data-elem]&amp;quot;).children;&lt;br /&gt;
  let elementValue = &amp;quot;&amp;quot;;&lt;br /&gt;
  if (elementChild.length) {&lt;br /&gt;
    for (&lt;br /&gt;
      let elementIndex = 0;&lt;br /&gt;
      elementIndex &amp;lt; elementChild.length;&lt;br /&gt;
      elementIndex++&lt;br /&gt;
    ) {&lt;br /&gt;
      elementValue += elementChild[elementIndex].title + &amp;quot; &amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  elementValue = elementValue.trim() || &amp;quot;Aucun&amp;quot;;&lt;br /&gt;
  cardData.elem = removeAccent(elementValue);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function extractTypeData(card, cardData) {&lt;br /&gt;
  const typeElement = card.querySelector(&amp;quot;[data-type]&amp;quot;);&lt;br /&gt;
  cardData.type = removeAccent(typeElement.textContent.split(&amp;quot; &amp;quot;)[0]);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function extractDamageData(card, cardData) {&lt;br /&gt;
  const damageElement = card.querySelector(&amp;quot;[data-damage]&amp;quot;);&lt;br /&gt;
  cardData.damage = removeAccent(damageElement.textContent.replace(&amp;quot; + &amp;quot;, &amp;quot; &amp;quot;));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function extractLocData(card, cardData) {&lt;br /&gt;
  const locElement = card.querySelector(&amp;quot;[data-loc]&amp;quot;);&lt;br /&gt;
  cardData.loc = locElement.dataset.loc;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getCardsData(cardsContainer, filterData, dataExtractionMapping) {&lt;br /&gt;
  const cards = cardsContainer.children;&lt;br /&gt;
  const activeExtractors = [extractInitData];&lt;br /&gt;
&lt;br /&gt;
  for (const [key, extractorFunction] of Object.entries(&lt;br /&gt;
    dataExtractionMapping&lt;br /&gt;
  )) {&lt;br /&gt;
    if (&lt;br /&gt;
      filterData.range.hasOwnProperty(key) ||&lt;br /&gt;
      filterData.checkbox.hasOwnProperty(key)&lt;br /&gt;
    ) {&lt;br /&gt;
      activeExtractors.push(extractorFunction);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  const cardsData = [];&lt;br /&gt;
&lt;br /&gt;
  for (let cardIndex = 0; cardIndex &amp;lt; cards.length; cardIndex++) {&lt;br /&gt;
    const card = cards[cardIndex];&lt;br /&gt;
    const cardData = {};&lt;br /&gt;
&lt;br /&gt;
    for (const extractor of activeExtractors) {&lt;br /&gt;
      extractor(card, cardData);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    cardsData.push(cardData);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return cardsData;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterInitialization(filterForm) {&lt;br /&gt;
  const filterData = {&lt;br /&gt;
    form: filterForm,&lt;br /&gt;
    filters: { filterName: &amp;quot;&amp;quot;, filter: {}, rangeFilter: {} },&lt;br /&gt;
    range: {},&lt;br /&gt;
    checkbox: {},&lt;br /&gt;
    reverse: false,&lt;br /&gt;
    filterCounter: {&lt;br /&gt;
      count: 0,&lt;br /&gt;
      span: document.getElementById(&amp;quot;filter-counter&amp;quot;),&lt;br /&gt;
    }&lt;br /&gt;
  };&lt;br /&gt;
  const filters = filterForm.querySelectorAll(&amp;quot;[data-filter]&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  filters.forEach((filter) =&amp;gt; fillData(filter, filterData));&lt;br /&gt;
&lt;br /&gt;
  return filterData;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function displayCounterValue(checkbox) {&lt;br /&gt;
  for (let filterCategory in checkbox) {&lt;br /&gt;
    const category = checkbox[filterCategory];&lt;br /&gt;
&lt;br /&gt;
    for (let filterValue in category) {&lt;br /&gt;
      const valueData = category[filterValue];&lt;br /&gt;
&lt;br /&gt;
      valueData.span.textContent = &amp;quot; (&amp;quot; + valueData.value + &amp;quot;)&amp;quot;;&lt;br /&gt;
      valueData.value = 0;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateCounter(cardData, checkbox, filterCategory) {&lt;br /&gt;
  cardData[filterCategory].split(&amp;quot; &amp;quot;).forEach((cardValue) =&amp;gt; {&lt;br /&gt;
    checkbox[filterCategory][cardValue].value += 1;&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isObjectValuesInRangeFilter(parameters, rangeFilter) {&lt;br /&gt;
  return Object.entries(rangeFilter).every(&lt;br /&gt;
    ([property, { min, max }]) =&amp;gt;&lt;br /&gt;
      parameters[property] &amp;gt;= min &amp;amp;&amp;amp; parameters[property] &amp;lt;= max&lt;br /&gt;
  );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterByName(parameters, filterName) {&lt;br /&gt;
  if (filterName) {&lt;br /&gt;
    return parameters.name.includes(filterName);&lt;br /&gt;
  }&lt;br /&gt;
  return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isObjectValuesInFilter(parameters, filter) {&lt;br /&gt;
  return Object.entries(filter).every(([property, values]) =&amp;gt;&lt;br /&gt;
    parameters[property].split(&amp;quot; &amp;quot;).some((value) =&amp;gt; values.includes(value))&lt;br /&gt;
  );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isObjectValuesInFilters(parameters, filter, rangeFilter, filterName) {&lt;br /&gt;
  return (&lt;br /&gt;
    isObjectValuesInFilter(parameters, filter) &amp;amp;&amp;amp;&lt;br /&gt;
    filterByName(parameters, filterName) &amp;amp;&amp;amp;&lt;br /&gt;
    isObjectValuesInRangeFilter(parameters, rangeFilter)&lt;br /&gt;
  );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterCards(cardsContainer, filterData, cardsData) {&lt;br /&gt;
  const { filters, checkbox, filterCounter } = filterData;&lt;br /&gt;
  const { filter, rangeFilter, filterName } = filters;&lt;br /&gt;
&lt;br /&gt;
  if (filterData.reverse) {&lt;br /&gt;
    for (&lt;br /&gt;
      let reverseIndex = 1;&lt;br /&gt;
      reverseIndex &amp;lt; cardsData.length;&lt;br /&gt;
      reverseIndex++&lt;br /&gt;
    ) {&lt;br /&gt;
      cardsContainer.insertBefore(&lt;br /&gt;
        cardsData[reverseIndex].card,&lt;br /&gt;
        cardsContainer.firstChild&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
    cardsData.reverse();&lt;br /&gt;
    filterData.reverse = false;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (let cardIndex = 0; cardIndex &amp;lt; cardsData.length; cardIndex++) {&lt;br /&gt;
    const cardData = cardsData[cardIndex];&lt;br /&gt;
&lt;br /&gt;
    if (isObjectValuesInFilters(cardData, filter, rangeFilter, filterName)) {&lt;br /&gt;
      showElement(cardData.card);&lt;br /&gt;
      for (let filterCategory in checkbox) {&lt;br /&gt;
        updateCounter(cardData, checkbox, filterCategory);&lt;br /&gt;
      }&lt;br /&gt;
    } else {&lt;br /&gt;
      hideElement(cardData.card);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  displayCounterValue(checkbox);&lt;br /&gt;
  updateFilterCounter(filterCounter);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleCheckbox(target, filter, filterCounter) {&lt;br /&gt;
  const { filter: category, value } = target.dataset;&lt;br /&gt;
&lt;br /&gt;
  if (target.checked) {&lt;br /&gt;
    filter[category] = filter[category] || [];&lt;br /&gt;
    filter[category].push(value);&lt;br /&gt;
    filterCounter.count += 1;&lt;br /&gt;
  } else {&lt;br /&gt;
    const index = filter[category].indexOf(value);&lt;br /&gt;
    if (index !== -1) {&lt;br /&gt;
      filter[category].splice(index, 1);&lt;br /&gt;
    }&lt;br /&gt;
    if (!filter[category].length) {&lt;br /&gt;
      delete filter[category];&lt;br /&gt;
    }&lt;br /&gt;
    filterCounter.count -= 1;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleNumberType(target, rangeFilter, range, filterCounter) {&lt;br /&gt;
  const { filter: category, value: extremum } = target.dataset;&lt;br /&gt;
  const currentValue = Number(target.value);&lt;br /&gt;
  const initialRange = range[category].init;&lt;br /&gt;
&lt;br /&gt;
  if (rangeFilter[category]) {&lt;br /&gt;
    rangeFilter[category][extremum] = currentValue;&lt;br /&gt;
  } else {&lt;br /&gt;
    rangeFilter[category] = {&lt;br /&gt;
      min: initialRange.min,&lt;br /&gt;
      max: initialRange.max,&lt;br /&gt;
    };&lt;br /&gt;
    rangeFilter[category][extremum] = currentValue;&lt;br /&gt;
    filterCounter.count += 1;&lt;br /&gt;
  }&lt;br /&gt;
  if (&lt;br /&gt;
    rangeFilter[category].max === initialRange.max &amp;amp;&amp;amp;&lt;br /&gt;
    rangeFilter[category].min === initialRange.min&lt;br /&gt;
  ) {&lt;br /&gt;
    delete rangeFilter[category];&lt;br /&gt;
    filterCounter.count -= 1;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateFilterCounter(filterCounter) {&lt;br /&gt;
  if (filterCounter.count) {&lt;br /&gt;
    filterCounter.span.textContent = `(${filterCounter.count})`;&lt;br /&gt;
  } else {&lt;br /&gt;
    filterCounter.span.textContent = &amp;quot;&amp;quot;;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleFormEvents(cardsContainer, filterForm, filterData, cardsData) {&lt;br /&gt;
  const { filters, range, filterCounter } = filterData;&lt;br /&gt;
  let debounceTimer;&lt;br /&gt;
&lt;br /&gt;
  filterForm.addEventListener(&amp;quot;submit&amp;quot;, function (event) {&lt;br /&gt;
    event.preventDefault();&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  filterForm.addEventListener(&amp;quot;change&amp;quot;, updateFilter);&lt;br /&gt;
&lt;br /&gt;
  filterForm.addEventListener(&amp;quot;input&amp;quot;, function (event) {&lt;br /&gt;
    clearTimeout(debounceTimer);&lt;br /&gt;
    debounceTimer = setTimeout(() =&amp;gt; {&lt;br /&gt;
      if (event.target.id === &amp;quot;filter-name&amp;quot;) {&lt;br /&gt;
        updateFilter(event, true);&lt;br /&gt;
      }&lt;br /&gt;
    }, 500);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  function updateFilter(event, filterByName = false) {&lt;br /&gt;
    const target = event.target;&lt;br /&gt;
    const targetType = target.type;&lt;br /&gt;
&lt;br /&gt;
    if (filterByName) {&lt;br /&gt;
      filters.filterName = toNormalForm(target.value);&lt;br /&gt;
    } else if (targetType === &amp;quot;checkbox&amp;quot;) {&lt;br /&gt;
      handleCheckbox(target, filters.filter, filterCounter);&lt;br /&gt;
    } else if (targetType === &amp;quot;number&amp;quot;) {&lt;br /&gt;
      handleNumberType(target, filters.rangeFilter, range, filterCounter);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    filterCards(cardsContainer, filterData, cardsData);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function processUrlParameter(filterName, filterData, key, value) {&lt;br /&gt;
  const { filters, filterCounter } = filterData;&lt;br /&gt;
&lt;br /&gt;
  if (key === &amp;quot;name&amp;quot;) {&lt;br /&gt;
    filterName.value = toNormalForm(value);&lt;br /&gt;
    filters.filterName = value;&lt;br /&gt;
  } else if (Object.keys(filterData.checkbox).indexOf(key) !== -1) {&lt;br /&gt;
    const checkboxElement = document.getElementById(key + &amp;quot;-&amp;quot; + value);&lt;br /&gt;
&lt;br /&gt;
    if (!checkboxElement) return;&lt;br /&gt;
&lt;br /&gt;
    checkboxElement.checked = true;&lt;br /&gt;
    filters.filter[key] = filters.filter[key] || [];&lt;br /&gt;
    filters.filter[key].push(value);&lt;br /&gt;
    filterCounter.count += 1;&lt;br /&gt;
  } else if (key === &amp;quot;reverse&amp;quot;) {&lt;br /&gt;
    if (value === &amp;quot;1&amp;quot;) {&lt;br /&gt;
      filterData.reverse = true;&lt;br /&gt;
      const reverseElement = document.getElementById(&amp;quot;filter-reverse&amp;quot;);&lt;br /&gt;
      if (reverseElement) {&lt;br /&gt;
        reverseElement.checked = true;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    const [splitKey, extremum] = key.split(&amp;quot;-&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (Object.keys(filterData.range).indexOf(splitKey) !== -1) {&lt;br /&gt;
      const rangeElement = document.getElementById(key);&lt;br /&gt;
&lt;br /&gt;
      if (!rangeElement) return;&lt;br /&gt;
&lt;br /&gt;
      rangeElement.value = value;&lt;br /&gt;
&lt;br /&gt;
      const rangeData = filterData.range[splitKey];&lt;br /&gt;
      const rangeFilter = filters.rangeFilter;&lt;br /&gt;
&lt;br /&gt;
      if (rangeFilter[splitKey]) {&lt;br /&gt;
        rangeFilter[splitKey][extremum] = value;&lt;br /&gt;
      } else {&lt;br /&gt;
        rangeFilter[splitKey] = {&lt;br /&gt;
          min: rangeData.init.min,&lt;br /&gt;
          max: rangeData.init.max,&lt;br /&gt;
        };&lt;br /&gt;
        rangeFilter[splitKey][extremum] = value;&lt;br /&gt;
        filterCounter.count += 1;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterWithUrl(filterName, filterData) {&lt;br /&gt;
  const url = new URL(window.location.href);&lt;br /&gt;
  const { hash, search } = url;&lt;br /&gt;
  let useParams = true;&lt;br /&gt;
&lt;br /&gt;
  if (hash) {&lt;br /&gt;
    const start = &amp;quot;.3F&amp;quot;;&lt;br /&gt;
    const equal = &amp;quot;.3D&amp;quot;;&lt;br /&gt;
    const and = &amp;quot;.26&amp;quot;;&lt;br /&gt;
    const startParametersIndex = hash.indexOf(start);&lt;br /&gt;
&lt;br /&gt;
    if (startParametersIndex !== -1) {&lt;br /&gt;
      const parameters = hash.slice(startParametersIndex + start.length);&lt;br /&gt;
&lt;br /&gt;
      parameters.split(and).forEach(function (keyValue) {&lt;br /&gt;
        const [key, value] = keyValue.split(equal);&lt;br /&gt;
        processUrlParameter(filterName, filterData, key, value);&lt;br /&gt;
      });&lt;br /&gt;
&lt;br /&gt;
      useParams = false;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (useParams) {&lt;br /&gt;
    const URLparams = new URLSearchParams(search);&lt;br /&gt;
&lt;br /&gt;
    for (const [key, value] of URLparams.entries()) {&lt;br /&gt;
      processUrlParameter(filterName, filterData, key, value);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function main_filter() {&lt;br /&gt;
  const filterForm = document.getElementById(&amp;quot;filter-form&amp;quot;);&lt;br /&gt;
  const filterName = document.getElementById(&amp;quot;filter-name&amp;quot;);&lt;br /&gt;
  const cardsContainer = document.getElementById(&amp;quot;cards-container&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  const dataExtractionMapping = {&lt;br /&gt;
    level: extractLevelData,&lt;br /&gt;
    elem: extractElementData,&lt;br /&gt;
    type: extractTypeData,&lt;br /&gt;
    damage: extractDamageData,&lt;br /&gt;
    loc: extractLocData&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  const filterData = filterInitialization(filterForm);&lt;br /&gt;
  const cardsData = getCardsData(&lt;br /&gt;
    cardsContainer,&lt;br /&gt;
    filterData,&lt;br /&gt;
    dataExtractionMapping&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  observeLanguageChange(filterName, cardsData);&lt;br /&gt;
  openFilter();&lt;br /&gt;
  filterWithUrl(filterName, filterData);&lt;br /&gt;
  filterCards(cardsContainer, filterData, cardsData);&lt;br /&gt;
  handleFormEvents(cardsContainer, filterForm, filterData, cardsData);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
main_filter();&lt;/div&gt;</summary>
		<author><name>Dexter</name></author>
		
	</entry>
	<entry>
		<id>https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Common.css&amp;diff=105978</id>
		<title>MediaWiki:Common.css</title>
		<link rel="alternate" type="text/html" href="https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Common.css&amp;diff=105978"/>
		<updated>2024-12-23T20:04:48Z</updated>

		<summary type="html">&lt;p&gt;Dexter : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;/* Le CSS placé ici sera chargé sur toutes les pages */&lt;br /&gt;
&lt;br /&gt;
html {&lt;br /&gt;
  scroll-behavior: smooth;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
  body {&lt;br /&gt;
    background-image: url('https://fr-wiki.metin2.gameforge.com/images/b/bf/Fondhalloween.png');&lt;br /&gt;
  }&lt;br /&gt;
  */&lt;br /&gt;
&lt;br /&gt;
body {&lt;br /&gt;
  background-image: url(&amp;quot;https://fr-wiki.metin2.gameforge.com/images/1/15/Fond2015.jpg&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#mw-content ul {&lt;br /&gt;
  margin-bottom: 0.3em;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#mw-content ol {&lt;br /&gt;
  list-style: none;&lt;br /&gt;
  counter-reset: custom-counter;&lt;br /&gt;
  margin: 0.3em 0 0.3em 1.6em;&lt;br /&gt;
  padding: 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
ol li {&lt;br /&gt;
  padding: 0;&lt;br /&gt;
  counter-increment: custom-counter;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
ol li::marker {&lt;br /&gt;
  content: counter(custom-counter) &amp;quot;.  &amp;quot;;&lt;br /&gt;
  font-weight: bold;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
td,&lt;br /&gt;
th {&lt;br /&gt;
  padding: 2px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.map span.mw-collapsible-toggle {&lt;br /&gt;
  padding-right: 10px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
table.map a.mw-collapsible-text,&lt;br /&gt;
.prettytable &amp;gt; span.mw-collapsible-toggle,&lt;br /&gt;
.prettytable &amp;gt; span.mw-collapsible-toggle &amp;gt; a {&lt;br /&gt;
  color: #ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.boxesheaderbackground,&lt;br /&gt;
.cadre &amp;gt; div:first-child {&lt;br /&gt;
  background: repeat&lt;br /&gt;
    url(&amp;quot;https://fr-wiki.metin2.gameforge.com/images/a/a7/Boxheaderbrown.png&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.cadre {&lt;br /&gt;
  border: 1px solid #2f1d1f;&lt;br /&gt;
  border-radius: 15px 0;&lt;br /&gt;
  width: 100%;&lt;br /&gt;
  box-shadow: 3px 3px 9px 0px #544e41;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.cadre &amp;gt; div:first-child {&lt;br /&gt;
  text-align: center;&lt;br /&gt;
  color: white;&lt;br /&gt;
  line-height: 25px;&lt;br /&gt;
  overflow: hidden;&lt;br /&gt;
  border-top-left-radius: 15px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.fondfenetre,&lt;br /&gt;
.sous-titre,&lt;br /&gt;
table.pretty-table th {&lt;br /&gt;
  background: url(&amp;quot;https://fr-wiki.metin2.gameforge.com/images/8/89/Fondfenetre.png&amp;quot;)&lt;br /&gt;
    repeat;&lt;br /&gt;
  color: white;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
table.pretty-table td {&lt;br /&gt;
  padding: 5px 10px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
table.pretty-table th {&lt;br /&gt;
  padding: 2px 10px;&lt;br /&gt;
  font-weight: normal;&lt;br /&gt;
  font-size: 1.1em;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
table.pretty-table tbody &amp;gt; *:nth-child(2n + 1) &amp;gt; td {&lt;br /&gt;
  background: rgba(0, 0, 0, 0.1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
table.pretty-table tr:hover {&lt;br /&gt;
  background: rgba(0, 0, 0, 0.05);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
table.pretty-table tr:first-child &amp;gt; th:first-child {&lt;br /&gt;
  border-radius: 8px 0 0 0;&lt;br /&gt;
  overflow: hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
table.pretty-table caption {&lt;br /&gt;
  margin-top: 10px;&lt;br /&gt;
  font-weight: bold;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.fondfenetre a,&lt;br /&gt;
.fondfenetre span,&lt;br /&gt;
table.pretty-table th a,&lt;br /&gt;
table.pretty-table th span {&lt;br /&gt;
  color: white;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
table.sticky-header-row thead tr {&lt;br /&gt;
  position: sticky;&lt;br /&gt;
  top: 0;&lt;br /&gt;
  z-index: 10;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
table.sticky-header-column th:first-child {&lt;br /&gt;
  position: sticky;&lt;br /&gt;
  left: 0;&lt;br /&gt;
  z-index: 20;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sous-titre {&lt;br /&gt;
  max-width: 180px;&lt;br /&gt;
  border: 1px solid black;&lt;br /&gt;
  border-radius: 8px;&lt;br /&gt;
  color: white;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.modeleAnnonce {&lt;br /&gt;
  border-image: url(&amp;quot;https://fr-wiki.metin2.gameforge.com/images/f/fb/Modeleannonce.png&amp;quot;)&lt;br /&gt;
    17 35 3 fill / auto / 0 repeat;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.container {&lt;br /&gt;
  display: flex;&lt;br /&gt;
  flex-direction: row;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.monster-card {&lt;br /&gt;
  border: 1px black solid;&lt;br /&gt;
  padding: 5px;&lt;br /&gt;
  max-width: 400px;&lt;br /&gt;
  box-sizing: border-box;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.monster-card &amp;gt; :first-child {&lt;br /&gt;
  display: flex;&lt;br /&gt;
  justify-content: space-between;&lt;br /&gt;
  margin-bottom: 5px;&lt;br /&gt;
  line-height: 25px;&lt;br /&gt;
  padding: 0 5px;&lt;br /&gt;
  background: none;&lt;br /&gt;
  background-color: black;&lt;br /&gt;
  color: white;&lt;br /&gt;
  white-space: nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.monster-card &amp;gt; :first-child a {&lt;br /&gt;
  color: white;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.monster-card &amp;gt; :nth-child(2) {&lt;br /&gt;
  display: flex;&lt;br /&gt;
  justify-content: space-between;&lt;br /&gt;
  margin-bottom: 5px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.monster-card &amp;gt; :nth-child(3) {&lt;br /&gt;
  background: rgba(0, 0, 0, 0.1);&lt;br /&gt;
  display: grid;&lt;br /&gt;
  justify-content: center;&lt;br /&gt;
  align-items: start;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
button.brown {&lt;br /&gt;
  background: #651e10;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
button.brown-transparent {&lt;br /&gt;
  background: #651e10cc;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
button.brown:hover,&lt;br /&gt;
button.brown:focus {&lt;br /&gt;
  background: #551a0e;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
button.red {&lt;br /&gt;
  background: #ef4444;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
button.red:hover,&lt;br /&gt;
button.red:focus {&lt;br /&gt;
  background: #b91c1c;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
button:active {&lt;br /&gt;
  opacity: 0.8;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.button {&lt;br /&gt;
  border: 2px solid grey;&lt;br /&gt;
  padding: 0 12px;&lt;br /&gt;
  line-height: 25px;&lt;br /&gt;
  border-radius: 16px;&lt;br /&gt;
  background: rgba(234, 234, 234);&lt;br /&gt;
  cursor: pointer;&lt;br /&gt;
  display: inline-block;&lt;br /&gt;
  position: relative;&lt;br /&gt;
  user-select: none;&lt;br /&gt;
  white-space: nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.button:hover {&lt;br /&gt;
  background: transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.modal {&lt;br /&gt;
  opacity: 0;&lt;br /&gt;
  visibility: hidden;&lt;br /&gt;
  transform: scale(1.1);&lt;br /&gt;
  transition: visibility 0s linear 0.25s, opacity 0.25s 0s, transform 0.25s;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.close-button {&lt;br /&gt;
  transition: color 0.2s linear, background-color 0.2s linear;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.close-button:hover {&lt;br /&gt;
  background-color: red;&lt;br /&gt;
  color: #ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.show-modal {&lt;br /&gt;
  opacity: 1;&lt;br /&gt;
  visibility: visible;&lt;br /&gt;
  transform: scale(1);&lt;br /&gt;
  transition: visibility 0s linear 0s, opacity 0.25s 0s, transform 0.25s;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.cacheOrdi,&lt;br /&gt;
.gen-active {&lt;br /&gt;
  display: block;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.texte-long,&lt;br /&gt;
.texte-long-2 {&lt;br /&gt;
  text-overflow: ellipsis;&lt;br /&gt;
  white-space: nowrap;&lt;br /&gt;
  overflow: hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.texte-long:hover,&lt;br /&gt;
.texte-long-2:hover {&lt;br /&gt;
  white-space: normal;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.shop-img img {&lt;br /&gt;
  height: auto;&lt;br /&gt;
  width: auto;&lt;br /&gt;
  max-height: 130px;&lt;br /&gt;
  max-width: 130px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#mw-content .soulignement &amp;gt; a:link {&lt;br /&gt;
  text-decoration: none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.popContenu {&lt;br /&gt;
  display: inline-block;&lt;br /&gt;
  transition: all 0.4s ease;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.popInfo:hover .popContenu {&lt;br /&gt;
  opacity: 1 !important;&lt;br /&gt;
  transition: all 0.4s ease;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.cadreFenetre {&lt;br /&gt;
  border: solid;&lt;br /&gt;
  border-image: url(&amp;quot;https://fr-wiki.metin2.gameforge.com/images/1/11/Cadrefenetre.png&amp;quot;)&lt;br /&gt;
    11 fill / auto / 0 repeat;&lt;br /&gt;
  padding: 10px;&lt;br /&gt;
  backdrop-filter: blur(4px);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tabber-active.button {&lt;br /&gt;
  background: rgba(75, 85, 95);&lt;br /&gt;
  color: white;&lt;br /&gt;
  border: 2px solid rgba(75, 85, 95);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
ul.subpage {&lt;br /&gt;
  display: flex;&lt;br /&gt;
  list-style: none;&lt;br /&gt;
  margin: 0 0 10px;&lt;br /&gt;
  padding: 0;&lt;br /&gt;
  background: rgba(81, 36, 16, 0.3);&lt;br /&gt;
  overflow: hidden;&lt;br /&gt;
  line-height: 30px;&lt;br /&gt;
  white-space: nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.subpage a {&lt;br /&gt;
  padding-left: 20px;&lt;br /&gt;
  background: #512410;&lt;br /&gt;
  display: inline-block;&lt;br /&gt;
  line-height: 30px;&lt;br /&gt;
  position: relative;&lt;br /&gt;
  color: #f1de8e;&lt;br /&gt;
  cursor: pointer;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.subpage a:before,&lt;br /&gt;
.subpage a:after {&lt;br /&gt;
  content: &amp;quot;&amp;quot;;&lt;br /&gt;
  position: absolute;&lt;br /&gt;
  width: 0;&lt;br /&gt;
  height: 0;&lt;br /&gt;
  right: 0;&lt;br /&gt;
  padding: 1px 0;&lt;br /&gt;
  border-top: 14px solid transparent;&lt;br /&gt;
  border-bottom: 14px solid transparent;&lt;br /&gt;
  border-left: 14px solid white;&lt;br /&gt;
  transform: translate(14px);&lt;br /&gt;
  z-index: 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.subpage a:after {&lt;br /&gt;
  border-left: 14px solid #512410;&lt;br /&gt;
  transform: translate(13px);&lt;br /&gt;
  z-index: 2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.subpage &amp;gt; li:last-child {&lt;br /&gt;
  padding-left: 20px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
ul.subpage &amp;gt; li:first-child {&lt;br /&gt;
  flex-shrink: 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
ul.subpage &amp;gt; li:first-child &amp;gt; a {&lt;br /&gt;
  height: 100%;&lt;br /&gt;
  display: flex;&lt;br /&gt;
  align-items: center;&lt;br /&gt;
  padding-left: 10px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
ul.subpage &amp;gt; li &amp;gt; a:hover {&lt;br /&gt;
  background: #9d5b37;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
ul.subpage &amp;gt; li &amp;gt; a:hover:after {&lt;br /&gt;
  border-left-color: #9d5b37;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.image-sizing img,&lt;br /&gt;
.image-sizing-200 img,&lt;br /&gt;
.image-sizing-none img {&lt;br /&gt;
  height: auto;&lt;br /&gt;
  width: auto;&lt;br /&gt;
  max-height: 300px;&lt;br /&gt;
  max-width: 100%;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.image-sizing-200 img {&lt;br /&gt;
  max-height: 200px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.image-sizing-none img {&lt;br /&gt;
  max-height: none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
div.ul-res ul {&lt;br /&gt;
  margin: 0;&lt;br /&gt;
  list-style: none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tab-glob {&lt;br /&gt;
  display: flex;&lt;br /&gt;
  flex-direction: row;&lt;br /&gt;
  margin: 10px 0;&lt;br /&gt;
  column-gap: 2px;&lt;br /&gt;
  align-items: flex-start;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tab-glob &amp;gt; :first-child {&lt;br /&gt;
  display: grid;&lt;br /&gt;
  grid-template-columns: max-content;&lt;br /&gt;
  row-gap: 2px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tab-glob &amp;gt; :first-child &amp;gt; * {&lt;br /&gt;
  border: 1px black solid;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tab-glob &amp;gt; :first-child &amp;gt; *:not(.fondfenetre) {&lt;br /&gt;
  font-weight: bold;&lt;br /&gt;
  display: flex;&lt;br /&gt;
  justify-content: center;&lt;br /&gt;
  align-items: center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tab-glob &amp;gt; :nth-child(2) {&lt;br /&gt;
  width: 100%;&lt;br /&gt;
  overflow-x: auto;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tab-glob &amp;gt; :nth-child(2) &amp;gt; :first-child {&lt;br /&gt;
  display: grid;&lt;br /&gt;
  grid-template-columns: repeat(10, minmax(75px, 1fr));&lt;br /&gt;
  gap: 2px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tab-glob &amp;gt; :nth-child(2) &amp;gt; :first-child &amp;gt; * {&lt;br /&gt;
  border: 1px black solid;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tab-glob &amp;gt; :nth-child(2) &amp;gt; :first-child &amp;gt; :not(.fondfenetre) {&lt;br /&gt;
  display: flex;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tab-glob &amp;gt; :nth-child(2) &amp;gt; :first-child &amp;gt; :not(.fondfenetre) &amp;gt; * {&lt;br /&gt;
  margin: auto;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.list-equip {&lt;br /&gt;
  padding: 5px;&lt;br /&gt;
  border: 1px solid #2f1d1f;&lt;br /&gt;
  display: flex;&lt;br /&gt;
  flex-direction: column;&lt;br /&gt;
  align-items: center;&lt;br /&gt;
  gap: 5px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.list-equip &amp;gt; :first-child {&lt;br /&gt;
  width: 100%;&lt;br /&gt;
  line-height: 25px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.list-equip &amp;gt; :first-child &amp;gt; * {&lt;br /&gt;
  padding: 0 5px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.fabrication {&lt;br /&gt;
  position: relative;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.fabrication &amp;gt; * {&lt;br /&gt;
  position: absolute;&lt;br /&gt;
  top: -188px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.fabrication &amp;gt; .bottom-fab,&lt;br /&gt;
.fabrication &amp;gt; .bottom-fab ~ * {&lt;br /&gt;
  top: -58px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.fabrication &amp;gt; * &amp;gt; *:nth-child(2) {&lt;br /&gt;
  position: relative;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.fabrication &amp;gt; * &amp;gt; *:nth-child(2) &amp;gt; * {&lt;br /&gt;
  position: absolute;&lt;br /&gt;
  top: -18px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.fabrication &amp;gt; * &amp;gt; *:nth-child(n + 3) {&lt;br /&gt;
  position: absolute;&lt;br /&gt;
  top: 100px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.info-boutique ul {&lt;br /&gt;
  list-style-image: none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.info-boutique p:last-child {&lt;br /&gt;
  margin-bottom: 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
kbd {&lt;br /&gt;
  background-color: #eee;&lt;br /&gt;
  border-radius: 3px;&lt;br /&gt;
  border: 1px solid #b4b4b4;&lt;br /&gt;
  box-shadow: 0 1px 1px rgb(0 0 0 / 20%), 0 2px 0 0 rgb(255 255 255 / 70%) inset;&lt;br /&gt;
  color: #333;&lt;br /&gt;
  display: inline-block;&lt;br /&gt;
  font-size: 0.85em;&lt;br /&gt;
  font-weight: 700;&lt;br /&gt;
  line-height: 1;&lt;br /&gt;
  padding: 2px 4px;&lt;br /&gt;
  white-space: nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.top-button {&lt;br /&gt;
  display: flex;&lt;br /&gt;
  justify-content: center;&lt;br /&gt;
  align-items: center;&lt;br /&gt;
  opacity: 0;&lt;br /&gt;
  cursor: pointer;&lt;br /&gt;
  position: fixed;&lt;br /&gt;
  bottom: 10px;&lt;br /&gt;
  right: 10px;&lt;br /&gt;
  width: 32px;&lt;br /&gt;
  height: 32px;&lt;br /&gt;
  background: linear-gradient(&lt;br /&gt;
    180deg,&lt;br /&gt;
    rgba(124, 200, 65, 1) 0%,&lt;br /&gt;
    rgba(113, 161, 85, 1) 50%,&lt;br /&gt;
    rgba(64, 117, 39, 1) 50%,&lt;br /&gt;
    rgba(46, 97, 31, 1) 100%&lt;br /&gt;
  );&lt;br /&gt;
  border: 1px solid #d0af52;&lt;br /&gt;
  box-shadow: 1px 1px 2px #000, inset 1px 1px #090200, inset -1px -1px #090200;&lt;br /&gt;
  transform: translateY(100px);&lt;br /&gt;
  transition: all 0.5s ease;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.top-button:after {&lt;br /&gt;
  content: &amp;quot;&amp;quot;;&lt;br /&gt;
  height: 32px;&lt;br /&gt;
  width: 32px;&lt;br /&gt;
  background-image: url(&amp;quot;data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fffacb' height='32' viewBox='0 -960 960 960' width='32'%3E%3Cpath d='m296-345-56-56 240-240 240 240-56 56-184-184-184 184Z'/%3E%3C/svg%3E&amp;quot;);&lt;br /&gt;
  background-repeat: no-repeat;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.show-button {&lt;br /&gt;
  opacity: 1;&lt;br /&gt;
  transform: translateY(0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.ul-row ul {&lt;br /&gt;
  display: flex;&lt;br /&gt;
  column-gap: 30px;&lt;br /&gt;
  flex-wrap: wrap;&lt;br /&gt;
  overflow: hidden;&lt;br /&gt;
  margin: 0;&lt;br /&gt;
  list-style-image: none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.flex {&lt;br /&gt;
  display: flex;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#catlinks {&lt;br /&gt;
  margin-top: 10px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.improved-collapsible &amp;gt; .mw-collapsible-toggle {&lt;br /&gt;
  grid-area: 1 / -1;&lt;br /&gt;
  display: flex;&lt;br /&gt;
  justify-content: flex-end;&lt;br /&gt;
  align-items: center;&lt;br /&gt;
  float: initial;&lt;br /&gt;
  z-index: 1;&lt;br /&gt;
  padding-right: 5px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.improved-collapsible .mw-collapsible-toggle:before {&lt;br /&gt;
  content: &amp;quot;&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.improved-collapsible .mw-collapsible-text {&lt;br /&gt;
  display: none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.improved-collapsible .mw-collapsible-toggle:after {&lt;br /&gt;
  width: 32px;&lt;br /&gt;
  height: 32px;&lt;br /&gt;
  content: &amp;quot;&amp;quot;;&lt;br /&gt;
  background-image: url(&amp;quot;data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23000000' height='32' viewBox='0 -960 960 960' width='32'%3E%3Cpath d='M480-345 240-585l56-56 184 184 184-184 56 56-240 240Z'/%3E%3C/svg%3E&amp;quot;);&lt;br /&gt;
  background-repeat: no-repeat;&lt;br /&gt;
  transition: transform 0.2s ease-in-out;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.improved-collapsible .mw-collapsible-toggle-expanded:after {&lt;br /&gt;
  transform: rotate(-180deg);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tooltip-icon {&lt;br /&gt;
  background-image: url(&amp;quot;data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' height='24' viewBox='0 -960 960 960' width='24'%3E%3Cpath d='M443-285h75v-234h-75v234Zm36.895-311Q496-596 507-606.895q11-10.894 11-27Q518-650 507.105-661q-10.894-11-27-11Q464-672 453-661.105q-11 10.894-11 27Q442-618 452.895-607q10.894 11 27 11ZM480-90q-80.907 0-152.065-30.763-71.159-30.763-123.797-83.5Q151.5-257 120.75-328.087 90-399.175 90-480q0-80.907 30.763-152.065 30.763-71.159 83.5-123.797Q257-808.5 328.087-839.25 399.175-870 480-870q80.907 0 152.065 30.763 71.159 30.763 123.797 83.5Q808.5-703 839.25-631.913 870-560.825 870-480q0 80.907-30.763 152.065-30.763 71.159-83.5 123.797Q703-151.5 631.913-120.75 560.825-90 480-90Zm0-75q131.5 0 223.25-91.75T795-480q0-131.5-91.75-223.25T480-795q-131.5 0-223.25 91.75T165-480q0 131.5 91.75 223.25T480-165Zm0-315Z'/%3E%3C/svg%3E&amp;quot;);&lt;br /&gt;
  background-repeat: no-repeat;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tooltip-info {&lt;br /&gt;
  position: absolute;&lt;br /&gt;
  bottom: calc(100% + 8px);&lt;br /&gt;
  left: 50%;&lt;br /&gt;
  transform: translateX(-50%);&lt;br /&gt;
  max-width: 290px;&lt;br /&gt;
  width: max-content;&lt;br /&gt;
  z-index: 50;&lt;br /&gt;
  opacity: 0;&lt;br /&gt;
  visibility: hidden;&lt;br /&gt;
  transition: opacity 0.2s ease, visibility 0.2s ease;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tooltip-info:after {&lt;br /&gt;
  content: &amp;quot;&amp;quot;;&lt;br /&gt;
  border: 8px solid transparent;&lt;br /&gt;
  border-top-color: inherit;&lt;br /&gt;
  position: absolute;&lt;br /&gt;
  left: calc(50% - 8px);&lt;br /&gt;
  top: 100%;&lt;br /&gt;
  z-index: 50;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tooltip-icon:hover &amp;gt; .tooltip-info {&lt;br /&gt;
  opacity: 1;&lt;br /&gt;
  visibility: visible;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
input,&lt;br /&gt;
input[type=&amp;quot;checkbox&amp;quot;],&lt;br /&gt;
select {&lt;br /&gt;
  border: 3px #d0e0e3 solid;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
input[type=&amp;quot;checkbox&amp;quot;] {&lt;br /&gt;
  background-color: white;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
input[type=&amp;quot;checkbox&amp;quot;]:checked {&lt;br /&gt;
  background-color: #19bd94;&lt;br /&gt;
  border: none;&lt;br /&gt;
  position: relative;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
input[type=&amp;quot;checkbox&amp;quot;]:checked:after {&lt;br /&gt;
  content: &amp;quot;&amp;quot;;&lt;br /&gt;
  position: absolute;&lt;br /&gt;
  background: transparent;&lt;br /&gt;
  left: 20%;&lt;br /&gt;
  top: 20%;&lt;br /&gt;
  width: 45%;&lt;br /&gt;
  height: 25%;&lt;br /&gt;
  transform: rotate(-45deg);&lt;br /&gt;
  border: 0.18em white solid;&lt;br /&gt;
  border-top: none;&lt;br /&gt;
  border-right: none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
input:focus,&lt;br /&gt;
select:focus {&lt;br /&gt;
  border: 3px rgb(102, 175, 233) solid;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
input:focus:not([type='checkbox']),&lt;br /&gt;
select:focus {&lt;br /&gt;
  box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075),&lt;br /&gt;
    0 0 8px rgba(102, 175, 233, 0.6);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.label-hover label:hover {&lt;br /&gt;
  background-color: rgba(0, 0, 0, 0.1);&lt;br /&gt;
  border-radius: 8px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.cacheTel,&lt;br /&gt;
.tabber-container &amp;gt; :last-child &amp;gt; :not(.tabber-active),&lt;br /&gt;
.tabber-noactive {&lt;br /&gt;
  display: none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes pnj-square {&lt;br /&gt;
  from {&lt;br /&gt;
    background-color: #f80000;&lt;br /&gt;
  }&lt;br /&gt;
  to {&lt;br /&gt;
    background-color: white;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes pnj-circle {&lt;br /&gt;
  from {&lt;br /&gt;
    border-color: #984c48;&lt;br /&gt;
  }&lt;br /&gt;
  to {&lt;br /&gt;
    border-color: white;&lt;br /&gt;
  }&lt;br /&gt;
  from {&lt;br /&gt;
    scale: 1;&lt;br /&gt;
  }&lt;br /&gt;
  to {&lt;br /&gt;
    scale: 0.1;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes loading {&lt;br /&gt;
  0% {&lt;br /&gt;
    transform: scale(1.5);&lt;br /&gt;
  }&lt;br /&gt;
  100% {&lt;br /&gt;
    transform: scale(1);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@media screen and (max-width: 768px) {&lt;br /&gt;
  .texte-long {&lt;br /&gt;
    white-space: normal;&lt;br /&gt;
    overflow: visible;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  .grid2 {&lt;br /&gt;
    grid-template-columns: repeat(2, 1fr) !important;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  .grid3 {&lt;br /&gt;
    grid-template-columns: repeat(3, auto) !important;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  .container {&lt;br /&gt;
    flex-direction: column;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  .cacheTel,&lt;br /&gt;
  .subpage &amp;gt; li:nth-last-child(2) &amp;gt; a {&lt;br /&gt;
    display: block;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  .top-button {&lt;br /&gt;
    background: rgba(0, 0, 0, 0.7);&lt;br /&gt;
    color: #999;&lt;br /&gt;
    border: none;&lt;br /&gt;
    box-shadow: none;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  .top-button::after {&lt;br /&gt;
    background-image: url(&amp;quot;data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23ffffff' height='24' viewBox='0 -960 960 960' width='24'%3E%3Cpath d='M440-80v-647L256-544l-56-56 280-280 280 280-56 57-184-184v647h-80Z'/%3E%3C/svg%3E&amp;quot;);&lt;br /&gt;
    height: 24px;&lt;br /&gt;
    width: 24px;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  .tooltip-icon {&lt;br /&gt;
    position: static;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  .tooltip-info {&lt;br /&gt;
    position: fixed;&lt;br /&gt;
    left: 20px;&lt;br /&gt;
    right: 20px;&lt;br /&gt;
    bottom: 50px;&lt;br /&gt;
    max-width: none;&lt;br /&gt;
    width: auto;&lt;br /&gt;
    transform: none;&lt;br /&gt;
    height: max-content;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  .subpage &amp;gt; li &amp;gt; a,&lt;br /&gt;
  .cacheOrdi,&lt;br /&gt;
  .tooltip-info:after {&lt;br /&gt;
    display: none;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@media screen and (max-width: 340px) {&lt;br /&gt;
  #mw-content {&lt;br /&gt;
    padding-left: 10px;&lt;br /&gt;
    padding-right: 10px;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@media screen and (min-width: 851px) {&lt;br /&gt;
  html {&lt;br /&gt;
    scroll-padding-top: 3.325em;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;/div&gt;</summary>
		<author><name>Dexter</name></author>
		
	</entry>
	<entry>
		<id>https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Script/Calculator.js&amp;diff=105977</id>
		<title>MediaWiki:Script/Calculator.js</title>
		<link rel="alternate" type="text/html" href="https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Script/Calculator.js&amp;diff=105977"/>
		<updated>2024-12-23T20:03:45Z</updated>

		<summary type="html">&lt;p&gt;Dexter : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;function removeAccent(str) {&lt;br /&gt;
  return str.normalize(&amp;quot;NFD&amp;quot;).replace(/[\u0300-\u036f]/g, &amp;quot;&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function pseudoFormat(str) {&lt;br /&gt;
  return removeAccent(str).replace(/[^A-Za-z0-9 \(\)\+_-]+/g, &amp;quot;&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isValueInArray(value, array) {&lt;br /&gt;
  return array.indexOf(value) !== -1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function copyObject(object) {&lt;br /&gt;
  var copy = {};&lt;br /&gt;
  for (var key in object) {&lt;br /&gt;
    copy[key] = object[key];&lt;br /&gt;
  }&lt;br /&gt;
  return copy;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function compareNumbers(a, b) {&lt;br /&gt;
  return b - a;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isChecked(attribute) {&lt;br /&gt;
  return attribute === &amp;quot;on&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function floorMultiplication(firstFactor, secondFactor) {&lt;br /&gt;
  return Math.floor((firstFactor * secondFactor).toFixed(8));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function truncateNumber(number, precision) {&lt;br /&gt;
  return Math.floor(number * 10 ** precision) / 10 ** precision;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addKeyValue(object, key, value) {&lt;br /&gt;
  if (object.hasOwnProperty(key)) {&lt;br /&gt;
    object[key] += value;&lt;br /&gt;
  } else {&lt;br /&gt;
    object[key] = value;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function editTableResultRow(row, valuesToDisplay, numberFormat) {&lt;br /&gt;
  row.innerHTML = &amp;quot;&amp;quot;;&lt;br /&gt;
  for (var index = 0; index &amp;lt; valuesToDisplay.length; index++) {&lt;br /&gt;
    var cell = row.insertCell();&lt;br /&gt;
    var textContent;&lt;br /&gt;
&lt;br /&gt;
    if (index &amp;gt;= 3) {&lt;br /&gt;
      textContent = numberFormat.format(valuesToDisplay[index]);&lt;br /&gt;
    } else {&lt;br /&gt;
      textContent = valuesToDisplay[index];&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    cell.textContent = textContent;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return row;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addRowToTableResultHistory(&lt;br /&gt;
  tableResultHistory,&lt;br /&gt;
  valuesToDisplay,&lt;br /&gt;
  deleteFightTemplate,&lt;br /&gt;
  numberFormat&lt;br /&gt;
) {&lt;br /&gt;
  var row = tableResultHistory.insertRow();&lt;br /&gt;
  editTableResultRow(row, valuesToDisplay, numberFormat);&lt;br /&gt;
  var cell = row.insertCell();&lt;br /&gt;
  cell.appendChild(deleteFightTemplate.cloneNode(true));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcMeanDamages(damagesWeightedByType, totalCardinal) {&lt;br /&gt;
  var sumDamages = 0;&lt;br /&gt;
&lt;br /&gt;
  for (var damagesTypeName in damagesWeightedByType) {&lt;br /&gt;
    if (damagesTypeName === &amp;quot;miss&amp;quot;) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var damagesWeighted = damagesWeightedByType[damagesTypeName];&lt;br /&gt;
&lt;br /&gt;
    for (var damages in damagesWeighted) {&lt;br /&gt;
      sumDamages += damages * damagesWeighted[damages];&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return sumDamages / totalCardinal;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function prepareDamagesData(&lt;br /&gt;
  damagesWeightedByType,&lt;br /&gt;
  possibleDamagesCountTemp,&lt;br /&gt;
  totalCardinal&lt;br /&gt;
) {&lt;br /&gt;
  var minDamages = Infinity;&lt;br /&gt;
  var maxDamages = 0;&lt;br /&gt;
  var scatterDataByType = {};&lt;br /&gt;
  var sumDamages = 0;&lt;br /&gt;
  var possibleDamagesCount = 0;&lt;br /&gt;
  var uniqueDamagesCount = 0;&lt;br /&gt;
&lt;br /&gt;
  for (var damagesTypeName in damagesWeightedByType) {&lt;br /&gt;
    if (damagesTypeName === &amp;quot;miss&amp;quot;) {&lt;br /&gt;
      scatterDataByType.miss = damagesWeightedByType.miss;&lt;br /&gt;
      possibleDamagesCount++;&lt;br /&gt;
      uniqueDamagesCount++;&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var firstIteration = true;&lt;br /&gt;
    var damagesWeighted = damagesWeightedByType[damagesTypeName];&lt;br /&gt;
    var scatterData = [];&lt;br /&gt;
    scatterDataByType[damagesTypeName] = scatterData;&lt;br /&gt;
&lt;br /&gt;
    for (var damages in damagesWeighted) {&lt;br /&gt;
      damages = +damages;&lt;br /&gt;
&lt;br /&gt;
      if (firstIteration) {&lt;br /&gt;
        if (damages &amp;lt; minDamages) {&lt;br /&gt;
          minDamages = damages;&lt;br /&gt;
        }&lt;br /&gt;
        firstIteration = false;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      var weight = damagesWeighted[damages];&lt;br /&gt;
      var probability = weight / totalCardinal;&lt;br /&gt;
&lt;br /&gt;
      sumDamages += damages * weight;&lt;br /&gt;
      damagesWeighted[damages] = probability;&lt;br /&gt;
      scatterData.push({ x: damages, y: probability });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var scatterDataLength = scatterData.length;&lt;br /&gt;
&lt;br /&gt;
    possibleDamagesCount += possibleDamagesCountTemp;&lt;br /&gt;
    uniqueDamagesCount += scatterDataLength;&lt;br /&gt;
&lt;br /&gt;
    if (damages &amp;gt; maxDamages) {&lt;br /&gt;
      maxDamages = damages;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (minDamages === Infinity) {&lt;br /&gt;
    minDamages = 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return [&lt;br /&gt;
    sumDamages / totalCardinal,&lt;br /&gt;
    minDamages,&lt;br /&gt;
    maxDamages,&lt;br /&gt;
    scatterDataByType,&lt;br /&gt;
    possibleDamagesCount,&lt;br /&gt;
    uniqueDamagesCount,&lt;br /&gt;
  ];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function aggregateDamages(scatterData, maxPoints) {&lt;br /&gt;
  var dataLength = scatterData.length;&lt;br /&gt;
  var remainingData = dataLength;&lt;br /&gt;
  var aggregateScatterData = [];&lt;br /&gt;
&lt;br /&gt;
  for (var groupIndex = 0; groupIndex &amp;lt; maxPoints; groupIndex++) {&lt;br /&gt;
    var groupLength = Math.floor(remainingData / (maxPoints - groupIndex));&lt;br /&gt;
    var startIndex = dataLength - remainingData;&lt;br /&gt;
    var aggregateDamages = 0;&lt;br /&gt;
    var aggregateProbability = 0;&lt;br /&gt;
&lt;br /&gt;
    for (var index = startIndex; index &amp;lt; startIndex + groupLength; index++) {&lt;br /&gt;
      var { x: damages, y: probability } = scatterData[index];&lt;br /&gt;
      aggregateDamages += damages * probability;&lt;br /&gt;
      aggregateProbability += probability;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    aggregateScatterData.push({&lt;br /&gt;
      x: aggregateDamages / aggregateProbability,&lt;br /&gt;
      y: aggregateProbability,&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    remainingData -= groupLength;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return aggregateScatterData;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addToDamagesChart(&lt;br /&gt;
  scatterDataByType,&lt;br /&gt;
  damagesChart,&lt;br /&gt;
  isReducePointsChecked&lt;br /&gt;
) {&lt;br /&gt;
  var { chart, datasetsStyle, maxPoints, reduceChartPointsContainer } =&lt;br /&gt;
    damagesChart;&lt;br /&gt;
  var isFirstDataset = true;&lt;br /&gt;
  var datasets = chart.data.datasets;&lt;br /&gt;
&lt;br /&gt;
  datasets.length = 0;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; datasetsStyle.length; index++) {&lt;br /&gt;
    var dataset = copyObject(datasetsStyle[index]);&lt;br /&gt;
&lt;br /&gt;
    if (!scatterDataByType.hasOwnProperty(dataset.name)) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var scatterData = scatterDataByType[dataset.name];&lt;br /&gt;
    var canBeReduced = scatterData.length &amp;gt; 2 * maxPoints;&lt;br /&gt;
&lt;br /&gt;
    dataset.hidden = !isFirstDataset;&lt;br /&gt;
    dataset.canBeReduced = canBeReduced;&lt;br /&gt;
&lt;br /&gt;
    if (canBeReduced &amp;amp;&amp;amp; isReducePointsChecked) {&lt;br /&gt;
      dataset.data = aggregateDamages(scatterData, maxPoints);&lt;br /&gt;
    } else {&lt;br /&gt;
      dataset.data = scatterData;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isFirstDataset) {&lt;br /&gt;
      isFirstDataset = false;&lt;br /&gt;
&lt;br /&gt;
      if (canBeReduced) {&lt;br /&gt;
        showElement(reduceChartPointsContainer);&lt;br /&gt;
&lt;br /&gt;
        if (!isReducePointsChecked) {&lt;br /&gt;
          handleChartAnimations(chart, false);&lt;br /&gt;
        }&lt;br /&gt;
      } else {&lt;br /&gt;
        hideElement(reduceChartPointsContainer);&lt;br /&gt;
        handleChartAnimations(chart, true);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    datasets.push(dataset);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  chart.data.missPercentage = scatterDataByType.miss;&lt;br /&gt;
  chart.update();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addToBonusVariationChart(&lt;br /&gt;
  damagesByBonus,&lt;br /&gt;
  augmentationByBonus,&lt;br /&gt;
  xLabel,&lt;br /&gt;
  chart&lt;br /&gt;
) {&lt;br /&gt;
  chart.data.datasets[0].data = damagesByBonus;&lt;br /&gt;
  chart.data.datasets[1].data = augmentationByBonus;&lt;br /&gt;
  chart.options.scales.x.title.text = xLabel;&lt;br /&gt;
  chart.update();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleChartAnimations(chart, addAnimations) {&lt;br /&gt;
  chart.options.animation = addAnimations;&lt;br /&gt;
  chart.options.animations.colors = addAnimations;&lt;br /&gt;
  chart.options.animations.x = addAnimations;&lt;br /&gt;
  chart.options.transitions.active.animation.duration = addAnimations * 1000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateDamagesChartDescription(&lt;br /&gt;
  uniqueDamagesCounters,&lt;br /&gt;
  uniqueDamagesCount,&lt;br /&gt;
  formatNumber&lt;br /&gt;
) {&lt;br /&gt;
  uniqueDamagesCounters.forEach(function (element) {&lt;br /&gt;
    if (uniqueDamagesCount &amp;lt;= 1) {&lt;br /&gt;
      hideElement(element.parentElement);&lt;br /&gt;
    } else {&lt;br /&gt;
      showElement(element.parentElement);&lt;br /&gt;
      element.textContent = formatNumber.format(uniqueDamagesCount);&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getMonsterName(monsterVnum) {&lt;br /&gt;
  var monsterAttributes = monsterData[monsterVnum];&lt;br /&gt;
  return monsterAttributes[monsterAttributes.length - 1];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterClass(selectedRace, classChoice, selectValueIsChanged = false) {&lt;br /&gt;
  showElement(classChoice.parentElement);&lt;br /&gt;
&lt;br /&gt;
  for (var option of classChoice.options) {&lt;br /&gt;
    if (option.getAttribute(&amp;quot;data-race&amp;quot;) === selectedRace) {&lt;br /&gt;
      if (!selectValueIsChanged) {&lt;br /&gt;
        classChoice.value = option.value;&lt;br /&gt;
        selectValueIsChanged = true;&lt;br /&gt;
      }&lt;br /&gt;
      showElement(option);&lt;br /&gt;
    } else {&lt;br /&gt;
      hideElement(option);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  if (selectedRace == &amp;quot;lycan&amp;quot;) {&lt;br /&gt;
    hideElement(classChoice.parentElement);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterWeapon(&lt;br /&gt;
  selectedRace,&lt;br /&gt;
  weaponElement,&lt;br /&gt;
  weaponCategory,&lt;br /&gt;
  allowedWeaponsPerRace,&lt;br /&gt;
  selectValueIsChanged = false&lt;br /&gt;
) {&lt;br /&gt;
  var allowedWeapons = allowedWeaponsPerRace[selectedRace];&lt;br /&gt;
&lt;br /&gt;
  if (!selectValueIsChanged) {&lt;br /&gt;
    var weaponType = createWeapon(weaponElement.value).type;&lt;br /&gt;
&lt;br /&gt;
    if (!isValueInArray(weaponType, allowedWeapons)) {&lt;br /&gt;
      weaponElement.value = 0;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var children = weaponCategory.children;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; children.length; index++) {&lt;br /&gt;
    var child = children[index];&lt;br /&gt;
&lt;br /&gt;
    if (isValueInArray(index, allowedWeapons)) {&lt;br /&gt;
      showElement(child);&lt;br /&gt;
    } else {&lt;br /&gt;
      hideElement(child);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSelectedWeapon(weaponCategory) {&lt;br /&gt;
  return weaponCategory.querySelector(&amp;quot;input[type='radio']:checked&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleWeaponDisplay(weaponCategory, weaponDisplay, weaponVnum, newWeapon) {&lt;br /&gt;
  var newWeapon = newWeapon || getSelectedWeapon(weaponCategory);&lt;br /&gt;
&lt;br /&gt;
  var newImage = newWeapon.nextElementSibling;&lt;br /&gt;
  var newText = document.createElement(&amp;quot;span&amp;quot;);&lt;br /&gt;
  var oldImage = weaponDisplay.firstChild;&lt;br /&gt;
  var oldText = oldImage.nextElementSibling;&lt;br /&gt;
  var weaponName = newImage.nextElementSibling.dataset.o;&lt;br /&gt;
&lt;br /&gt;
  if (weaponVnum == 0) {&lt;br /&gt;
    newText.textContent = &amp;quot; &amp;quot; + weaponName + &amp;quot; &amp;quot;;&lt;br /&gt;
  } else {&lt;br /&gt;
    var weaponLink = document.createElement(&amp;quot;a&amp;quot;);&lt;br /&gt;
    weaponLink.href = mw.util.getUrl(weaponName);&lt;br /&gt;
    weaponLink.title = weaponName;&lt;br /&gt;
    weaponLink.textContent = weaponName;&lt;br /&gt;
&lt;br /&gt;
    newText.appendChild(document.createTextNode(&amp;quot; &amp;quot;));&lt;br /&gt;
    newText.appendChild(weaponLink);&lt;br /&gt;
    newText.appendChild(document.createTextNode(&amp;quot; &amp;quot;));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  weaponDisplay.replaceChild(newImage.cloneNode(), oldImage);&lt;br /&gt;
  weaponDisplay.replaceChild(newText, oldText);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterUpgrade(&lt;br /&gt;
  weaponUpgrade,&lt;br /&gt;
  weaponVnum,&lt;br /&gt;
  randomAttackValue,&lt;br /&gt;
  randomMagicAttackValue,&lt;br /&gt;
) {&lt;br /&gt;
  var weapon = createWeapon(weaponVnum);&lt;br /&gt;
  var currentUpgrade = Number(weaponUpgrade.value);&lt;br /&gt;
&lt;br /&gt;
  if (weapon.isSerpent) {&lt;br /&gt;
    showElement(randomAttackValue);&lt;br /&gt;
&lt;br /&gt;
    if (weapon.isMagic) {&lt;br /&gt;
      showElement(randomMagicAttackValue);&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    hideElement(randomAttackValue);&lt;br /&gt;
    hideElement(randomMagicAttackValue);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (weapon.maxUpgrade &amp;lt; 1) {&lt;br /&gt;
    hideElement(weaponUpgrade.parentElement);&lt;br /&gt;
  } else {&lt;br /&gt;
    showElement(weaponUpgrade.parentElement);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  weaponUpgrade.innerHTML = &amp;quot;&amp;quot;;&lt;br /&gt;
  var lastOption;&lt;br /&gt;
&lt;br /&gt;
  for (var upgrade = 0; upgrade &amp;lt;= weapon.maxUpgrade; upgrade++) {&lt;br /&gt;
    var option = document.createElement(&amp;quot;option&amp;quot;);&lt;br /&gt;
    option.value = upgrade;&lt;br /&gt;
    option.textContent = &amp;quot;+&amp;quot; + upgrade;&lt;br /&gt;
    weaponUpgrade.appendChild(option);&lt;br /&gt;
&lt;br /&gt;
    if (upgrade === currentUpgrade) {&lt;br /&gt;
      option.selected = true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    lastOption = option;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if ((currentUpgrade &amp;gt; weapon.maxUpgrade || !currentUpgrade) &amp;amp;&amp;amp; lastOption) {&lt;br /&gt;
    lastOption.selected = true;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterCheckbox(checkbox, element) {&lt;br /&gt;
  if (checkbox.checked) {&lt;br /&gt;
    showElement(element);&lt;br /&gt;
  } else {&lt;br /&gt;
    hideElement(element);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterSkills(selectedClass, skillElementsToFilter) {&lt;br /&gt;
  for (var element of skillElementsToFilter) {&lt;br /&gt;
    if (isValueInArray(selectedClass, element.dataset.class)) {&lt;br /&gt;
      showElement(element);&lt;br /&gt;
    } else {&lt;br /&gt;
      hideElement(element);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterAttackTypeSelection(attacker, attackTypeSelection) {&lt;br /&gt;
  var attackerClass = attacker.class;&lt;br /&gt;
  var selectedOption =&lt;br /&gt;
    attackTypeSelection.options[attackTypeSelection.selectedIndex];&lt;br /&gt;
  var attackerIsNotPolymorph = !isPolymorph(attacker);&lt;br /&gt;
&lt;br /&gt;
  for (var index = 2; index &amp;lt; attackTypeSelection.options.length; index++) {&lt;br /&gt;
    var option = attackTypeSelection.options[index];&lt;br /&gt;
    var optionClass = option.dataset.class;&lt;br /&gt;
    var optionValue = option.value;&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      attackerIsNotPolymorph &amp;amp;&amp;amp;&lt;br /&gt;
      attacker[optionValue] &amp;amp;&amp;amp;&lt;br /&gt;
      (attackerClass === optionClass ||&lt;br /&gt;
        (optionValue.startsWith(&amp;quot;horseSkill&amp;quot;) &amp;amp;&amp;amp;&lt;br /&gt;
          isRiding(attacker) &amp;amp;&amp;amp;&lt;br /&gt;
          (!optionClass || isValueInArray(attackerClass, optionClass))))&lt;br /&gt;
    ) {&lt;br /&gt;
      showElement(option);&lt;br /&gt;
    } else {&lt;br /&gt;
      hideElement(option);&lt;br /&gt;
&lt;br /&gt;
      if (selectedOption === option) {&lt;br /&gt;
        attackTypeSelection.selectedIndex = 0;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterAttackTypeSelectionMonster(attackTypeSelection) {&lt;br /&gt;
  for (var index = 2; index &amp;lt; attackTypeSelection.options.length; index++) {&lt;br /&gt;
    hideElement(attackTypeSelection.options[index]);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (attackTypeSelection.selectedIndex !== 1) {&lt;br /&gt;
    attackTypeSelection.selectedIndex = 0;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterForm(characters, battle) {&lt;br /&gt;
  var characterCreation = characters.characterCreation;&lt;br /&gt;
  var allowedWeaponsPerRace = battle.constants.allowedWeaponsPerRace;&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;change&amp;quot;, function (event) {&lt;br /&gt;
    var target = event.target;&lt;br /&gt;
    var targetName = target.name;&lt;br /&gt;
&lt;br /&gt;
    switch (targetName) {&lt;br /&gt;
      case &amp;quot;race&amp;quot;:&lt;br /&gt;
        var selectedRace = target.value;&lt;br /&gt;
        var classChoice = characterCreation.class;&lt;br /&gt;
        var weaponElement = characterCreation.weapon;&lt;br /&gt;
&lt;br /&gt;
        filterClass(selectedRace, classChoice);&lt;br /&gt;
        filterWeapon(&lt;br /&gt;
          selectedRace,&lt;br /&gt;
          weaponElement,&lt;br /&gt;
          characters.weaponCategory,&lt;br /&gt;
          allowedWeaponsPerRace&lt;br /&gt;
        );&lt;br /&gt;
        handleWeaponDisplay(&lt;br /&gt;
          characters.weaponCategory,&lt;br /&gt;
          characters.weaponDisplay,&lt;br /&gt;
          weaponElement.value&lt;br /&gt;
        );&lt;br /&gt;
        filterUpgrade(&lt;br /&gt;
          characterCreation.weaponUpgrade,&lt;br /&gt;
          weaponElement.value,&lt;br /&gt;
          characters.randomAttackValue,&lt;br /&gt;
          characters.randomMagicAttackValue,&lt;br /&gt;
        );&lt;br /&gt;
        filterSkills(classChoice.value, characters.skillElementsToFilter);&lt;br /&gt;
&lt;br /&gt;
        if (characterCreation.name.value === battle.attackerSelection.value) {&lt;br /&gt;
          battle.resetAttackType = true;&lt;br /&gt;
        }&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;class&amp;quot;:&lt;br /&gt;
        filterSkills(target.value, characters.skillElementsToFilter);&lt;br /&gt;
&lt;br /&gt;
        if (characterCreation.name.value === battle.attackerSelection.value) {&lt;br /&gt;
          battle.resetAttackType = true;&lt;br /&gt;
        }&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;weapon&amp;quot;:&lt;br /&gt;
        var weaponElement = characterCreation.weapon;&lt;br /&gt;
&lt;br /&gt;
        handleWeaponDisplay(&lt;br /&gt;
          characters.weaponCategory,&lt;br /&gt;
          characters.weaponDisplay,&lt;br /&gt;
          weaponElement.value,&lt;br /&gt;
          target&lt;br /&gt;
        );&lt;br /&gt;
        filterUpgrade(&lt;br /&gt;
          characterCreation.weaponUpgrade,&lt;br /&gt;
          target.value,&lt;br /&gt;
          characters.randomAttackValue,&lt;br /&gt;
          characters.randomMagicAttackValue&lt;br /&gt;
        );&lt;br /&gt;
        handleBonusVariationUpdate(&lt;br /&gt;
          characterCreation,&lt;br /&gt;
          characters.bonusVariation&lt;br /&gt;
        );&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;isPolymorph&amp;quot;:&lt;br /&gt;
        filterCheckbox(&lt;br /&gt;
          target,&lt;br /&gt;
          characterCreation.polymorphMonster.parentElement&lt;br /&gt;
        );&lt;br /&gt;
        if (characterCreation.name.value === battle.attackerSelection.value) {&lt;br /&gt;
          battle.resetAttackType = true;&lt;br /&gt;
        }&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;lowRank&amp;quot;:&lt;br /&gt;
        filterCheckbox(target, characterCreation.playerRank.parentElement);&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;isBlessed&amp;quot;:&lt;br /&gt;
        filterCheckbox(target, characters.blessingCreation);&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;onYohara&amp;quot;:&lt;br /&gt;
        filterCheckbox(target, characters.yoharaCreation);&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;isMarried&amp;quot;:&lt;br /&gt;
        filterCheckbox(target, characters.marriageCreation);&lt;br /&gt;
        break;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      targetName.startsWith(&amp;quot;attackSkill&amp;quot;) ||&lt;br /&gt;
      targetName.startsWith(&amp;quot;horseSkill&amp;quot;)&lt;br /&gt;
    ) {&lt;br /&gt;
      battle.resetAttackType = true;&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addUniquePseudo(characterDataObject, savedCharactersPseudo) {&lt;br /&gt;
  var characterPseudo = String(characterDataObject.name);&lt;br /&gt;
  var originalPseudo = characterPseudo;&lt;br /&gt;
  var count = 0;&lt;br /&gt;
&lt;br /&gt;
  var regex = /(.*)(\d)$/;&lt;br /&gt;
  var match = characterPseudo.match(regex);&lt;br /&gt;
&lt;br /&gt;
  if (match) {&lt;br /&gt;
    originalPseudo = match[1];&lt;br /&gt;
    count = match[2];&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  while (isValueInArray(characterPseudo, savedCharactersPseudo)) {&lt;br /&gt;
    characterPseudo = originalPseudo + count;&lt;br /&gt;
    count++;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  characterDataObject.name = characterPseudo;&lt;br /&gt;
  return [characterDataObject, characterPseudo];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function convertToNumber(value) {&lt;br /&gt;
  var valueNumber = Number(value);&lt;br /&gt;
  return isNaN(valueNumber) ? value : valueNumber;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getLocalStorageValue(key, defaultValue) {&lt;br /&gt;
  var storedValue = localStorage.getItem(key);&lt;br /&gt;
&lt;br /&gt;
  if (storedValue) {&lt;br /&gt;
    return JSON.parse(storedValue);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return defaultValue;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSavedCharacters() {&lt;br /&gt;
  return getLocalStorageValue(&amp;quot;savedCharactersCalculator&amp;quot;, {});&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSavedMonsters() {&lt;br /&gt;
  var savedMonsters = getLocalStorageValue(&amp;quot;savedMonstersCalculator&amp;quot;, {});&lt;br /&gt;
&lt;br /&gt;
  if (Array.isArray(savedMonsters)) {&lt;br /&gt;
    return {};&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var filteredMonsters = {};&lt;br /&gt;
&lt;br /&gt;
  for (var vnum in savedMonsters) {&lt;br /&gt;
    if (String(Number(vnum)) === vnum) {&lt;br /&gt;
      filteredMonsters[vnum] = savedMonsters[vnum];&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return filteredMonsters;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSavedFights() {&lt;br /&gt;
  return getLocalStorageValue(&amp;quot;savedFightsCalculator&amp;quot;, []);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveToLocalStorage(key, value) {&lt;br /&gt;
  localStorage.setItem(key, JSON.stringify(value));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateSavedCharacters(savedCharacters) {&lt;br /&gt;
  saveToLocalStorage(&amp;quot;savedCharactersCalculator&amp;quot;, savedCharacters);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateSavedMonsters(savedMonsters) {&lt;br /&gt;
  saveToLocalStorage(&amp;quot;savedMonstersCalculator&amp;quot;, savedMonsters);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateSavedFights(savedFights) {&lt;br /&gt;
  saveToLocalStorage(&amp;quot;savedFightsCalculator&amp;quot;, savedFights);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveCharacter(&lt;br /&gt;
  savedCharacters,&lt;br /&gt;
  characterCreation,&lt;br /&gt;
  battle,&lt;br /&gt;
  newCharacter,&lt;br /&gt;
  characterDataObject&lt;br /&gt;
) {&lt;br /&gt;
  if (!characterDataObject) {&lt;br /&gt;
    var characterData = new FormData(characterCreation);&lt;br /&gt;
    var characterDataObject = {};&lt;br /&gt;
&lt;br /&gt;
    characterData.forEach(function (value, key) {&lt;br /&gt;
      characterDataObject[key] = convertToNumber(value);&lt;br /&gt;
    });&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  savedCharacters[characterDataObject.name] = characterDataObject;&lt;br /&gt;
  updateSavedCharacters(savedCharacters);&lt;br /&gt;
&lt;br /&gt;
  if (newCharacter) {&lt;br /&gt;
    addBattleChoice(battle, characterDataObject.name);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (battle.resetAttackType) {&lt;br /&gt;
    filterAttackTypeSelection(characterDataObject, battle.attackTypeSelection);&lt;br /&gt;
    battle.resetAttackType = false;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveButtonGreen(saveButton) {&lt;br /&gt;
  saveButton.classList.remove(&amp;quot;unsaved-character&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveButtonOrange(saveButton) {&lt;br /&gt;
  saveButton.classList.add(&amp;quot;unsaved-character&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function characterCreationListener(characters, battle) {&lt;br /&gt;
  var { characterCreation, saveButton, weaponCategory } = characters;&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;submit&amp;quot;, function (event) {&lt;br /&gt;
    event.preventDefault();&lt;br /&gt;
&lt;br /&gt;
    if (characters.unsavedChanges) {&lt;br /&gt;
      saveCharacter(characters.savedCharacters, characterCreation, battle);&lt;br /&gt;
      saveButtonGreen(saveButton);&lt;br /&gt;
      characters.unsavedChanges = false;&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  document.addEventListener(&amp;quot;keydown&amp;quot;, function (event) {&lt;br /&gt;
    if (event.ctrlKey &amp;amp;&amp;amp; event.key === &amp;quot;s&amp;quot;) {&lt;br /&gt;
      event.preventDefault();&lt;br /&gt;
      saveButton.click();&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  weaponCategory.addEventListener(&amp;quot;mouseover&amp;quot;, function (event) {&lt;br /&gt;
    label = event.target.closest(&amp;quot;label&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (label) {&lt;br /&gt;
      var tooltip = label.lastChild;&lt;br /&gt;
&lt;br /&gt;
      if (tooltip.classList.contains(&amp;quot;popContenu&amp;quot;)) {&lt;br /&gt;
        var tooltipRect = tooltip.getBoundingClientRect();&lt;br /&gt;
        var modalRect = weaponCategory.getBoundingClientRect();&lt;br /&gt;
&lt;br /&gt;
        if (tooltipRect.right &amp;gt; modalRect.right) {&lt;br /&gt;
          tooltip.style.left = &amp;quot;-100%&amp;quot;;&lt;br /&gt;
        } else if (tooltipRect.left &amp;lt; modalRect.left) {&lt;br /&gt;
          tooltip.style.left = &amp;quot;200%&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function downloadData(content, type, filename) {&lt;br /&gt;
  var link = document.createElement(&amp;quot;a&amp;quot;);&lt;br /&gt;
  var blob = new Blob([content], { type: type });&lt;br /&gt;
  var blobURL = URL.createObjectURL(blob);&lt;br /&gt;
&lt;br /&gt;
  link.href = blobURL;&lt;br /&gt;
  link.download = filename;&lt;br /&gt;
  document.body.appendChild(link);&lt;br /&gt;
&lt;br /&gt;
  link.click();&lt;br /&gt;
  document.body.removeChild(link);&lt;br /&gt;
  URL.revokeObjectURL(blobURL);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function uploadCharacter(&lt;br /&gt;
  selectedFiles,&lt;br /&gt;
  characters,&lt;br /&gt;
  characterTemplate,&lt;br /&gt;
  charactersContainer,&lt;br /&gt;
  battle&lt;br /&gt;
) {&lt;br /&gt;
  var selectFilesLength = selectedFiles.length;&lt;br /&gt;
&lt;br /&gt;
  for (var fileIndex = 0; fileIndex &amp;lt; selectFilesLength; fileIndex++) {&lt;br /&gt;
    var selectedFile = selectedFiles[fileIndex];&lt;br /&gt;
&lt;br /&gt;
    if (selectedFile.type === &amp;quot;text/plain&amp;quot;) {&lt;br /&gt;
      var reader = new FileReader();&lt;br /&gt;
      reader.onload = function (e) {&lt;br /&gt;
        var fileContent = e.target.result;&lt;br /&gt;
        try {&lt;br /&gt;
          var characterDataObject = JSON.parse(fileContent);&lt;br /&gt;
&lt;br /&gt;
          if (characterDataObject.hasOwnProperty(&amp;quot;name&amp;quot;)) {&lt;br /&gt;
            var characterPseudo = String(characterDataObject.name);&lt;br /&gt;
&lt;br /&gt;
            hideElement(characters.characterCreation);&lt;br /&gt;
            characterPseudo = validPseudo(characterPseudo);&lt;br /&gt;
&lt;br /&gt;
            [characterDataObject, characterPseudo] = addUniquePseudo(&lt;br /&gt;
              characterDataObject,&lt;br /&gt;
              Object.keys(characters.savedCharacters)&lt;br /&gt;
            );&lt;br /&gt;
            var selectedCharacter = handleNewCharacter(&lt;br /&gt;
              characters,&lt;br /&gt;
              characterTemplate,&lt;br /&gt;
              charactersContainer,&lt;br /&gt;
              battle,&lt;br /&gt;
              characterPseudo&lt;br /&gt;
            )[0];&lt;br /&gt;
&lt;br /&gt;
            if (selectFilesLength === 1) {&lt;br /&gt;
              updateForm(&lt;br /&gt;
                characterDataObject,&lt;br /&gt;
                characters.characterCreation,&lt;br /&gt;
                characters,&lt;br /&gt;
                selectedCharacter,&lt;br /&gt;
                battle&lt;br /&gt;
              );&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            saveCharacter(&lt;br /&gt;
              characters.savedCharacters,&lt;br /&gt;
              characters.characterCreation,&lt;br /&gt;
              battle,&lt;br /&gt;
              true,&lt;br /&gt;
              characterDataObject&lt;br /&gt;
            );&lt;br /&gt;
          }&lt;br /&gt;
        } catch (error) {&lt;br /&gt;
          console.log(error);&lt;br /&gt;
          if (error.name === &amp;quot;TypeError&amp;quot;) {&lt;br /&gt;
            // delete the character&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
      };&lt;br /&gt;
      reader.readAsText(selectedFile);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleUploadCharacter(&lt;br /&gt;
  characters,&lt;br /&gt;
  characterTemplate,&lt;br /&gt;
  charactersContainer,&lt;br /&gt;
  battle&lt;br /&gt;
) {&lt;br /&gt;
  var characterInput = characters.characterInput;&lt;br /&gt;
  var dropZone = characters.dropZone;&lt;br /&gt;
&lt;br /&gt;
  characterInput.accept = &amp;quot;.txt&amp;quot;;&lt;br /&gt;
  characterInput.multiple = true;&lt;br /&gt;
  dropZone.setAttribute(&amp;quot;tabindex&amp;quot;, &amp;quot;0&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  dropZone.addEventListener(&amp;quot;click&amp;quot;, function () {&lt;br /&gt;
    characterInput.click();&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  dropZone.addEventListener(&amp;quot;dragover&amp;quot;, function (event) {&lt;br /&gt;
    event.preventDefault();&lt;br /&gt;
    dropZone.classList.add(&amp;quot;drop-zone--dragover&amp;quot;);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  [&amp;quot;dragleave&amp;quot;, &amp;quot;dragend&amp;quot;].forEach(function (type) {&lt;br /&gt;
    dropZone.addEventListener(type, function () {&lt;br /&gt;
      dropZone.classList.remove(&amp;quot;drop-zone--dragover&amp;quot;);&lt;br /&gt;
    });&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  dropZone.addEventListener(&amp;quot;drop&amp;quot;, function (event) {&lt;br /&gt;
    event.preventDefault();&lt;br /&gt;
    uploadCharacter(&lt;br /&gt;
      event.dataTransfer.files,&lt;br /&gt;
      characters,&lt;br /&gt;
      characterTemplate,&lt;br /&gt;
      charactersContainer,&lt;br /&gt;
      battle&lt;br /&gt;
    );&lt;br /&gt;
    dropZone.classList.remove(&amp;quot;drop-zone--dragover&amp;quot;);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  characterInput.addEventListener(&amp;quot;change&amp;quot;, function (event) {&lt;br /&gt;
    uploadCharacter(&lt;br /&gt;
      event.target.files,&lt;br /&gt;
      characters,&lt;br /&gt;
      characterTemplate,&lt;br /&gt;
      charactersContainer,&lt;br /&gt;
      battle&lt;br /&gt;
    );&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function deleteCharacter(characters, pseudo, element, battle) {&lt;br /&gt;
  battle.battleForm.reset();&lt;br /&gt;
  delete characters.savedCharacters[pseudo];&lt;br /&gt;
  element.remove();&lt;br /&gt;
&lt;br /&gt;
  updateSavedCharacters(characters.savedCharacters);&lt;br /&gt;
  removeBattleChoice(battle, pseudo);&lt;br /&gt;
&lt;br /&gt;
  if (&lt;br /&gt;
    !Object.keys(characters.savedCharacters).length ||&lt;br /&gt;
    characters.characterCreation.name.value === pseudo&lt;br /&gt;
  ) {&lt;br /&gt;
    saveButtonGreen(characters.saveButton);&lt;br /&gt;
    characters.unsavedChanges = false;&lt;br /&gt;
    hideElement(characters.characterCreation);&lt;br /&gt;
    showElement(characters.characterCreation.previousElementSibling);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function deleteMonster(characters, battle, monsterVnum, monsterElement) {&lt;br /&gt;
  var monsterElement =&lt;br /&gt;
    monsterElement ||&lt;br /&gt;
    characters.monstersContainer.querySelector(&lt;br /&gt;
      &amp;quot;[data-monster-id='&amp;quot; + monsterVnum + &amp;quot;']&amp;quot;&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
  if (monsterElement) {&lt;br /&gt;
    monsterElement.remove();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  battle.battleForm.reset();&lt;br /&gt;
  delete characters.savedMonsters[monsterVnum];&lt;br /&gt;
&lt;br /&gt;
  updateSavedMonsters(characters.savedMonsters);&lt;br /&gt;
  removeBattleChoice(battle, monsterVnum);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleStyle(characters, selectedElement) {&lt;br /&gt;
  var currentCharacter = characters.currentCharacter;&lt;br /&gt;
&lt;br /&gt;
  if (currentCharacter) {&lt;br /&gt;
    currentCharacter.classList.remove(&amp;quot;selected-character&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  selectedElement.classList.add(&amp;quot;selected-character&amp;quot;);&lt;br /&gt;
  characters.currentCharacter = selectedElement;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateForm(&lt;br /&gt;
  formData,&lt;br /&gt;
  characterCreation,&lt;br /&gt;
  characters,&lt;br /&gt;
  selectedElement,&lt;br /&gt;
  battle&lt;br /&gt;
) {&lt;br /&gt;
  saveButtonGreen(characters.saveButton);&lt;br /&gt;
  hideElement(characterCreation.previousElementSibling);&lt;br /&gt;
  showElement(characterCreation);&lt;br /&gt;
  handleStyle(characters, selectedElement);&lt;br /&gt;
&lt;br /&gt;
  characterCreation.reset();&lt;br /&gt;
&lt;br /&gt;
  for (var [name, value] of Object.entries(formData)) {&lt;br /&gt;
    var formElement = characterCreation[name];&lt;br /&gt;
&lt;br /&gt;
    if (!formElement) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (formElement.type === &amp;quot;checkbox&amp;quot;) {&lt;br /&gt;
      if (isChecked(value)) {&lt;br /&gt;
        formElement.checked = true;&lt;br /&gt;
      }&lt;br /&gt;
    } else {&lt;br /&gt;
      formElement.value = value;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  var selectedRace = characterCreation.race.value;&lt;br /&gt;
  var classChoice = characterCreation.class;&lt;br /&gt;
  var weaponElement = characterCreation.weapon;&lt;br /&gt;
&lt;br /&gt;
  filterClass(selectedRace, classChoice, true);&lt;br /&gt;
  filterWeapon(&lt;br /&gt;
    selectedRace,&lt;br /&gt;
    weaponElement,&lt;br /&gt;
    characters.weaponCategory,&lt;br /&gt;
    battle.constants.allowedWeaponsPerRace,&lt;br /&gt;
    true&lt;br /&gt;
  );&lt;br /&gt;
  handleWeaponDisplay(characters.weaponCategory, characters.weaponDisplay, weaponElement.value);&lt;br /&gt;
  filterUpgrade(&lt;br /&gt;
    characterCreation.weaponUpgrade,&lt;br /&gt;
    weaponElement.value,&lt;br /&gt;
    characters.randomAttackValue,&lt;br /&gt;
    characters.randomMagicAttackValue,&lt;br /&gt;
  );&lt;br /&gt;
  filterCheckbox(&lt;br /&gt;
    characterCreation.isPolymorph,&lt;br /&gt;
    characterCreation.polymorphMonster.parentElement&lt;br /&gt;
  );&lt;br /&gt;
  filterCheckbox(&lt;br /&gt;
    characterCreation.lowRank,&lt;br /&gt;
    characterCreation.playerRank.parentElement&lt;br /&gt;
  );&lt;br /&gt;
  filterCheckbox(characterCreation.onYohara, characters.yoharaCreation);&lt;br /&gt;
  filterCheckbox(characterCreation.isBlessed, characters.blessingCreation);&lt;br /&gt;
  filterCheckbox(characterCreation.isMarried, characters.marriageCreation);&lt;br /&gt;
  filterSkills(classChoice.value, characters.skillElementsToFilter);&lt;br /&gt;
  handleBonusVariationUpdate(characterCreation, characters.bonusVariation);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleClickOnCharacter(&lt;br /&gt;
  spanInput,&lt;br /&gt;
  target,&lt;br /&gt;
  characters,&lt;br /&gt;
  characterElement,&lt;br /&gt;
  battle,&lt;br /&gt;
  edition&lt;br /&gt;
) {&lt;br /&gt;
  var displayedPseudo = characters.characterCreation.name.value;&lt;br /&gt;
  var pseudo = spanInput.dataset.name;&lt;br /&gt;
&lt;br /&gt;
  if (edition) {&lt;br /&gt;
    if (!characters.unsavedChanges) {&lt;br /&gt;
      updateForm(&lt;br /&gt;
        characters.savedCharacters[pseudo],&lt;br /&gt;
        characters.characterCreation,&lt;br /&gt;
        characters,&lt;br /&gt;
        characterElement,&lt;br /&gt;
        battle&lt;br /&gt;
      );&lt;br /&gt;
    } else if (displayedPseudo === pseudo) {&lt;br /&gt;
      // pass&lt;br /&gt;
    } else {&lt;br /&gt;
      var result = confirm(&lt;br /&gt;
        &amp;quot;Voulez-vous continuer ? Les dernières modifications ne seront pas sauvegardées.&amp;quot;&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      if (result) {&lt;br /&gt;
        updateForm(&lt;br /&gt;
          characters.savedCharacters[pseudo],&lt;br /&gt;
          characters.characterCreation,&lt;br /&gt;
          characters,&lt;br /&gt;
          characterElement,&lt;br /&gt;
          battle&lt;br /&gt;
        );&lt;br /&gt;
        characters.unsavedChanges = false;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    if (target.tagName === &amp;quot;path&amp;quot;) {&lt;br /&gt;
      target = target.parentElement;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    switch (target.dataset.icon) {&lt;br /&gt;
      case &amp;quot;duplicate&amp;quot;:&lt;br /&gt;
        if (!characters.unsavedChanges) {&lt;br /&gt;
          addNewCharacter(&lt;br /&gt;
            characters,&lt;br /&gt;
            characters.newCharacterTemplate,&lt;br /&gt;
            characters.charactersContainer,&lt;br /&gt;
            battle,&lt;br /&gt;
            pseudo&lt;br /&gt;
          );&lt;br /&gt;
        } else {&lt;br /&gt;
          var result = confirm(&lt;br /&gt;
            &amp;quot;Voulez-vous continuer ? Les dernières modifications ne seront pas sauvegardées.&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
&lt;br /&gt;
          if (result) {&lt;br /&gt;
            addNewCharacter(&lt;br /&gt;
              characters,&lt;br /&gt;
              characters.newCharacterTemplate,&lt;br /&gt;
              characters.charactersContainer,&lt;br /&gt;
              battle,&lt;br /&gt;
              pseudo&lt;br /&gt;
            );&lt;br /&gt;
            saveButtonGreen(characters.saveButton);&lt;br /&gt;
            characters.unsavedChanges = false;&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
        break;&lt;br /&gt;
&lt;br /&gt;
      case &amp;quot;download&amp;quot;:&lt;br /&gt;
        var character = characters.savedCharacters[pseudo];&lt;br /&gt;
        downloadData(&lt;br /&gt;
          JSON.stringify(character),&lt;br /&gt;
          &amp;quot;text/plain&amp;quot;,&lt;br /&gt;
          character.name + &amp;quot;.txt&amp;quot;&lt;br /&gt;
        );&lt;br /&gt;
        break;&lt;br /&gt;
&lt;br /&gt;
      case &amp;quot;delete&amp;quot;:&lt;br /&gt;
        var result = confirm(&lt;br /&gt;
          &amp;quot;Voulez-vous vraiment supprimer définitivement le personnage &amp;quot; +&lt;br /&gt;
          pseudo +&lt;br /&gt;
          &amp;quot; ?&amp;quot;&lt;br /&gt;
        );&lt;br /&gt;
        if (result) {&lt;br /&gt;
          deleteCharacter(characters, pseudo, characterElement, battle);&lt;br /&gt;
        }&lt;br /&gt;
        break;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleNewCharacter(&lt;br /&gt;
  characters,&lt;br /&gt;
  characterTemplate,&lt;br /&gt;
  charactersContainer,&lt;br /&gt;
  battle,&lt;br /&gt;
  pseudo&lt;br /&gt;
) {&lt;br /&gt;
  var newCharacterTemplate = characterTemplate.cloneNode(true);&lt;br /&gt;
  var spanInput = newCharacterTemplate.querySelector(&amp;quot;span.input&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  newCharacterTemplate.setAttribute(&amp;quot;tabindex&amp;quot;, &amp;quot;0&amp;quot;);&lt;br /&gt;
  charactersContainer.appendChild(newCharacterTemplate);&lt;br /&gt;
&lt;br /&gt;
  if (pseudo) {&lt;br /&gt;
    spanInput.textContent = pseudo;&lt;br /&gt;
    spanInput.setAttribute(&amp;quot;data-name&amp;quot;, pseudo);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  newCharacterTemplate.addEventListener(&amp;quot;click&amp;quot;, function (event) {&lt;br /&gt;
    var target = event.target;&lt;br /&gt;
&lt;br /&gt;
    if (target.tagName === &amp;quot;path&amp;quot; || target.tagName === &amp;quot;svg&amp;quot;) {&lt;br /&gt;
      handleClickOnCharacter(&lt;br /&gt;
        spanInput,&lt;br /&gt;
        target,&lt;br /&gt;
        characters,&lt;br /&gt;
        newCharacterTemplate,&lt;br /&gt;
        battle&lt;br /&gt;
      );&lt;br /&gt;
    } else {&lt;br /&gt;
      handleClickOnCharacter(&lt;br /&gt;
        spanInput,&lt;br /&gt;
        null,&lt;br /&gt;
        characters,&lt;br /&gt;
        newCharacterTemplate,&lt;br /&gt;
        battle,&lt;br /&gt;
        true&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  newCharacterTemplate.addEventListener(&amp;quot;keydown&amp;quot;, function (event) {&lt;br /&gt;
    if (event.keyCode === 13) {&lt;br /&gt;
      event.target.click();&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  return [newCharacterTemplate, spanInput];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function validPseudo(pseudo) {&lt;br /&gt;
  var newPseudo = pseudoFormat(pseudo);&lt;br /&gt;
&lt;br /&gt;
  if (!newPseudo) {&lt;br /&gt;
    return &amp;quot;Pseudo&amp;quot;;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return newPseudo;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addNewCharacter(&lt;br /&gt;
  characters,&lt;br /&gt;
  characterTemplate,&lt;br /&gt;
  charactersContainer,&lt;br /&gt;
  battle,&lt;br /&gt;
  pseudoToDuplicate&lt;br /&gt;
) {&lt;br /&gt;
  function editAndSetCharacterPseudoInput(selectedCharacter, spanInput) {&lt;br /&gt;
    var maxPseudoLength = 20;&lt;br /&gt;
&lt;br /&gt;
    var selection = window.getSelection();&lt;br /&gt;
    var range = document.createRange();&lt;br /&gt;
&lt;br /&gt;
    if (pseudoToDuplicate) {&lt;br /&gt;
      spanInput.textContent = pseudoToDuplicate;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    spanInput.contentEditable = true;&lt;br /&gt;
    spanInput.focus();&lt;br /&gt;
    range.selectNodeContents(spanInput);&lt;br /&gt;
    selection.removeAllRanges();&lt;br /&gt;
    selection.addRange(range);&lt;br /&gt;
&lt;br /&gt;
    function pseudoValidation() {&lt;br /&gt;
      var characterPseudo = validPseudo(spanInput.textContent);&lt;br /&gt;
      var characterDataObject = { name: characterPseudo };&lt;br /&gt;
&lt;br /&gt;
      if (pseudoToDuplicate) {&lt;br /&gt;
        characterDataObject = copyObject(&lt;br /&gt;
          characters.savedCharacters[pseudoToDuplicate]&lt;br /&gt;
        );&lt;br /&gt;
        characterDataObject.name = characterPseudo;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      [characterDataObject, characterPseudo] = addUniquePseudo(&lt;br /&gt;
        characterDataObject,&lt;br /&gt;
        Object.keys(characters.savedCharacters)&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      selection.removeAllRanges();&lt;br /&gt;
      spanInput.contentEditable = false;&lt;br /&gt;
      spanInput.textContent = characterPseudo;&lt;br /&gt;
      spanInput.setAttribute(&amp;quot;data-name&amp;quot;, characterPseudo);&lt;br /&gt;
&lt;br /&gt;
      updateForm(&lt;br /&gt;
        characterDataObject,&lt;br /&gt;
        characters.characterCreation,&lt;br /&gt;
        characters,&lt;br /&gt;
        selectedCharacter,&lt;br /&gt;
        battle&lt;br /&gt;
      );&lt;br /&gt;
      saveCharacter(&lt;br /&gt;
        characters.savedCharacters,&lt;br /&gt;
        characters.characterCreation,&lt;br /&gt;
        battle,&lt;br /&gt;
        true&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handleMaxLength(event) {&lt;br /&gt;
      if (spanInput.textContent.length &amp;gt; maxPseudoLength) {&lt;br /&gt;
        spanInput.textContent = spanInput.textContent.slice(0, maxPseudoLength);&lt;br /&gt;
        range.setStart(spanInput.childNodes[0], maxPseudoLength);&lt;br /&gt;
        selection.removeAllRanges();&lt;br /&gt;
        selection.addRange(range);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handleBlur() {&lt;br /&gt;
      spanInput.removeEventListener(&amp;quot;blur&amp;quot;, handleBlur);&lt;br /&gt;
      spanInput.removeEventListener(&amp;quot;input&amp;quot;, handleMaxLength);&lt;br /&gt;
      pseudoValidation();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handleKeyDown(event) {&lt;br /&gt;
      if (event.key === &amp;quot;Enter&amp;quot;) {&lt;br /&gt;
        event.preventDefault();&lt;br /&gt;
&lt;br /&gt;
        spanInput.removeEventListener(&amp;quot;keydown&amp;quot;, handleKeyDown);&lt;br /&gt;
        spanInput.removeEventListener(&amp;quot;blur&amp;quot;, handleBlur);&lt;br /&gt;
        spanInput.removeEventListener(&amp;quot;input&amp;quot;, handleMaxLength);&lt;br /&gt;
&lt;br /&gt;
        pseudoValidation();&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    spanInput.addEventListener(&amp;quot;input&amp;quot;, handleMaxLength);&lt;br /&gt;
    spanInput.addEventListener(&amp;quot;keydown&amp;quot;, handleKeyDown);&lt;br /&gt;
    spanInput.addEventListener(&amp;quot;blur&amp;quot;, handleBlur);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  hideElement(characters.characterCreation);&lt;br /&gt;
  var [selectedCharacter, spanInput] = handleNewCharacter(&lt;br /&gt;
    characters,&lt;br /&gt;
    characterTemplate,&lt;br /&gt;
    charactersContainer,&lt;br /&gt;
    battle&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  editAndSetCharacterPseudoInput(selectedCharacter, spanInput);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleFocus() {&lt;br /&gt;
  var tooltipLinks = document.querySelectorAll(&amp;quot;div.tooltip a&amp;quot;);&lt;br /&gt;
  tooltipLinks.forEach(function (link) {&lt;br /&gt;
    link.setAttribute(&amp;quot;tabindex&amp;quot;, -1);&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleBonusVariationUpdate(characterCreation, bonusVariation) {&lt;br /&gt;
  var selectedBonus = characterCreation.bonusVariation.value;&lt;br /&gt;
&lt;br /&gt;
  if (characterCreation.hasOwnProperty(selectedBonus)) {&lt;br /&gt;
    handleBonusVariation(characterCreation[selectedBonus], bonusVariation);&lt;br /&gt;
  } else {&lt;br /&gt;
    var { minValue, maxValue } = bonusVariation;&lt;br /&gt;
&lt;br /&gt;
    minValue.removeAttribute(&amp;quot;min&amp;quot;);&lt;br /&gt;
    minValue.removeAttribute(&amp;quot;max&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    maxValue.removeAttribute(&amp;quot;min&amp;quot;);&lt;br /&gt;
    maxValue.removeAttribute(&amp;quot;max&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    hideElement(bonusVariation.container);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getTargetContent(targetParent, targetName, isSkill) {&lt;br /&gt;
  var targetContent = &amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  if (targetParent.children.length &amp;lt;= 1) {&lt;br /&gt;
    targetContent = targetParent.textContent;&lt;br /&gt;
  } else if (targetName === &amp;quot;weaponUpgrade&amp;quot;) {&lt;br /&gt;
    targetContent = targetParent.children[1].textContent;&lt;br /&gt;
  } else if (isSkill) {&lt;br /&gt;
    var container = targetParent.children[1];&lt;br /&gt;
&lt;br /&gt;
    for (var index = 1; index &amp;lt; container.children.length; index++) {&lt;br /&gt;
      var element = container.children[index];&lt;br /&gt;
&lt;br /&gt;
      if (element.checkVisibility()) {&lt;br /&gt;
        targetContent += element.textContent;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    for (var index = 1; index &amp;lt; targetParent.children.length; index++) {&lt;br /&gt;
      var element = targetParent.children[index];&lt;br /&gt;
&lt;br /&gt;
      if (element.checkVisibility()) {&lt;br /&gt;
        targetContent += element.textContent;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return targetContent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleBonusVariation(target, bonusVariation, isSelectedByUser) {&lt;br /&gt;
  var { activation, inputDisplay, minValue, maxValue, container } =&lt;br /&gt;
    bonusVariation;&lt;br /&gt;
&lt;br /&gt;
  var {&lt;br /&gt;
    min: targetMin,&lt;br /&gt;
    max: targetMax,&lt;br /&gt;
    name: targetName,&lt;br /&gt;
    value: targetValue,&lt;br /&gt;
    parentElement: targetParent,&lt;br /&gt;
    tagName,&lt;br /&gt;
  } = target;&lt;br /&gt;
&lt;br /&gt;
  targetMin = Number(targetMin);&lt;br /&gt;
  targetMax = Number(targetMax);&lt;br /&gt;
  targetValue = Number(targetValue);&lt;br /&gt;
&lt;br /&gt;
  var isSkill = tagName === &amp;quot;SELECT&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  if (container.contains(target) || targetName == 0) {&lt;br /&gt;
    if (!isSelectedByUser) {&lt;br /&gt;
      hideElement(container);&lt;br /&gt;
    }&lt;br /&gt;
    return;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (isSkill) {&lt;br /&gt;
    var options = target.options;&lt;br /&gt;
&lt;br /&gt;
    targetMin = options[0].value;&lt;br /&gt;
    targetMax = options[options.length - 1].value;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  minValue.min = targetMin;&lt;br /&gt;
  minValue.max = targetMax;&lt;br /&gt;
&lt;br /&gt;
  maxValue.min = targetMin;&lt;br /&gt;
  maxValue.max = targetMax;&lt;br /&gt;
&lt;br /&gt;
  if (isSelectedByUser) {&lt;br /&gt;
    var { input, tab } = bonusVariation;&lt;br /&gt;
&lt;br /&gt;
    inputDisplay.value = getTargetContent(targetParent, targetName, isSkill);&lt;br /&gt;
&lt;br /&gt;
    input.value = targetName;&lt;br /&gt;
    minValue.value = Math.max(targetValue - 10, targetMin);&lt;br /&gt;
    maxValue.value = Math.min(targetValue + 10, targetMax);&lt;br /&gt;
&lt;br /&gt;
    activation.checked = true;&lt;br /&gt;
&lt;br /&gt;
    tab.click();&lt;br /&gt;
    tab.scrollIntoView(true);&lt;br /&gt;
&lt;br /&gt;
    input.dispatchEvent(new Event(&amp;quot;change&amp;quot;, { bubbles: true }));&lt;br /&gt;
  } else {&lt;br /&gt;
    if (minValue.value &amp;lt; targetMin) {&lt;br /&gt;
      minValue.value = targetMin;&lt;br /&gt;
      minValue.dispatchEvent(new Event(&amp;quot;change&amp;quot;, { bubbles: true }));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (maxValue.value &amp;gt; targetMax) {&lt;br /&gt;
      maxValue.value = targetMax;&lt;br /&gt;
      maxValue.dispatchEvent(new Event(&amp;quot;change&amp;quot;, { bubbles: true }));&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  inputDisplay.style.width = inputDisplay.value.length * 0.55 + &amp;quot;em&amp;quot;;&lt;br /&gt;
  showElement(container);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function characterManagement(characters, battle) {&lt;br /&gt;
  var {&lt;br /&gt;
    newCharacterTemplate: characterTemplate,&lt;br /&gt;
    charactersContainer,&lt;br /&gt;
    addNewCharacterButton,&lt;br /&gt;
    saveButton,&lt;br /&gt;
    characterCreation,&lt;br /&gt;
    bonusVariation,&lt;br /&gt;
  } = characters;&lt;br /&gt;
&lt;br /&gt;
  Object.keys(characters.savedCharacters).forEach(function (pseudo) {&lt;br /&gt;
    handleNewCharacter(&lt;br /&gt;
      characters,&lt;br /&gt;
      characterTemplate,&lt;br /&gt;
      charactersContainer,&lt;br /&gt;
      battle,&lt;br /&gt;
      pseudo&lt;br /&gt;
    );&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  addNewCharacterButton.addEventListener(&amp;quot;click&amp;quot;, function (event) {&lt;br /&gt;
    if (!characters.unsavedChanges) {&lt;br /&gt;
      addNewCharacter(&lt;br /&gt;
        characters,&lt;br /&gt;
        characterTemplate,&lt;br /&gt;
        charactersContainer,&lt;br /&gt;
        battle&lt;br /&gt;
      );&lt;br /&gt;
    } else {&lt;br /&gt;
      var result = confirm(&lt;br /&gt;
        &amp;quot;Voulez-vous continuer ? Les dernières modifications ne seront pas sauvegardées.&amp;quot;&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      if (result) {&lt;br /&gt;
        addNewCharacter(&lt;br /&gt;
          characters,&lt;br /&gt;
          characterTemplate,&lt;br /&gt;
          charactersContainer,&lt;br /&gt;
          battle&lt;br /&gt;
        );&lt;br /&gt;
        saveButtonGreen(saveButton);&lt;br /&gt;
        characters.unsavedChanges = false;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  handleUploadCharacter(&lt;br /&gt;
    characters,&lt;br /&gt;
    characterTemplate,&lt;br /&gt;
    charactersContainer,&lt;br /&gt;
    battle&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;change&amp;quot;, function () {&lt;br /&gt;
    saveButtonOrange(saveButton);&lt;br /&gt;
    characters.unsavedChanges = true;&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  function handleLongPress(target) {&lt;br /&gt;
    if (target.tagName !== &amp;quot;INPUT&amp;quot; &amp;amp;&amp;amp; target.tagName !== &amp;quot;SELECT&amp;quot;) {&lt;br /&gt;
      target = target.querySelector(&amp;quot;input&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      !target ||&lt;br /&gt;
      (target.type !== &amp;quot;number&amp;quot; &amp;amp;&amp;amp;&lt;br /&gt;
        !target.classList.contains(&amp;quot;skill-select&amp;quot;) &amp;amp;&amp;amp;&lt;br /&gt;
        target.name !== &amp;quot;weaponUpgrade&amp;quot;)&lt;br /&gt;
    ) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    handleBonusVariation(target, bonusVariation, true);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;click&amp;quot;, function (event) {&lt;br /&gt;
    if (event.shiftKey || event.ctrlKey) {&lt;br /&gt;
      handleLongPress(event.target);&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  var longPressTimer;&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;touchstart&amp;quot;, function (event) {&lt;br /&gt;
    longPressTimer = setTimeout(function () {&lt;br /&gt;
      handleLongPress(event.target);&lt;br /&gt;
    }, 800);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;touchend&amp;quot;, function () {&lt;br /&gt;
    clearTimeout(longPressTimer);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;touchmove&amp;quot;, function () {&lt;br /&gt;
    clearTimeout(longPressTimer);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  filterForm(characters, battle);&lt;br /&gt;
  characterCreationListener(characters, battle);&lt;br /&gt;
  handleFocus();&lt;br /&gt;
&lt;br /&gt;
  window.addEventListener(&amp;quot;beforeunload&amp;quot;, function (event) {&lt;br /&gt;
    if (characters.unsavedChanges) {&lt;br /&gt;
      event.preventDefault();&lt;br /&gt;
      return &amp;quot;&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function removeFromIframe(iframe, monsterVnum, addButton) {&lt;br /&gt;
  var iframeDoc = iframe.contentDocument || iframe.contentWindow.document;&lt;br /&gt;
  var removeButton = iframeDoc.querySelector(&lt;br /&gt;
    &amp;quot;.handle-monster[data-monster-id='&amp;quot; + monsterVnum + &amp;quot;']&amp;quot;&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  if (removeButton) {&lt;br /&gt;
    replaceMonsterButton(removeButton, addButton, monsterVnum);&lt;br /&gt;
    return true;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return false;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addMonsterElement(characters, battle, monsterVnum) {&lt;br /&gt;
  var {&lt;br /&gt;
    monsteriFrame,&lt;br /&gt;
    stoneiFrame,&lt;br /&gt;
    monsterTemplate,&lt;br /&gt;
    monstersContainer,&lt;br /&gt;
    monsterButtonTemplates,&lt;br /&gt;
  } = characters;&lt;br /&gt;
  var addButton = monsterButtonTemplates.children[0];&lt;br /&gt;
  var monsterElement = monsterTemplate.cloneNode(true);&lt;br /&gt;
&lt;br /&gt;
  var spanInput = monsterElement.querySelector(&amp;quot;span.input&amp;quot;);&lt;br /&gt;
  var deleteSvg = monsterElement.querySelector(&amp;quot;svg&amp;quot;);&lt;br /&gt;
  var monsterName = getMonsterName(monsterVnum);&lt;br /&gt;
&lt;br /&gt;
  var link = document.createElement(&amp;quot;a&amp;quot;);&lt;br /&gt;
  link.href = mw.util.getUrl(monsterName);&lt;br /&gt;
  link.title = monsterName;&lt;br /&gt;
  link.textContent = monsterName;&lt;br /&gt;
&lt;br /&gt;
  spanInput.appendChild(link);&lt;br /&gt;
&lt;br /&gt;
  monsterElement.setAttribute(&amp;quot;tabindex&amp;quot;, &amp;quot;0&amp;quot;);&lt;br /&gt;
  monsterElement.setAttribute(&amp;quot;data-monster-id&amp;quot;, monsterVnum);&lt;br /&gt;
&lt;br /&gt;
  monstersContainer.appendChild(monsterElement);&lt;br /&gt;
&lt;br /&gt;
  deleteSvg.addEventListener(&amp;quot;click&amp;quot;, function () {&lt;br /&gt;
    deleteMonster(characters, battle, monsterVnum, monsterElement);&lt;br /&gt;
    var isRemoved = removeFromIframe(monsteriFrame, monsterVnum, addButton);&lt;br /&gt;
    if (!isRemoved) {&lt;br /&gt;
      removeFromIframe(stoneiFrame, monsterVnum, addButton);&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addNewMonster(characters, battle, monsterVnum, monsterImage) {&lt;br /&gt;
  if (isValueInArray(monsterVnum, Object.keys(characters.savedMonsters)))&lt;br /&gt;
    return;&lt;br /&gt;
&lt;br /&gt;
  characters.savedMonsters[monsterVnum] = { image: monsterImage };&lt;br /&gt;
  addMonsterElement(characters, battle, monsterVnum);&lt;br /&gt;
  updateSavedMonsters(characters.savedMonsters);&lt;br /&gt;
  addBattleChoice(battle, monsterVnum, true);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function replaceMonsterButton(currentButton, newButton, monsterVnum) {&lt;br /&gt;
  var newButtonClone = newButton.cloneNode(true);&lt;br /&gt;
  newButtonClone.dataset.monsterId = monsterVnum;&lt;br /&gt;
  currentButton.replaceWith(newButtonClone);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addButtonsToCards(&lt;br /&gt;
  iframeDoc,&lt;br /&gt;
  nameToVnum,&lt;br /&gt;
  addButton,&lt;br /&gt;
  removeButton,&lt;br /&gt;
  characters&lt;br /&gt;
) {&lt;br /&gt;
  var cardToEdit = iframeDoc.getElementById(&amp;quot;cards-container&amp;quot;).children;&lt;br /&gt;
  var addedMonsters = Object.keys(characters.savedMonsters);&lt;br /&gt;
&lt;br /&gt;
  for (var cardIndex = 0; cardIndex &amp;lt; cardToEdit.length; cardIndex++) {&lt;br /&gt;
    var card = cardToEdit[cardIndex];&lt;br /&gt;
    var cardName = card.querySelector(&amp;quot;[data-name]&amp;quot;).firstChild.title;&lt;br /&gt;
&lt;br /&gt;
    cardName = cardName.replace(/\s/g, &amp;quot; &amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (!nameToVnum.hasOwnProperty(cardName)) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var monsterVnum = nameToVnum[cardName];&lt;br /&gt;
    var buttonClone;&lt;br /&gt;
&lt;br /&gt;
    if (isValueInArray(monsterVnum, addedMonsters)) {&lt;br /&gt;
      buttonClone = removeButton.cloneNode(true);&lt;br /&gt;
    } else {&lt;br /&gt;
      buttonClone = addButton.cloneNode(true);&lt;br /&gt;
    }&lt;br /&gt;
    buttonClone.dataset.monsterId = monsterVnum;&lt;br /&gt;
    card.lastElementChild.appendChild(buttonClone);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getMonsterImage(addButton) {&lt;br /&gt;
  var elder = addButton.parentElement.firstElementChild;&lt;br /&gt;
  var image = elder.querySelector(&amp;quot;img&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (image) {&lt;br /&gt;
    return image.getAttribute(&amp;quot;src&amp;quot;) || &amp;quot;&amp;quot;;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return &amp;quot;&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleiFrame(category, iframe, nameToVnum, characters, battle) {&lt;br /&gt;
  var [addButton, removeButton] = characters.monsterButtonTemplates.children;&lt;br /&gt;
  var loadingAnimation = iframe.previousElementSibling;&lt;br /&gt;
&lt;br /&gt;
  iframe.src = mw.util.getUrl(category);&lt;br /&gt;
&lt;br /&gt;
  iframe.addEventListener(&amp;quot;load&amp;quot;, function () {&lt;br /&gt;
    var iframeDoc = this.contentDocument || this.contentWindow.document;&lt;br /&gt;
    var iframeBody = iframeDoc.body;&lt;br /&gt;
&lt;br /&gt;
    content = iframeDoc.getElementById(&amp;quot;show-after-loading&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    iframeBody.firstElementChild.replaceWith(content);&lt;br /&gt;
&lt;br /&gt;
    iframeBody.style.background = &amp;quot;transparent&amp;quot;;&lt;br /&gt;
    iframeBody.style.paddingRight = &amp;quot;10px&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    addButtonsToCards(&lt;br /&gt;
      iframeDoc,&lt;br /&gt;
      nameToVnum,&lt;br /&gt;
      addButton,&lt;br /&gt;
      removeButton,&lt;br /&gt;
      characters&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    hideElement(loadingAnimation);&lt;br /&gt;
    showElement(iframe);&lt;br /&gt;
&lt;br /&gt;
    iframeDoc.addEventListener(&amp;quot;click&amp;quot;, function (event) {&lt;br /&gt;
      var target = event.target;&lt;br /&gt;
      var link = target.closest(&amp;quot;a&amp;quot;);&lt;br /&gt;
      var currentButton = target.closest(&amp;quot;.handle-monster&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
      if (link) {&lt;br /&gt;
        event.preventDefault();&lt;br /&gt;
        window.open(link.href, &amp;quot;_blank&amp;quot;);&lt;br /&gt;
      } else if (currentButton) {&lt;br /&gt;
        var { monsterId: monsterVnum, action } = currentButton.dataset;&lt;br /&gt;
        var newButton;&lt;br /&gt;
&lt;br /&gt;
        if (action === &amp;quot;add&amp;quot;) {&lt;br /&gt;
          var monsterImage = getMonsterImage(currentButton);&lt;br /&gt;
          addNewMonster(characters, battle, monsterVnum, monsterImage);&lt;br /&gt;
          newButton = removeButton;&lt;br /&gt;
        } else if (action === &amp;quot;remove&amp;quot;) {&lt;br /&gt;
          deleteMonster(characters, battle, monsterVnum);&lt;br /&gt;
          newButton = addButton;&lt;br /&gt;
        }&lt;br /&gt;
        replaceMonsterButton(currentButton, newButton, monsterVnum);&lt;br /&gt;
      }&lt;br /&gt;
    });&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getNameToVnumMapping() {&lt;br /&gt;
  var nameToVnum = {};&lt;br /&gt;
&lt;br /&gt;
  for (var monsterVnum in monsterData) {&lt;br /&gt;
    nameToVnum[monsterData[monsterVnum][monsterData[monsterVnum].length - 1]] =&lt;br /&gt;
      monsterVnum;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return nameToVnum;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function monsterManagement(characters, battle) {&lt;br /&gt;
  var { monsteriFrame, stoneiFrame } = characters;&lt;br /&gt;
  var nameToVnum = getNameToVnumMapping();&lt;br /&gt;
  var monsterVnums = Object.keys(monsterData);&lt;br /&gt;
&lt;br /&gt;
  var iframeLoaded = { monster: false, stone: false };&lt;br /&gt;
&lt;br /&gt;
  document.addEventListener(&amp;quot;modalOpen&amp;quot;, function (event) {&lt;br /&gt;
    var modalName = event.detail.name;&lt;br /&gt;
&lt;br /&gt;
    if (modalName === &amp;quot;monster&amp;quot; &amp;amp;&amp;amp; !iframeLoaded.monster) {&lt;br /&gt;
      handleiFrame(&amp;quot;Monstres&amp;quot;, monsteriFrame, nameToVnum, characters, battle);&lt;br /&gt;
      iframeLoaded.monster = true;&lt;br /&gt;
    } else if (modalName === &amp;quot;stone&amp;quot; &amp;amp;&amp;amp; !iframeLoaded.stone) {&lt;br /&gt;
      handleiFrame(&lt;br /&gt;
        &amp;quot;Pierres Metin&amp;quot;,&lt;br /&gt;
        stoneiFrame,&lt;br /&gt;
        nameToVnum,&lt;br /&gt;
        characters,&lt;br /&gt;
        battle&lt;br /&gt;
      );&lt;br /&gt;
      iframeLoaded.stone = true;&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  Object.keys(characters.savedMonsters)&lt;br /&gt;
    .slice()&lt;br /&gt;
    .forEach(function (monsterVnum) {&lt;br /&gt;
      if (isValueInArray(monsterVnum, monsterVnums)) {&lt;br /&gt;
        addMonsterElement(characters, battle, monsterVnum);&lt;br /&gt;
      } else {&lt;br /&gt;
        deleteMonster(characters, battle, monsterVnum);&lt;br /&gt;
      }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function removeBattleChoice(battle, name) {&lt;br /&gt;
  var battleSelects = [battle.attackerSelection, battle.victimSelection];&lt;br /&gt;
&lt;br /&gt;
  battleSelects.forEach(function (battleSelect) {&lt;br /&gt;
    for (&lt;br /&gt;
      var optionIndex = 0;&lt;br /&gt;
      optionIndex &amp;lt; battleSelect.options.length;&lt;br /&gt;
      optionIndex++&lt;br /&gt;
    ) {&lt;br /&gt;
      if (battleSelect.options[optionIndex].value === name) {&lt;br /&gt;
        battleSelect.remove(optionIndex);&lt;br /&gt;
        break;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addBattleChoice(battle, name, isMonster = false) {&lt;br /&gt;
  function createOption(text, vnum) {&lt;br /&gt;
    var option = document.createElement(&amp;quot;option&amp;quot;);&lt;br /&gt;
    option.textContent = text;&lt;br /&gt;
    option.value = vnum;&lt;br /&gt;
&lt;br /&gt;
    if (!isMonster) {&lt;br /&gt;
      option.classList.add(&amp;quot;notranslate&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return option;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var vnum = name;&lt;br /&gt;
&lt;br /&gt;
  if (isMonster) {&lt;br /&gt;
    name = getMonsterName(name);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (isMonster &amp;amp;&amp;amp; monsterData[vnum][1]) {&lt;br /&gt;
    // pass&lt;br /&gt;
  } else {&lt;br /&gt;
    battle.attackerSelection.appendChild(createOption(name, vnum));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  battle.victimSelection.appendChild(createOption(name, vnum));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateBattleChoice(characters, battle) {&lt;br /&gt;
  function addChoices(names, isMonster) {&lt;br /&gt;
    for (var index = 0; index &amp;lt; names.length; index++) {&lt;br /&gt;
      addBattleChoice(battle, names[index], isMonster);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var characterNames = Object.keys(characters.savedCharacters);&lt;br /&gt;
  var monsterNames = Object.keys(characters.savedMonsters);&lt;br /&gt;
&lt;br /&gt;
  addChoices(characterNames, false);&lt;br /&gt;
  addChoices(monsterNames, true);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isPC(character) {&lt;br /&gt;
  if (character.race === 0 || character.race === 1) {&lt;br /&gt;
    return false;&lt;br /&gt;
  }&lt;br /&gt;
  return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isBoss(character) {&lt;br /&gt;
  return character.race === 0 &amp;amp;&amp;amp; character.rank &amp;gt;= 5;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isStone(character) {&lt;br /&gt;
  return character.race === 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isMeleeAttacker(monster) {&lt;br /&gt;
  return monster.attack == 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isRangeAttacker(monster) {&lt;br /&gt;
  return monster.attack == 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isMagicAttacker(monster) {&lt;br /&gt;
  return monster.attack == 2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isMagicClass(character) {&lt;br /&gt;
  return character.race === &amp;quot;shaman&amp;quot; || character.class === &amp;quot;black_magic&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isDispell(character, skillId) {&lt;br /&gt;
  return character.class === &amp;quot;weaponary&amp;quot; &amp;amp;&amp;amp; skillId === 6;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isPolymorph(character) {&lt;br /&gt;
  return isChecked(character.isPolymorph);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isRiding(character) {&lt;br /&gt;
  return isChecked(character.isRiding);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isBow(weaponType) {&lt;br /&gt;
  return weaponType === 2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcAttackFactor(attacker, victim) {&lt;br /&gt;
  function calcCoeffK(dex, level) {&lt;br /&gt;
    return Math.min(90, Math.floor((2 * dex + level) / 3));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var K1 = calcCoeffK(attacker.polymorphDex, attacker.level);&lt;br /&gt;
  var K2 = calcCoeffK(victim.polymorphDex, attacker.level);&lt;br /&gt;
&lt;br /&gt;
  var AR = (K1 + 210) / 300;&lt;br /&gt;
  var ER = (((2 * K2 + 5) / (K2 + 95)) * 3) / 10;&lt;br /&gt;
&lt;br /&gt;
  return truncateNumber(AR - ER, 8);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcMainAttackValue(attacker) {&lt;br /&gt;
  var leadership = 0;&lt;br /&gt;
  var weaponGrowth = 0;&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker)) {&lt;br /&gt;
    weaponGrowth = attacker.weapon.growth;&lt;br /&gt;
    leadership = attacker.leadership;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return 2 * (attacker.level + weaponGrowth) + leadership;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcStatAttackValue(character) {&lt;br /&gt;
  switch (character.race) {&lt;br /&gt;
    case &amp;quot;warrior&amp;quot;:&lt;br /&gt;
    case &amp;quot;sura&amp;quot;:&lt;br /&gt;
      return 2 * character.str;&lt;br /&gt;
    case &amp;quot;ninja&amp;quot;:&lt;br /&gt;
      return Math.floor((1 / 4) * (character.str + 7 * character.dex));&lt;br /&gt;
    case &amp;quot;shaman&amp;quot;:&lt;br /&gt;
      return Math.floor((1 / 3) * (5 * character.int + character.dex));&lt;br /&gt;
    case &amp;quot;lycan&amp;quot;:&lt;br /&gt;
      return character.vit + 2 * character.dex;&lt;br /&gt;
    default:&lt;br /&gt;
      return 2 * character.str;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcSecondaryAttackValue(attacker) {&lt;br /&gt;
  var attackValueOther = 0;&lt;br /&gt;
&lt;br /&gt;
  var minAttackValue = 0;&lt;br /&gt;
  var maxAttackValue = 0;&lt;br /&gt;
&lt;br /&gt;
  var minAttackValueSlash = 0;&lt;br /&gt;
  var maxAttackValueSlash = 0;&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker)) {&lt;br /&gt;
    var { type, isSerpent, minAttackValue, maxAttackValue, growth } =&lt;br /&gt;
      attacker.weapon;&lt;br /&gt;
&lt;br /&gt;
    if (isSerpent) {&lt;br /&gt;
      minAttackValue = Math.max(0, attacker.minAttackValueRandom - growth);&lt;br /&gt;
      maxAttackValue = Math.max(&lt;br /&gt;
        minAttackValue,&lt;br /&gt;
        attacker.maxAttackValueRandom - growth&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    minAttackValueSlash = Math.min(&lt;br /&gt;
      attacker.minAttackValueSlash,&lt;br /&gt;
      attacker.maxAttackValueSlash&lt;br /&gt;
    );&lt;br /&gt;
    maxAttackValueSlash = Math.max(&lt;br /&gt;
      attacker.minAttackValueSlash,&lt;br /&gt;
      attacker.maxAttackValueSlash&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    attackValueOther += attacker.attackValue;&lt;br /&gt;
&lt;br /&gt;
    if (isBow(type) &amp;amp;&amp;amp; !isPolymorph(attacker)) {&lt;br /&gt;
      attackValueOther += 25;&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    minAttackValue = attacker.minAttackValue;&lt;br /&gt;
    maxAttackValue = attacker.maxAttackValue;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  minAttackValue += attacker.minAttackValuePolymorph;&lt;br /&gt;
  maxAttackValue += attacker.maxAttackValuePolymorph;&lt;br /&gt;
&lt;br /&gt;
  attackValueOther += attacker.statAttackValue;&lt;br /&gt;
  attackValueOther += attacker.horseAttackValue;&lt;br /&gt;
&lt;br /&gt;
  var weaponInterval = maxAttackValue - minAttackValue + 1;&lt;br /&gt;
  var slashInterval = maxAttackValueSlash - minAttackValueSlash + 1;&lt;br /&gt;
&lt;br /&gt;
  var totalCardinal = weaponInterval * slashInterval * 1_000_000;&lt;br /&gt;
  var minInterval = Math.min(weaponInterval, slashInterval);&lt;br /&gt;
&lt;br /&gt;
  minAttackValue += minAttackValueSlash;&lt;br /&gt;
  maxAttackValue += maxAttackValueSlash;&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    minAttackValue: minAttackValue,&lt;br /&gt;
    maxAttackValue: maxAttackValue,&lt;br /&gt;
    attackValueOther: attackValueOther,&lt;br /&gt;
    totalCardinal: totalCardinal,&lt;br /&gt;
    weights: calcWeights(minAttackValue, maxAttackValue, minInterval),&lt;br /&gt;
    possibleDamagesCount: maxAttackValue - minAttackValue + 1,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcMagicAttackValue(attacker) {&lt;br /&gt;
  var minMagicAttackValueSlash = 0;&lt;br /&gt;
  var maxMagicAttackValueSlash = 0;&lt;br /&gt;
&lt;br /&gt;
  var { isSerpent, minMagicAttackValue, maxMagicAttackValue, growth } =&lt;br /&gt;
    attacker.weapon;&lt;br /&gt;
&lt;br /&gt;
  if (isSerpent) {&lt;br /&gt;
    minMagicAttackValue = Math.max(0, attacker.minMagicAttackValueRandom);&lt;br /&gt;
    maxMagicAttackValue = Math.max(&lt;br /&gt;
      minMagicAttackValue,&lt;br /&gt;
      attacker.maxMagicAttackValueRandom&lt;br /&gt;
    );&lt;br /&gt;
  } else {&lt;br /&gt;
    minMagicAttackValue += growth;&lt;br /&gt;
    maxMagicAttackValue += growth;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  minMagicAttackValueSlash = Math.min(&lt;br /&gt;
    attacker.minMagicAttackValueSlash,&lt;br /&gt;
    attacker.maxMagicAttackValueSlash&lt;br /&gt;
  );&lt;br /&gt;
  maxMagicAttackValueSlash = Math.max(&lt;br /&gt;
    attacker.minMagicAttackValueSlash,&lt;br /&gt;
    attacker.maxMagicAttackValueSlash&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  var weaponInterval = maxMagicAttackValue - minMagicAttackValue + 1;&lt;br /&gt;
  var slashInterval = maxMagicAttackValueSlash - minMagicAttackValueSlash + 1;&lt;br /&gt;
&lt;br /&gt;
  var totalCardinal = weaponInterval * slashInterval * 1_000_000;&lt;br /&gt;
  var minInterval = Math.min(weaponInterval, slashInterval);&lt;br /&gt;
&lt;br /&gt;
  minMagicAttackValue += minMagicAttackValueSlash;&lt;br /&gt;
  maxMagicAttackValue += maxMagicAttackValueSlash;&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    minMagicAttackValue: minMagicAttackValue,&lt;br /&gt;
    maxMagicAttackValue: maxMagicAttackValue,&lt;br /&gt;
    magicAttackValueAugmentation: getMagicAttackValueAugmentation(&lt;br /&gt;
      minMagicAttackValue,&lt;br /&gt;
      maxMagicAttackValue,&lt;br /&gt;
      attacker.magicAttackValue&lt;br /&gt;
    ),&lt;br /&gt;
    totalCardinal: totalCardinal,&lt;br /&gt;
    weights: calcWeights(minMagicAttackValue, maxMagicAttackValue, minInterval),&lt;br /&gt;
    possibleDamagesCount: maxMagicAttackValue - minMagicAttackValue + 1,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getPolymorphPower(polymorphPoint, polymorphPowerTable) {&lt;br /&gt;
  return polymorphPowerTable[polymorphPoint];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSkillPower(skillPoint, skillPowerTable) {&lt;br /&gt;
  return skillPowerTable[skillPoint];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getMarriageBonusValue(character, marriageTable, itemName) {&lt;br /&gt;
  var index;&lt;br /&gt;
  var lovePoint = character.lovePoint;&lt;br /&gt;
&lt;br /&gt;
  if (lovePoint &amp;lt; 65) {&lt;br /&gt;
    index = 0;&lt;br /&gt;
  } else if (lovePoint &amp;lt; 80) {&lt;br /&gt;
    index = 1;&lt;br /&gt;
  } else if (lovePoint &amp;lt; 100) {&lt;br /&gt;
    index = 2;&lt;br /&gt;
  } else {&lt;br /&gt;
    index = 3;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return marriageTable[itemName][index];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcDamageWithPrimaryBonuses(damages, bonusValues) {&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.attackValueCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  damages += bonusValues.attackValueMarriage;&lt;br /&gt;
&lt;br /&gt;
  damages = Math.floor(&lt;br /&gt;
    (damages * bonusValues.monsterResistanceMarriageCoeff) / 100&lt;br /&gt;
  );&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.monsterResistanceCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  damages += Math.floor((damages * bonusValues.typeBonusCoeff) / 100);&lt;br /&gt;
  damages +=&lt;br /&gt;
    Math.floor((damages * bonusValues.raceBonusCoeff) / 100) -&lt;br /&gt;
    Math.floor((damages * bonusValues.raceResistanceCoeff) / 100);&lt;br /&gt;
  damages += Math.floor((damages * bonusValues.stoneBonusCoeff) / 100);&lt;br /&gt;
  damages += Math.floor((damages * bonusValues.monsterBonusCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  var elementBonusCoeff = bonusValues.elementBonusCoeff;&lt;br /&gt;
&lt;br /&gt;
  damages +=&lt;br /&gt;
    Math.trunc((damages * elementBonusCoeff[0]) / 10000) +&lt;br /&gt;
    Math.trunc((damages * elementBonusCoeff[1]) / 10000) +&lt;br /&gt;
    Math.trunc((damages * elementBonusCoeff[2]) / 10000) +&lt;br /&gt;
    Math.trunc((damages * elementBonusCoeff[3]) / 10000) +&lt;br /&gt;
    Math.trunc((damages * elementBonusCoeff[4]) / 10000) +&lt;br /&gt;
    Math.trunc((damages * elementBonusCoeff[5]) / 10000);&lt;br /&gt;
&lt;br /&gt;
  damages = Math.floor(damages * bonusValues.damageMultiplier);&lt;br /&gt;
&lt;br /&gt;
  return damages;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcDamageWithSecondaryBonuses(&lt;br /&gt;
  damages,&lt;br /&gt;
  bonusValues,&lt;br /&gt;
  damagesType,&lt;br /&gt;
  minPiercingDamages,&lt;br /&gt;
  damagesWithPrimaryBonuses&lt;br /&gt;
) {&lt;br /&gt;
  damages = Math.floor(damages * bonusValues.magicResistanceCoeff);&lt;br /&gt;
  damages = Math.trunc((damages * bonusValues.weaponDefenseCoeff) / 100);&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.tigerStrengthCoeff) / 100);&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.blessingBonusCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  if (damagesType.criticalHit) {&lt;br /&gt;
    damages *= 2;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (damagesType.piercingHit) {&lt;br /&gt;
    damages += bonusValues.defenseBoost + Math.min(0, minPiercingDamages);&lt;br /&gt;
    damages += Math.floor(&lt;br /&gt;
      (damagesWithPrimaryBonuses * bonusValues.extraPiercingHitCoeff) / 1000&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.averageDamageCoeff) / 100);&lt;br /&gt;
  damages = Math.floor(&lt;br /&gt;
    (damages * bonusValues.averageDamageResistanceCoeff) / 100&lt;br /&gt;
  );&lt;br /&gt;
  damages = Math.floor(&lt;br /&gt;
    (damages * bonusValues.skillDamageResistanceCoeff) / 100&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.rankBonusCoeff) / 100);&lt;br /&gt;
  damages = Math.max(0, damages + bonusValues.defensePercent);&lt;br /&gt;
  damages += Math.min(&lt;br /&gt;
    300,&lt;br /&gt;
    Math.floor((damages * bonusValues.damageBonusCoeff) / 100)&lt;br /&gt;
  );&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.empireMalusCoeff) / 10);&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.sungMaStrBonusCoeff) / 10000);&lt;br /&gt;
  damages -= Math.floor(damages * bonusValues.sungmaStrMalusCoeff);&lt;br /&gt;
&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.whiteDragonElixirCoeff) / 100);&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.steelDragonElixirCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  return damages;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcSkillDamageWithSecondaryBonuses(&lt;br /&gt;
  damages,&lt;br /&gt;
  bonusValues,&lt;br /&gt;
  damagesType,&lt;br /&gt;
  minPiercingDamages&lt;br /&gt;
) {&lt;br /&gt;
  damages = Math.floor(damages * bonusValues.magicResistanceCoeff);&lt;br /&gt;
  damages = Math.trunc((damages * bonusValues.weaponDefenseCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  damages -= bonusValues.defense;&lt;br /&gt;
&lt;br /&gt;
  damages = floorMultiplication(damages, bonusValues.skillWardCoeff);&lt;br /&gt;
  damages = floorMultiplication(damages, bonusValues.skillBonusCoeff);&lt;br /&gt;
&lt;br /&gt;
  var tempDamages = Math.floor(&lt;br /&gt;
    (damages * bonusValues.skillBonusByBonusCoeff) / 100&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  damages = Math.floor(&lt;br /&gt;
    (tempDamages * bonusValues.magicAttackValueCoeff) / 100 + 0.5&lt;br /&gt;
  );&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.tigerStrengthCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  if (damagesType.criticalHit) {&lt;br /&gt;
    damages *= 2;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (damagesType.piercingHit) {&lt;br /&gt;
    damages += bonusValues.defenseBoost + Math.min(0, minPiercingDamages);&lt;br /&gt;
    damages += Math.floor(&lt;br /&gt;
      (tempDamages * bonusValues.extraPiercingHitCoeff) / 1000&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.skillDamageCoeff) / 100);&lt;br /&gt;
  damages = Math.floor(&lt;br /&gt;
    (damages * bonusValues.skillDamageResistanceCoeff) / 100&lt;br /&gt;
  );&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.rankBonusCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  damages = Math.max(0, damages + bonusValues.defensePercent);&lt;br /&gt;
  damages += Math.min(&lt;br /&gt;
    300,&lt;br /&gt;
    Math.floor((damages * bonusValues.damageBonusCoeff) / 100)&lt;br /&gt;
  );&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.empireMalusCoeff) / 10);&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.sungMaStrBonusCoeff) / 10000);&lt;br /&gt;
  damages -= Math.floor(damages * bonusValues.sungmaStrMalusCoeff);&lt;br /&gt;
&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.whiteDragonElixirCoeff) / 100);&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.steelDragonElixirCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  return damages;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function computePolymorphPoint(attacker, victim, polymorphPowerTable) {&lt;br /&gt;
  attacker.statAttackValue = 0;&lt;br /&gt;
&lt;br /&gt;
  attacker.polymorphDex = attacker.dex;&lt;br /&gt;
  victim.polymorphDex = victim.dex;&lt;br /&gt;
&lt;br /&gt;
  attacker.minAttackValuePolymorph = 0;&lt;br /&gt;
  attacker.maxAttackValuePolymorph = 0;&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker) &amp;amp;&amp;amp; isPolymorph(attacker)) {&lt;br /&gt;
    var polymorphPowerPct =&lt;br /&gt;
      getPolymorphPower(attacker.polymorphPoint, polymorphPowerTable) / 100;&lt;br /&gt;
    var polymorphMonster = createMonster(attacker.polymorphMonster);&lt;br /&gt;
&lt;br /&gt;
    var polymorphStr = floorMultiplication(&lt;br /&gt;
      polymorphPowerPct,&lt;br /&gt;
      polymorphMonster.str&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    attacker.polymorphDex += floorMultiplication(&lt;br /&gt;
      polymorphPowerPct,&lt;br /&gt;
      polymorphMonster.dex&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    attacker.minAttackValuePolymorph = floorMultiplication(&lt;br /&gt;
      polymorphPowerPct,&lt;br /&gt;
      polymorphMonster.minAttackValue&lt;br /&gt;
    );&lt;br /&gt;
    attacker.maxAttackValuePolymorph = floorMultiplication(&lt;br /&gt;
      polymorphPowerPct,&lt;br /&gt;
      polymorphMonster.maxAttackValue&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    if (!attacker.weapon) {&lt;br /&gt;
      attacker.maxAttackValuePolymorph += 1;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    attacker.attackValue = 0;&lt;br /&gt;
&lt;br /&gt;
    if (isMagicClass(attacker)) {&lt;br /&gt;
      attacker.statAttackValue = 2 * (polymorphStr + attacker.int);&lt;br /&gt;
    } else {&lt;br /&gt;
      attacker.statAttackValue = 2 * (polymorphStr + attacker.str);&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    attacker.statAttackValue = calcStatAttackValue(attacker);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function computeHorse(attacker) {&lt;br /&gt;
  attacker.horseAttackValue = 0;&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker) &amp;amp;&amp;amp; isRiding(attacker)) {&lt;br /&gt;
    var horseConstant = 30;&lt;br /&gt;
&lt;br /&gt;
    if (attacker.class === &amp;quot;weaponary&amp;quot;) {&lt;br /&gt;
      horseConstant = 60;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    attacker.horseAttackValue = floorMultiplication(&lt;br /&gt;
      2 * attacker.level + attacker.statAttackValue,&lt;br /&gt;
      attacker.horsePoint / horseConstant&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getRankBonus(attacker) {&lt;br /&gt;
  if (!isChecked(attacker.lowRank)) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  switch (attacker.playerRank) {&lt;br /&gt;
    case &amp;quot;aggressive&amp;quot;:&lt;br /&gt;
      return 1;&lt;br /&gt;
    case &amp;quot;fraudulent&amp;quot;:&lt;br /&gt;
      return 2;&lt;br /&gt;
    case &amp;quot;malicious&amp;quot;:&lt;br /&gt;
      return 3;&lt;br /&gt;
    case &amp;quot;cruel&amp;quot;:&lt;br /&gt;
      return 5;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcElementCoeffPvP(elementBonus, mapping, attacker, victim) {&lt;br /&gt;
  var minElementMalus = 0;&lt;br /&gt;
  var maxDifference = 0;&lt;br /&gt;
  var savedElementDifferences = [];&lt;br /&gt;
  var elementBonusIndex = 0;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; elementBonus.length; index++) {&lt;br /&gt;
    if (!attacker[mapping.elementBonus[index]]) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var elementDifference =&lt;br /&gt;
      attacker[mapping.elementBonus[index]] -&lt;br /&gt;
      victim[mapping.elementResistance[index]];&lt;br /&gt;
&lt;br /&gt;
    if (elementDifference &amp;gt;= 0) {&lt;br /&gt;
      elementBonus[elementBonusIndex] = 10 * elementDifference;&lt;br /&gt;
      minElementMalus -= elementDifference;&lt;br /&gt;
      maxDifference = Math.max(maxDifference, elementDifference);&lt;br /&gt;
      elementBonusIndex++;&lt;br /&gt;
    } else {&lt;br /&gt;
      savedElementDifferences.push(elementDifference);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (!savedElementDifferences.length) {&lt;br /&gt;
    return;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  minElementMalus += maxDifference;&lt;br /&gt;
  savedElementDifferences.sort(compareNumbers);&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; savedElementDifferences.length; index++) {&lt;br /&gt;
    var elementDifference = savedElementDifferences[index];&lt;br /&gt;
&lt;br /&gt;
    elementBonus[elementBonusIndex + index] =&lt;br /&gt;
      10 * Math.max(minElementMalus, elementDifference);&lt;br /&gt;
&lt;br /&gt;
    minElementMalus = Math.min(&lt;br /&gt;
      0,&lt;br /&gt;
      Math.max(minElementMalus, minElementMalus - elementDifference)&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function skillChanceReduction(value) {&lt;br /&gt;
  if (value &amp;lt;= 9) {&lt;br /&gt;
    return Math.floor(value / 2);&lt;br /&gt;
  }&lt;br /&gt;
  return 5 + Math.floor((value - 10) / 4);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function magicResistanceToCoeff(magicResistance) {&lt;br /&gt;
  if (magicResistance) {&lt;br /&gt;
    return 2000 / (6 * magicResistance + 1000) - 1;&lt;br /&gt;
  }&lt;br /&gt;
  return 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createBattleValues(attacker, victim, battle, skillType) {&lt;br /&gt;
  var { mapping, constants } = battle;&lt;br /&gt;
  var calcAttackValues;&lt;br /&gt;
&lt;br /&gt;
  var missPercentage = 0;&lt;br /&gt;
  var attackValueMeleeMagic = 0;&lt;br /&gt;
  var attackValueMarriage = 0;&lt;br /&gt;
  var monsterResistanceMarriage = 0;&lt;br /&gt;
  var monsterResistance = 0;&lt;br /&gt;
  var typeBonus = 0;&lt;br /&gt;
  var raceBonus = 0;&lt;br /&gt;
  var raceResistance = 0;&lt;br /&gt;
  var stoneBonus = 0;&lt;br /&gt;
  var monsterBonus = 0;&lt;br /&gt;
  var elementBonus = [0, 0, 0, 0, 0, 0]; // fire, ice, lightning, earth, darkness, wind, order doesn't matter&lt;br /&gt;
  var defenseMarriage = 0;&lt;br /&gt;
  var damageMultiplier = 1;&lt;br /&gt;
  var useDamages = 1;&lt;br /&gt;
  var defense = victim.defense;&lt;br /&gt;
  var defenseBoost = defense;&lt;br /&gt;
  var magicResistance = 0;&lt;br /&gt;
  var weaponDefense = 0;&lt;br /&gt;
  var tigerStrength = 0;&lt;br /&gt;
  var blessingBonus = 0;&lt;br /&gt;
  var magicAttackValueMeleeMagic = 0;&lt;br /&gt;
  var criticalHitPercentage = attacker.criticalHit;&lt;br /&gt;
  var piercingHitPercentage = attacker.piercingHit;&lt;br /&gt;
  var extraPiercingHitPercentage = Math.max(0, piercingHitPercentage - 100);&lt;br /&gt;
  var averageDamage = 0;&lt;br /&gt;
  var averageDamageResistance = 0;&lt;br /&gt;
  var skillDamage = 0;&lt;br /&gt;
  var skillDamageResistance = 0;&lt;br /&gt;
  var rankBonus = 0;&lt;br /&gt;
  var defensePercent = 0;&lt;br /&gt;
  var damageBonus = 0;&lt;br /&gt;
  var empireMalus = 0;&lt;br /&gt;
  var sungMaStrBonus = 0;&lt;br /&gt;
  var sungmaStrMalus = 0;&lt;br /&gt;
  var whiteDragonElixir = 0;&lt;br /&gt;
  var steelDragonElixir = 0;&lt;br /&gt;
&lt;br /&gt;
  computePolymorphPoint(attacker, victim, constants.polymorphPowerTable);&lt;br /&gt;
  computeHorse(attacker);&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker)) {&lt;br /&gt;
    if (weaponData.hasOwnProperty(attacker.weapon)) {&lt;br /&gt;
      attacker.weapon = createWeapon(attacker.weapon);&lt;br /&gt;
    } else {&lt;br /&gt;
      attacker.weapon = createWeapon(0);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    attacker.weapon.getValues(attacker.weaponUpgrade);&lt;br /&gt;
&lt;br /&gt;
    attackValueMeleeMagic =&lt;br /&gt;
      attacker.attackValuePercent + Math.min(100, attacker.attackMeleeMagic);&lt;br /&gt;
&lt;br /&gt;
    var weaponType = attacker.weapon.type;&lt;br /&gt;
&lt;br /&gt;
    if (skillType &amp;amp;&amp;amp; attacker.class === &amp;quot;archery&amp;quot;) {&lt;br /&gt;
      if (weaponType !== 2) {&lt;br /&gt;
        useDamages = 0;&lt;br /&gt;
        weaponType = 2;&lt;br /&gt;
      }&lt;br /&gt;
      defense = 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var weaponDefenseName = mapping.defenseWeapon[weaponType];&lt;br /&gt;
    var weaponDefenseBreakName = mapping.breakWeapon[weaponType];&lt;br /&gt;
&lt;br /&gt;
    if (victim.hasOwnProperty(weaponDefenseName)) {&lt;br /&gt;
      weaponDefense = victim[weaponDefenseName];&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isChecked(attacker.whiteDragonElixir)) {&lt;br /&gt;
      whiteDragonElixir = 10;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isPC(victim)) {&lt;br /&gt;
      if (!skillType) {&lt;br /&gt;
        if (weaponType === 2 &amp;amp;&amp;amp; !isPolymorph(attacker)) {&lt;br /&gt;
          missPercentage = victim.arrowBlock;&lt;br /&gt;
        } else {&lt;br /&gt;
          missPercentage = victim.meleeBlock;&lt;br /&gt;
        }&lt;br /&gt;
        missPercentage +=&lt;br /&gt;
          victim.meleeArrowBlock -&lt;br /&gt;
          (missPercentage * victim.meleeArrowBlock) / 100;&lt;br /&gt;
&lt;br /&gt;
        blessingBonus = calcBlessingBonus(constants.skillPowerTable, victim);&lt;br /&gt;
        averageDamageResistance = victim.averageDamageResistance;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      typeBonus = Math.max(1, attacker.humanBonus - victim.humanResistance);&lt;br /&gt;
      raceBonus = attacker[mapping.raceBonus[victim.race]];&lt;br /&gt;
      raceResistance = victim[mapping.raceResistance[attacker.race]];&lt;br /&gt;
&lt;br /&gt;
      calcElementCoeffPvP(elementBonus, mapping, attacker, victim);&lt;br /&gt;
&lt;br /&gt;
      if (weaponType !== 2 &amp;amp;&amp;amp; attacker.hasOwnProperty(weaponDefenseBreakName)) {&lt;br /&gt;
        weaponDefense -= attacker[weaponDefenseBreakName];&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      criticalHitPercentage = 0;&lt;br /&gt;
    } else {&lt;br /&gt;
      if (isChecked(attacker.isMarried)) {&lt;br /&gt;
        if (isChecked(attacker.loveNecklace)) {&lt;br /&gt;
          attackValueMarriage = getMarriageBonusValue(&lt;br /&gt;
            attacker,&lt;br /&gt;
            constants.marriageTable,&lt;br /&gt;
            &amp;quot;loveNecklace&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isChecked(attacker.loveEarrings)) {&lt;br /&gt;
          criticalHitPercentage += getMarriageBonusValue(&lt;br /&gt;
            attacker,&lt;br /&gt;
            constants.marriageTable,&lt;br /&gt;
            &amp;quot;loveEarrings&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isChecked(attacker.harmonyEarrings)) {&lt;br /&gt;
          piercingHitPercentage += getMarriageBonusValue(&lt;br /&gt;
            attacker,&lt;br /&gt;
            constants.marriageTable,&lt;br /&gt;
            &amp;quot;harmonyEarrings&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (isChecked(attacker.tigerStrength)) {&lt;br /&gt;
        tigerStrength = 40;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      for (var index = 0; index &amp;lt; elementBonus.length; index++) {&lt;br /&gt;
        var elementBonusName = mapping.elementBonus[index];&lt;br /&gt;
        var elementResistanceName = mapping.elementResistance[index];&lt;br /&gt;
&lt;br /&gt;
        if (attacker[elementBonusName] &amp;amp;&amp;amp; victim[elementBonusName]) {&lt;br /&gt;
          elementBonus[index] =&lt;br /&gt;
            50 * (attacker[elementBonusName] - victim[elementResistanceName]);&lt;br /&gt;
        } else {&lt;br /&gt;
          elementBonus[index] = 5 * attacker[elementBonusName];&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      var victimType = victim.type;&lt;br /&gt;
&lt;br /&gt;
      if (victimType !== -1) {&lt;br /&gt;
        typeBonus = attacker[mapping.typeFlag[victimType]];&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      monsterBonus = attacker.monsterBonus;&lt;br /&gt;
&lt;br /&gt;
      if (isStone(victim)) {&lt;br /&gt;
        stoneBonus = attacker.stoneBonus;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (isBoss(victim)) {&lt;br /&gt;
        if (skillType) {&lt;br /&gt;
          skillDamage += attacker.skillBossDamage;&lt;br /&gt;
        } else {&lt;br /&gt;
          averageDamage += attacker.bossDamage;&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (isChecked(attacker.onYohara)) {&lt;br /&gt;
        var sungmaStrDifference = attacker.sungmaStr - attacker.sungmaStrMalus;&lt;br /&gt;
&lt;br /&gt;
        if (sungmaStrDifference &amp;gt;= 0) {&lt;br /&gt;
          sungMaStrBonus = sungmaStrDifference;&lt;br /&gt;
        } else {&lt;br /&gt;
          sungmaStrMalus = 0.5;&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (skillType) {&lt;br /&gt;
      skillDamage += attacker.skillDamage;&lt;br /&gt;
    } else {&lt;br /&gt;
      averageDamage += attacker.averageDamage;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    rankBonus = getRankBonus(attacker);&lt;br /&gt;
    damageBonus = attacker.damageBonus;&lt;br /&gt;
&lt;br /&gt;
    if (isChecked(attacker.empireMalus)) {&lt;br /&gt;
      empireMalus = 1;&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    if (isPC(victim)) {&lt;br /&gt;
      if (isChecked(victim.isMarried)) {&lt;br /&gt;
        if (isChecked(victim.harmonyBracelet)) {&lt;br /&gt;
          monsterResistanceMarriage = getMarriageBonusValue(&lt;br /&gt;
            victim,&lt;br /&gt;
            constants.marriageTable,&lt;br /&gt;
            &amp;quot;harmonyBracelet&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isChecked(victim.harmonyNecklace) &amp;amp;&amp;amp; !skillType) {&lt;br /&gt;
          defenseMarriage = getMarriageBonusValue(&lt;br /&gt;
            victim,&lt;br /&gt;
            constants.marriageTable,&lt;br /&gt;
            &amp;quot;harmonyNecklace&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      monsterResistance = victim.monsterResistance;&lt;br /&gt;
&lt;br /&gt;
      for (var index = 0; index &amp;lt; elementBonus.length; index++) {&lt;br /&gt;
        var elementBonusName = mapping.elementBonus[index];&lt;br /&gt;
        var elementResistanceName = mapping.elementResistance[index];&lt;br /&gt;
&lt;br /&gt;
        if (attacker[elementBonusName]) {&lt;br /&gt;
          elementBonus[index] =&lt;br /&gt;
            80 * (attacker[elementBonusName] - victim[elementResistanceName]);&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (!skillType) {&lt;br /&gt;
        if (isMeleeAttacker(attacker)) {&lt;br /&gt;
          missPercentage = victim.meleeBlock;&lt;br /&gt;
          averageDamageResistance = victim.averageDamageResistance;&lt;br /&gt;
          blessingBonus = calcBlessingBonus(constants.skillPowerTable, victim);&lt;br /&gt;
        } else if (isRangeAttacker(attacker)) {&lt;br /&gt;
          missPercentage = victim.arrowBlock;&lt;br /&gt;
          weaponDefense = victim.arrowDefense;&lt;br /&gt;
          averageDamageResistance = victim.averageDamageResistance;&lt;br /&gt;
          blessingBonus = calcBlessingBonus(constants.skillPowerTable, victim);&lt;br /&gt;
        } else if (isMagicAttacker(attacker)) {&lt;br /&gt;
          missPercentage = victim.arrowBlock;&lt;br /&gt;
          skillDamageResistance = victim.skillDamageResistance;&lt;br /&gt;
          magicResistance = victim.magicResistance;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        missPercentage +=&lt;br /&gt;
          victim.meleeArrowBlock -&lt;br /&gt;
          (missPercentage * victim.meleeArrowBlock) / 100;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    typeBonus = 1;&lt;br /&gt;
    damageMultiplier = attacker.damageMultiplier;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillType) {&lt;br /&gt;
    criticalHitPercentage = skillChanceReduction(criticalHitPercentage);&lt;br /&gt;
    piercingHitPercentage = skillChanceReduction(piercingHitPercentage);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (isPC(victim)) {&lt;br /&gt;
    if (!skillType &amp;amp;&amp;amp; isChecked(victim.biologist70)) {&lt;br /&gt;
      defenseBoost = Math.floor((defenseBoost * 110) / 100);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    criticalHitPercentage = Math.max(&lt;br /&gt;
      0,&lt;br /&gt;
      criticalHitPercentage - victim.criticalHitResistance&lt;br /&gt;
    );&lt;br /&gt;
    piercingHitPercentage = Math.max(&lt;br /&gt;
      0,&lt;br /&gt;
      piercingHitPercentage - victim.piercingHitResistance&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    if (skillType) {&lt;br /&gt;
      skillDamageResistance = victim.skillDamageResistance;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isMagicClass(victim)) {&lt;br /&gt;
      defensePercent = (-2 * victim.magicDefense * victim.defensePercent) / 100;&lt;br /&gt;
    } else {&lt;br /&gt;
      defensePercent = (-2 * defenseBoost * victim.defensePercent) / 100;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isChecked(victim.steelDragonElixir)) {&lt;br /&gt;
      steelDragonElixir = 10;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillType === &amp;quot;magic&amp;quot;) {&lt;br /&gt;
    attackValueMeleeMagic = 0;&lt;br /&gt;
    magicAttackValueMeleeMagic =&lt;br /&gt;
      attacker.attackMagic + Math.min(100, attacker.attackMeleeMagic);&lt;br /&gt;
    attackValueMarriage = 0;&lt;br /&gt;
    defense = 0;&lt;br /&gt;
    if (isDispell(attacker, 6)) {&lt;br /&gt;
      typeBonus = 0;&lt;br /&gt;
      raceBonus = 0;&lt;br /&gt;
      raceResistance = 0;&lt;br /&gt;
      stoneBonus = 0;&lt;br /&gt;
      monsterBonus = 0;&lt;br /&gt;
      for (var index = 0; index &amp;lt; elementBonus.length; index++) {&lt;br /&gt;
        elementBonus[index] = 0;&lt;br /&gt;
      }&lt;br /&gt;
    } else {&lt;br /&gt;
      magicResistance = victim.magicResistance;&lt;br /&gt;
    }&lt;br /&gt;
    weaponDefense = 0;&lt;br /&gt;
    calcAttackValues = calcMagicAttackValue;&lt;br /&gt;
  } else {&lt;br /&gt;
    calcAttackValues = calcSecondaryAttackValue;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  missPercentage = Math.min(100, missPercentage);&lt;br /&gt;
&lt;br /&gt;
  var bonusValues = {&lt;br /&gt;
    missPercentage: missPercentage,&lt;br /&gt;
    weaponBonusCoeff: 1,&lt;br /&gt;
    attackValueCoeff: 100 + attackValueMeleeMagic,&lt;br /&gt;
    attackValueMarriage: attackValueMarriage,&lt;br /&gt;
    monsterResistanceMarriageCoeff: 100 - monsterResistanceMarriage,&lt;br /&gt;
    monsterResistanceCoeff: 100 - monsterResistance,&lt;br /&gt;
    typeBonusCoeff: typeBonus,&lt;br /&gt;
    raceBonusCoeff: raceBonus,&lt;br /&gt;
    raceResistanceCoeff: raceResistance,&lt;br /&gt;
    stoneBonusCoeff: stoneBonus,&lt;br /&gt;
    monsterBonusCoeff: monsterBonus,&lt;br /&gt;
    elementBonusCoeff: elementBonus,&lt;br /&gt;
    damageMultiplier: damageMultiplier,&lt;br /&gt;
    useDamages: useDamages,&lt;br /&gt;
    defense: defense,&lt;br /&gt;
    defenseBoost: defenseBoost,&lt;br /&gt;
    defenseMarriage: defenseMarriage,&lt;br /&gt;
    tigerStrengthCoeff: 100 + tigerStrength,&lt;br /&gt;
    magicResistanceCoeff: magicResistanceToCoeff(magicResistance),&lt;br /&gt;
    weaponDefenseCoeff: 100 - weaponDefense,&lt;br /&gt;
    blessingBonusCoeff: 100 - blessingBonus,&lt;br /&gt;
    magicAttackValueCoeff: 100 + magicAttackValueMeleeMagic,&lt;br /&gt;
    extraPiercingHitCoeff: 5 * extraPiercingHitPercentage,&lt;br /&gt;
    averageDamageCoeff: 100 + averageDamage,&lt;br /&gt;
    averageDamageResistanceCoeff: 100 - Math.min(99, averageDamageResistance),&lt;br /&gt;
    skillDamageCoeff: 100 + skillDamage,&lt;br /&gt;
    skillDamageResistanceCoeff: 100 - Math.min(99, skillDamageResistance),&lt;br /&gt;
    rankBonusCoeff: 100 + rankBonus,&lt;br /&gt;
    defensePercent: Math.floor(defensePercent),&lt;br /&gt;
    damageBonusCoeff: damageBonus,&lt;br /&gt;
    empireMalusCoeff: 10 - empireMalus,&lt;br /&gt;
    sungMaStrBonusCoeff: 10000 + sungMaStrBonus,&lt;br /&gt;
    sungmaStrMalusCoeff: sungmaStrMalus,&lt;br /&gt;
    whiteDragonElixirCoeff: 100 + whiteDragonElixir,&lt;br /&gt;
    steelDragonElixirCoeff: 100 - steelDragonElixir,&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  criticalHitPercentage = Math.min(criticalHitPercentage, 100);&lt;br /&gt;
  piercingHitPercentage = Math.min(piercingHitPercentage, 100);&lt;br /&gt;
&lt;br /&gt;
  var damagesTypeCombinaison = [&lt;br /&gt;
    {&lt;br /&gt;
      criticalHit: false,&lt;br /&gt;
      piercingHit: false,&lt;br /&gt;
      weight:&lt;br /&gt;
        (100 - criticalHitPercentage) *&lt;br /&gt;
        (100 - piercingHitPercentage) *&lt;br /&gt;
        (100 - missPercentage),&lt;br /&gt;
      name: &amp;quot;normalHit&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      criticalHit: true,&lt;br /&gt;
      piercingHit: false,&lt;br /&gt;
      weight:&lt;br /&gt;
        criticalHitPercentage *&lt;br /&gt;
        (100 - piercingHitPercentage) *&lt;br /&gt;
        (100 - missPercentage),&lt;br /&gt;
      name: &amp;quot;criticalHit&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      criticalHit: false,&lt;br /&gt;
      piercingHit: true,&lt;br /&gt;
      weight:&lt;br /&gt;
        (100 - criticalHitPercentage) *&lt;br /&gt;
        piercingHitPercentage *&lt;br /&gt;
        (100 - missPercentage),&lt;br /&gt;
      name: &amp;quot;piercingHit&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      criticalHit: true,&lt;br /&gt;
      piercingHit: true,&lt;br /&gt;
      weight:&lt;br /&gt;
        criticalHitPercentage * piercingHitPercentage * (100 - missPercentage),&lt;br /&gt;
      name: &amp;quot;criticalPiercingHit&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
  ];&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    attacker: attacker,&lt;br /&gt;
    victim: victim,&lt;br /&gt;
    attackFactor: calcAttackFactor(attacker, victim),&lt;br /&gt;
    mainAttackValue: calcMainAttackValue(attacker),&lt;br /&gt;
    attackValues: calcAttackValues(attacker),&lt;br /&gt;
    bonusValues: bonusValues,&lt;br /&gt;
    damagesTypeCombinaison: damagesTypeCombinaison,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateBattleValues(battleValues, skillFormula, skillInfo) {&lt;br /&gt;
  var weaponBonus = 0;&lt;br /&gt;
  var skillWard = 0;&lt;br /&gt;
  var skillBonus = 0;&lt;br /&gt;
  var skillBonusByBonus = 0;&lt;br /&gt;
  var { attacker: attacker, bonusValues: bonusValues } = battleValues;&lt;br /&gt;
  var {&lt;br /&gt;
    range: [minVariation, maxVariation],&lt;br /&gt;
  } = skillInfo;&lt;br /&gt;
  var variationLength = maxVariation - minVariation + 1;&lt;br /&gt;
&lt;br /&gt;
  if (skillInfo.hasOwnProperty(&amp;quot;weaponBonus&amp;quot;)) {&lt;br /&gt;
    var [weaponType, weaponBonusValue] = skillInfo.weaponBonus;&lt;br /&gt;
&lt;br /&gt;
    if (weaponType === attacker.weapon.type) {&lt;br /&gt;
      weaponBonus = weaponBonusValue;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillInfo.skillBonus) {&lt;br /&gt;
    skillBonus = skillInfo.skillBonus;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillInfo.skillWard) {&lt;br /&gt;
    skillWard = skillInfo.skillWard;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillInfo.skillBonusByBonus) {&lt;br /&gt;
    skillBonusByBonus = skillInfo.skillBonusByBonus;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillInfo.removeWeaponReduction) {&lt;br /&gt;
    bonusValues.weaponDefenseCoeff = 100;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  bonusValues.weaponBonusCoeff = 100 + weaponBonus;&lt;br /&gt;
  bonusValues.skillWardCoeff = 1 - skillWard / 100;&lt;br /&gt;
  bonusValues.skillBonusCoeff = 1 + skillBonus / 100;&lt;br /&gt;
  bonusValues.skillBonusByBonusCoeff = 100 + skillBonusByBonus;&lt;br /&gt;
&lt;br /&gt;
  battleValues.skillFormula = skillFormula;&lt;br /&gt;
  battleValues.skillRange = skillInfo.range;&lt;br /&gt;
  battleValues.attackValues.totalCardinal *= variationLength;&lt;br /&gt;
  battleValues.attackValues.possibleDamagesCount *= variationLength;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcWeights(minValue, maxValue, minInterval) {&lt;br /&gt;
  var firstWeightLimit = minValue + minInterval - 1;&lt;br /&gt;
  var lastWeightsLimit = maxValue - minInterval + 1;&lt;br /&gt;
  var weights = [];&lt;br /&gt;
&lt;br /&gt;
  for (var value = minValue; value &amp;lt; firstWeightLimit; value++) {&lt;br /&gt;
    weights.push(value - minValue + 1);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (var value = firstWeightLimit; value &amp;lt;= lastWeightsLimit; value++) {&lt;br /&gt;
    weights.push(minInterval);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (var value = lastWeightsLimit + 1; value &amp;lt;= maxValue; value++) {&lt;br /&gt;
    weights.push(maxValue - value + 1);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return weights;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcBlessingBonus(skillPowerTable, victim) {&lt;br /&gt;
  if (!isChecked(victim.isBlessed)) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var int = victim.intBlessing;&lt;br /&gt;
  var dex = victim.dexBlessing;&lt;br /&gt;
  var skillPower = getSkillPower(victim[&amp;quot;skillBlessing&amp;quot;], skillPowerTable);&lt;br /&gt;
&lt;br /&gt;
  if (!skillPower) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var blessingBonus = floorMultiplication(&lt;br /&gt;
    ((int * 0.3 + 5) * (2 * skillPower + 0.5) + 0.3 * dex) / (skillPower + 2.3),&lt;br /&gt;
    1&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  if (victim.class === &amp;quot;dragon&amp;quot; &amp;amp;&amp;amp; isChecked(ictim.blessingOnself)) {&lt;br /&gt;
    blessingBonus = floorMultiplication(blessingBonus, 1.1);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return blessingBonus;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSkillFormula(battle, skillId, battleValues, removeSkillVariation) {&lt;br /&gt;
  var { attacker, victim, attackFactor } = battleValues;&lt;br /&gt;
  var skillPowerTable = battle.constants.skillPowerTable;&lt;br /&gt;
&lt;br /&gt;
  var skillFormula;&lt;br /&gt;
  var skillInfo = { range: [0, 0] };&lt;br /&gt;
&lt;br /&gt;
  var { class: attackerClass, level: lv, vit, str, int, dex } = attacker;&lt;br /&gt;
&lt;br /&gt;
  if (skillId &amp;lt;= 9) {&lt;br /&gt;
    var skillPower = getSkillPower(&lt;br /&gt;
      attacker[&amp;quot;attackSkill&amp;quot; + skillId],&lt;br /&gt;
      skillPowerTable&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    var improvedBySkillBonus = false;&lt;br /&gt;
    var improvedByBonus = false;&lt;br /&gt;
&lt;br /&gt;
    if (attackerClass === &amp;quot;body&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Triple lacération&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.1 * atk + (0.5 * atk + 1.5 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Moulinet à l'épée&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              3 * atk + (0.8 * atk + 5 * str + 3 * dex + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Accélération&lt;br /&gt;
        case 5:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * atk + (atk + dex * 3 + str * 7 + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Volonté de vivre&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              (3 * atk + (atk + 1.5 * str) * skillPower) * 1.07,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          break;&lt;br /&gt;
        // Tremblement de terre&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              3 * atk +&lt;br /&gt;
              (0.9 * atk + variation + 5 * str + 3 * dex + lv) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;mental&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Attaque de l'esprit&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2.3 * atk + (4 * atk + 4 * str + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Attaque de la paume&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2.3 * atk + (3 * atk + 4 * str + 3 * vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Charge&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * atk + (2 * atk + 2 * dex + 2 * vit + 4 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          break;&lt;br /&gt;
        // Coup d'épée&lt;br /&gt;
        case 5:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * atk + (atk + 3 * dex + 5 * str + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Orbe de l'épée&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              (2 * atk + (2 * atk + 2 * dex + 2 * vit + 4 * str) * skillPower) *&lt;br /&gt;
              1.1,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          break;&lt;br /&gt;
        // Tremblement de terre&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              3 * atk +&lt;br /&gt;
              (0.9 * atk + variation + 5 * str + 3 * dex + lv) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;blade_fight&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Embuscade&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk + (1.2 * atk + variation + 4 * dex + 4 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [1, 50];&lt;br /&gt;
          skillInfo.range = [500, 700];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Attaque rapide&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk + (1.6 * atk + variation + 7 * dex + 7 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [1, 35];&lt;br /&gt;
          skillInfo.range = [200, 300];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Dague filante&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * atk + (0.5 * atk + 9 * dex + 7 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Brume empoisonnée&lt;br /&gt;
        case 5:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * lv + (atk + 3 * str + 18 * dex) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Poison insidieux&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              (2 * lv + (atk + 3 * str + 18 * dex) * skillPower) * 1.1,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          break;&lt;br /&gt;
        // Étoiles brillantes&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk + (1.7 * atk + variation + 6 * dex + 5 * lv) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;archery&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Tir à répétition&lt;br /&gt;
        // case 1:&lt;br /&gt;
        //   skillFormula = function (atk) {&lt;br /&gt;
        //     return floorMultiplication(&lt;br /&gt;
        //       atk + 0.2 * atk * Math.floor(2 + 6 * skillPower) + (0.8 * atk + 8 * dex * attackFactor + 2 * int) * skillPower,&lt;br /&gt;
        //       1&lt;br /&gt;
        //     );&lt;br /&gt;
        //   };&lt;br /&gt;
        //   improvedByBonus = true;&lt;br /&gt;
        //   break;&lt;br /&gt;
        // Pluie de flèches&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk + (1.7 * atk + 5 * dex + str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Flèche de feu&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.5 * atk + (2.6 * atk + 0.9 * int + variation) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [100, 300];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Foulée de plume&lt;br /&gt;
        case 4:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              (3 * dex + 200 + 2 * str + 2 * int) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.removeWeaponReduction = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Flèche empoisonnée&lt;br /&gt;
        case 5:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk +&lt;br /&gt;
              (1.4 * atk + variation + 7 * dex + 4 * str + 4 * int) *&lt;br /&gt;
              skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [100, 200];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Coup étincelant&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              (atk +&lt;br /&gt;
                (1.2 * atk + variation + 6 * dex + 3 * str + 3 * int) *&lt;br /&gt;
                skillPower) *&lt;br /&gt;
              1.2,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [100, 200];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Tir tempête&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.9 * atk + (2.6 * atk + variation) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;weaponary&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Toucher brûlant&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk +&lt;br /&gt;
              2 * lv +&lt;br /&gt;
              2 * int +&lt;br /&gt;
              (2 * atk + 4 * str + 14 * int) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Tourbillon du dragon&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.1 * atk +&lt;br /&gt;
              2 * lv +&lt;br /&gt;
              2 * int +&lt;br /&gt;
              (1.5 * atk + str + 12 * int) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Contre-sort&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              40 +&lt;br /&gt;
              5 * lv +&lt;br /&gt;
              2 * int +&lt;br /&gt;
              (10 * int + 7 * mav + variation) * attackFactor * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [50, 100];&lt;br /&gt;
          break;&lt;br /&gt;
        // Coup démoniaque&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.9 * atk + (2.6 * atk + variation) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;black_magic&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Attaque des ténèbres&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              40 +&lt;br /&gt;
              5 * lv +&lt;br /&gt;
              2 * int +&lt;br /&gt;
              (13 * int + 6 * mav + variation) * attackFactor * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [50, 100];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Attaque de flammes&lt;br /&gt;
        // case 2:&lt;br /&gt;
        //   skillFormula = function (mav, variation) {&lt;br /&gt;
        //     return floorMultiplication(&lt;br /&gt;
        //       5 * lv + 2 * int + (7 * int + 8 * mav + 4 * str + 2 * vit + variation) * skillPower,&lt;br /&gt;
        //       1&lt;br /&gt;
        //     );&lt;br /&gt;
        //   };&lt;br /&gt;
        //   skillInfo.range = [180, 100];&lt;br /&gt;
        //   improvedByBonus = true;&lt;br /&gt;
        //   break;&lt;br /&gt;
        // Esprit de flammes&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              30 +&lt;br /&gt;
              2 * lv +&lt;br /&gt;
              2 * int +&lt;br /&gt;
              (7 * int + 6 * mav + variation) * attackFactor * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [200, 500];&lt;br /&gt;
          break;&lt;br /&gt;
        // Frappe de l'esprit&lt;br /&gt;
        // case 5:&lt;br /&gt;
        //   skillFormula = function (mav, variation) {&lt;br /&gt;
        //     return floorMultiplication(&lt;br /&gt;
        //       40 + 2 * lv + 2 * int + (2 * vit + 2 * dex + 13 * int + 6 * mav + variation) * attackFactor * skillPower,&lt;br /&gt;
        //       1&lt;br /&gt;
        //     );&lt;br /&gt;
        //   };&lt;br /&gt;
        //   skillInfo.range = [180, 200];&lt;br /&gt;
        //   break;&lt;br /&gt;
        // Orbe des ténèbres&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (mav) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              120 +&lt;br /&gt;
              6 * lv +&lt;br /&gt;
              (5 * vit + 5 * dex + 29 * int + 9 * mav) *&lt;br /&gt;
              attackFactor *&lt;br /&gt;
              skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Vague mortelle&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              120 +&lt;br /&gt;
              6 * lv +&lt;br /&gt;
              (5 * vit + 5 * dex + 30 * int + variation + 9 * mav) *&lt;br /&gt;
              attackFactor *&lt;br /&gt;
              skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;dragon&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Talisman volant&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (mav) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              70 +&lt;br /&gt;
              5 * lv +&lt;br /&gt;
              (18 * int + 7 * str + 5 * mav + 50) * attackFactor * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [4, 10];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Dragon chassant&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (mav) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              60 +&lt;br /&gt;
              5 * lv +&lt;br /&gt;
              (16 * int + 6 * dex + 6 * mav + 120) *&lt;br /&gt;
              attackFactor *&lt;br /&gt;
              skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [4, 10];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Rugissement du dragon&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (mav) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              70 +&lt;br /&gt;
              3 * lv +&lt;br /&gt;
              (20 * int + 3 * str + 10 * mav + 100) *&lt;br /&gt;
              attackFactor *&lt;br /&gt;
              skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [4, 10];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Météore&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              120 +&lt;br /&gt;
              6 * lv +&lt;br /&gt;
              (5 * vit + 5 * dex + 30 * int + variation + 9 * mav) *&lt;br /&gt;
              attackFactor *&lt;br /&gt;
              skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;heal&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Jet de foudre&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              60 +&lt;br /&gt;
              5 * lv +&lt;br /&gt;
              (8 * int + 2 * dex + 8 * mav + variation) *&lt;br /&gt;
              attackFactor *&lt;br /&gt;
              skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [6, 10];&lt;br /&gt;
          skillInfo.range = [5 * int, 15 * int];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Invocation de foudre&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              40 +&lt;br /&gt;
              4 * lv +&lt;br /&gt;
              (13 * int + 2 * str + 10 * mav + variation) *&lt;br /&gt;
              attackFactor *&lt;br /&gt;
              skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [6, 10];&lt;br /&gt;
          skillInfo.range = [5 * int, 16 * int];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Griffe de foudre&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              50 +&lt;br /&gt;
              5 * lv +&lt;br /&gt;
              (8 * int + 2 * str + 8 * mav + variation) *&lt;br /&gt;
              attackFactor *&lt;br /&gt;
              skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 800];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;lycan&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Déchiqueter&lt;br /&gt;
        // case 1:&lt;br /&gt;
        //   skillFormula = function (atk) {&lt;br /&gt;
        //     return floorMultiplication(&lt;br /&gt;
        //       1.1 * atk + (0.3 * atk + 1.5 * str) * skillPower,&lt;br /&gt;
        //       1&lt;br /&gt;
        //     );&lt;br /&gt;
        //   };&lt;br /&gt;
        //   skillInfo.weaponBonus = [5, 54];&lt;br /&gt;
        //   improvedByBonus = true;&lt;br /&gt;
        //   break;&lt;br /&gt;
        // Souffle de loup&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * atk + (atk + 3 * dex + 5 * str + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [5, 35];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Bond de loup&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk + (1.6 * atk + 200 + 7 * dex + 7 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [5, 35];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Griffe de loup&lt;br /&gt;
        case 4:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              3 * atk + (0.8 * atk + 6 * str + 2 * dex + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Tempête cinglante&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.8 * atk +&lt;br /&gt;
              (atk + 6 * dex + variation + 3 * str + lv) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
    if (improvedBySkillBonus) {&lt;br /&gt;
      skillInfo.skillBonus =&lt;br /&gt;
        16 * getSkillPower(attacker.skillBonus, skillPowerTable);&lt;br /&gt;
&lt;br /&gt;
      var skillWardChoice = victim.skillWardChoice;&lt;br /&gt;
&lt;br /&gt;
      if (skillWardChoice &amp;amp;&amp;amp; skillWardChoice === attackerClass) {&lt;br /&gt;
        skillInfo.skillWard =&lt;br /&gt;
          24 * getSkillPower(victim.skillWard, skillPowerTable);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (improvedByBonus) {&lt;br /&gt;
      skillInfo.skillBonusByBonus = attacker[&amp;quot;skillBonus&amp;quot; + skillId];&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (removeSkillVariation) {&lt;br /&gt;
      var averageVariation = (skillInfo.range[0] + skillInfo.range[0]) / 2;&lt;br /&gt;
      skillInfo.range = [averageVariation, averageVariation];&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    var skillPower = getSkillPower(&lt;br /&gt;
      attacker[&amp;quot;horseSkill&amp;quot; + skillId],&lt;br /&gt;
      skillPowerTable&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    switch (skillId) {&lt;br /&gt;
      // Combat équestre&lt;br /&gt;
      case 137:&lt;br /&gt;
        skillFormula = function (atk) {&lt;br /&gt;
          return floorMultiplication(atk + 2 * atk * skillPower, 1);&lt;br /&gt;
        };&lt;br /&gt;
        break;&lt;br /&gt;
      // Charge à cheval&lt;br /&gt;
      case 138:&lt;br /&gt;
        skillFormula = function (atk) {&lt;br /&gt;
          return floorMultiplication(&lt;br /&gt;
            2.4 * (200 + 1.5 * lv) + 600 * skillPower,&lt;br /&gt;
            1&lt;br /&gt;
          );&lt;br /&gt;
        };&lt;br /&gt;
        break;&lt;br /&gt;
      // Vague de Pouvoir&lt;br /&gt;
      case 139:&lt;br /&gt;
        skillFormula = function (atk) {&lt;br /&gt;
          return floorMultiplication(&lt;br /&gt;
            2 * (200 + 1.5 * lv) + 600 * skillPower,&lt;br /&gt;
            1&lt;br /&gt;
          );&lt;br /&gt;
        };&lt;br /&gt;
        break;&lt;br /&gt;
      // Grêle de flèches&lt;br /&gt;
      case 140:&lt;br /&gt;
        skillFormula = function (atk) {&lt;br /&gt;
          return floorMultiplication(atk + 2 * atk * skillPower, 1);&lt;br /&gt;
        };&lt;br /&gt;
        break;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  updateBattleValues(battleValues, skillFormula, skillInfo);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcMagicAttackValueAugmentation(&lt;br /&gt;
  magicAttackValueWeapon,&lt;br /&gt;
  magicAttackValueBonus&lt;br /&gt;
) {&lt;br /&gt;
  if (magicAttackValueBonus) {&lt;br /&gt;
    return Math.max(&lt;br /&gt;
      1,&lt;br /&gt;
      0.0025056 *&lt;br /&gt;
      magicAttackValueBonus ** 0.602338 *&lt;br /&gt;
      magicAttackValueWeapon ** 1.20476&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
  return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getMagicAttackValueAugmentation(&lt;br /&gt;
  minMagicAttackValue,&lt;br /&gt;
  maxMagicAttackValue,&lt;br /&gt;
  magicAttackValueBonus&lt;br /&gt;
) {&lt;br /&gt;
  var magicAttackValueAugmentation = [];&lt;br /&gt;
&lt;br /&gt;
  for (&lt;br /&gt;
    var magicAttackValue = minMagicAttackValue;&lt;br /&gt;
    magicAttackValue &amp;lt;= maxMagicAttackValue;&lt;br /&gt;
    magicAttackValue++&lt;br /&gt;
  ) {&lt;br /&gt;
    magicAttackValueAugmentation.push(&lt;br /&gt;
      calcMagicAttackValueAugmentation(magicAttackValue, magicAttackValueBonus)&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return magicAttackValueAugmentation;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcPhysicalDamages(battleValues) {&lt;br /&gt;
  var {&lt;br /&gt;
    attackFactor,&lt;br /&gt;
    mainAttackValue,&lt;br /&gt;
    attackValues: { minAttackValue, maxAttackValue, attackValueOther, weights },&lt;br /&gt;
    bonusValues,&lt;br /&gt;
    damagesTypeCombinaison,&lt;br /&gt;
  } = battleValues;&lt;br /&gt;
&lt;br /&gt;
  var damagesWeightedByType = {};&lt;br /&gt;
&lt;br /&gt;
  if (bonusValues.missPercentage) {&lt;br /&gt;
    damagesWeightedByType.miss = bonusValues.missPercentage / 100;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (var damagesType of damagesTypeCombinaison) {&lt;br /&gt;
    if (!damagesType.weight) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var damagesWeighted = {};&lt;br /&gt;
    damagesWeightedByType[damagesType.name] = damagesWeighted;&lt;br /&gt;
&lt;br /&gt;
    for (&lt;br /&gt;
      var attackValue = minAttackValue;&lt;br /&gt;
      attackValue &amp;lt;= maxAttackValue;&lt;br /&gt;
      attackValue++&lt;br /&gt;
    ) {&lt;br /&gt;
      var weight = weights[attackValue - minAttackValue] * damagesType.weight;&lt;br /&gt;
&lt;br /&gt;
      var secondaryAttackValue = 2 * attackValue + attackValueOther;&lt;br /&gt;
      var rawDamages =&lt;br /&gt;
        mainAttackValue +&lt;br /&gt;
        floorMultiplication(attackFactor, secondaryAttackValue);&lt;br /&gt;
&lt;br /&gt;
      var damagesWithPrimaryBonuses = calcDamageWithPrimaryBonuses(&lt;br /&gt;
        rawDamages,&lt;br /&gt;
        bonusValues&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      var minPiercingDamages =&lt;br /&gt;
        damagesWithPrimaryBonuses -&lt;br /&gt;
        bonusValues.defenseBoost +&lt;br /&gt;
        bonusValues.defenseMarriage;&lt;br /&gt;
&lt;br /&gt;
      if (minPiercingDamages &amp;lt;= 2) {&lt;br /&gt;
        for (var damages = 1; damages &amp;lt;= 5; damages++) {&lt;br /&gt;
          var finalDamages = calcDamageWithSecondaryBonuses(&lt;br /&gt;
            damages,&lt;br /&gt;
            bonusValues,&lt;br /&gt;
            damagesType,&lt;br /&gt;
            minPiercingDamages,&lt;br /&gt;
            damagesWithPrimaryBonuses&lt;br /&gt;
          );&lt;br /&gt;
&lt;br /&gt;
          addKeyValue(damagesWeighted, finalDamages, weight / 5);&lt;br /&gt;
        }&lt;br /&gt;
      } else {&lt;br /&gt;
        var finalDamages = calcDamageWithSecondaryBonuses(&lt;br /&gt;
          minPiercingDamages,&lt;br /&gt;
          bonusValues,&lt;br /&gt;
          damagesType,&lt;br /&gt;
          minPiercingDamages,&lt;br /&gt;
          damagesWithPrimaryBonuses&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        addKeyValue(damagesWeighted, finalDamages, weight);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return damagesWeightedByType;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcPhysicalSkillDamages(battleValues) {&lt;br /&gt;
  var {&lt;br /&gt;
    attackFactor,&lt;br /&gt;
    mainAttackValue,&lt;br /&gt;
    attackValues: { minAttackValue, maxAttackValue, attackValueOther, weights },&lt;br /&gt;
    bonusValues,&lt;br /&gt;
    damagesTypeCombinaison,&lt;br /&gt;
    skillFormula,&lt;br /&gt;
    skillRange: [minVariation, maxVariation],&lt;br /&gt;
  } = battleValues;&lt;br /&gt;
&lt;br /&gt;
  var damagesWeightedByType = {};&lt;br /&gt;
&lt;br /&gt;
  for (var damagesType of damagesTypeCombinaison) {&lt;br /&gt;
    if (!damagesType.weight) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var damagesWeighted = {};&lt;br /&gt;
    var savedDamages = {};&lt;br /&gt;
&lt;br /&gt;
    damagesWeightedByType[damagesType.name] = damagesWeighted;&lt;br /&gt;
&lt;br /&gt;
    for (&lt;br /&gt;
      var attackValue = minAttackValue;&lt;br /&gt;
      attackValue &amp;lt;= maxAttackValue;&lt;br /&gt;
      attackValue++&lt;br /&gt;
    ) {&lt;br /&gt;
      var weight = weights[attackValue - minAttackValue] * damagesType.weight;&lt;br /&gt;
&lt;br /&gt;
      var secondaryAttackValue = 2 * attackValue + attackValueOther;&lt;br /&gt;
      var rawDamages =&lt;br /&gt;
        mainAttackValue +&lt;br /&gt;
        floorMultiplication(attackFactor, secondaryAttackValue);&lt;br /&gt;
&lt;br /&gt;
      var damagesWithPrimaryBonuses = calcDamageWithPrimaryBonuses(&lt;br /&gt;
        rawDamages,&lt;br /&gt;
        bonusValues&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      for (&lt;br /&gt;
        var variation = minVariation;&lt;br /&gt;
        variation &amp;lt;= maxVariation;&lt;br /&gt;
        variation++&lt;br /&gt;
      ) {&lt;br /&gt;
        if (damagesWithPrimaryBonuses &amp;lt;= 2) {&lt;br /&gt;
          for (var damages = 1; damages &amp;lt;= 5; damages++) {&lt;br /&gt;
            damages *= bonusValues.useDamages;&lt;br /&gt;
&lt;br /&gt;
            var damagesWithFormula = skillFormula(damages, variation);&lt;br /&gt;
&lt;br /&gt;
            damagesWithFormula = Math.floor(&lt;br /&gt;
              (damagesWithFormula * bonusValues.weaponBonusCoeff) / 100&lt;br /&gt;
            );&lt;br /&gt;
&lt;br /&gt;
            var finalDamages = calcSkillDamageWithSecondaryBonuses(&lt;br /&gt;
              damagesWithFormula,&lt;br /&gt;
              bonusValues,&lt;br /&gt;
              damagesType,&lt;br /&gt;
              damagesWithPrimaryBonuses&lt;br /&gt;
            );&lt;br /&gt;
&lt;br /&gt;
            addKeyValue(damagesWeighted, finalDamages, weight / 5);&lt;br /&gt;
          }&lt;br /&gt;
        } else {&lt;br /&gt;
          damagesWithPrimaryBonuses *= bonusValues.useDamages;&lt;br /&gt;
&lt;br /&gt;
          var damagesWithFormula = skillFormula(&lt;br /&gt;
            damagesWithPrimaryBonuses,&lt;br /&gt;
            variation&lt;br /&gt;
          );&lt;br /&gt;
&lt;br /&gt;
          if (savedDamages.hasOwnProperty(damagesWithFormula)) {&lt;br /&gt;
            var finalDamages = savedDamages[damagesWithFormula];&lt;br /&gt;
            damagesWeighted[finalDamages] += weight;&lt;br /&gt;
            continue;&lt;br /&gt;
          }&lt;br /&gt;
&lt;br /&gt;
          var finalDamages = Math.floor(&lt;br /&gt;
            (damagesWithFormula * bonusValues.weaponBonusCoeff) / 100&lt;br /&gt;
          );&lt;br /&gt;
&lt;br /&gt;
          finalDamages = calcSkillDamageWithSecondaryBonuses(&lt;br /&gt;
            finalDamages,&lt;br /&gt;
            bonusValues,&lt;br /&gt;
            damagesType,&lt;br /&gt;
            damagesWithPrimaryBonuses&lt;br /&gt;
          );&lt;br /&gt;
&lt;br /&gt;
          savedDamages[damagesWithFormula] = finalDamages;&lt;br /&gt;
          addKeyValue(damagesWeighted, finalDamages, weight);&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return damagesWeightedByType;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcMagicSkillDamages(battleValues) {&lt;br /&gt;
  var {&lt;br /&gt;
    attackValues: {&lt;br /&gt;
      minMagicAttackValue,&lt;br /&gt;
      maxMagicAttackValue,&lt;br /&gt;
      magicAttackValueAugmentation,&lt;br /&gt;
      weights,&lt;br /&gt;
    },&lt;br /&gt;
    bonusValues,&lt;br /&gt;
    damagesTypeCombinaison,&lt;br /&gt;
    skillFormula,&lt;br /&gt;
    skillRange: [minVariation, maxVariation],&lt;br /&gt;
  } = battleValues;&lt;br /&gt;
&lt;br /&gt;
  var damagesWeightedByType = {};&lt;br /&gt;
&lt;br /&gt;
  for (var damagesType of damagesTypeCombinaison) {&lt;br /&gt;
    if (!damagesType.weight) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var damagesWeighted = {};&lt;br /&gt;
    var savedDamages = {};&lt;br /&gt;
&lt;br /&gt;
    damagesWeightedByType[damagesType.name] = damagesWeighted;&lt;br /&gt;
&lt;br /&gt;
    for (&lt;br /&gt;
      var magicAttackValue = minMagicAttackValue;&lt;br /&gt;
      magicAttackValue &amp;lt;= maxMagicAttackValue;&lt;br /&gt;
      magicAttackValue++&lt;br /&gt;
    ) {&lt;br /&gt;
      var index = magicAttackValue - minMagicAttackValue;&lt;br /&gt;
      var weight = weights[index] * damagesType.weight;&lt;br /&gt;
&lt;br /&gt;
      for (&lt;br /&gt;
        var variation = minVariation;&lt;br /&gt;
        variation &amp;lt;= maxVariation;&lt;br /&gt;
        variation++&lt;br /&gt;
      ) {&lt;br /&gt;
        var rawDamages = skillFormula(&lt;br /&gt;
          magicAttackValue + magicAttackValueAugmentation[index],&lt;br /&gt;
          variation&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        if (savedDamages.hasOwnProperty(rawDamages)) {&lt;br /&gt;
          var finalDamages = savedDamages[rawDamages];&lt;br /&gt;
          damagesWeighted[finalDamages] += weight;&lt;br /&gt;
          continue;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var damagesWithPrimaryBonuses = Math.floor(&lt;br /&gt;
          (rawDamages * bonusValues.weaponBonusCoeff) / 100&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        damagesWithPrimaryBonuses = calcDamageWithPrimaryBonuses(&lt;br /&gt;
          damagesWithPrimaryBonuses,&lt;br /&gt;
          bonusValues&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        if (damagesWithPrimaryBonuses &amp;lt;= 2) {&lt;br /&gt;
          for (var damages = 1; damages &amp;lt;= 5; damages++) {&lt;br /&gt;
            var finalDamages = calcSkillDamageWithSecondaryBonuses(&lt;br /&gt;
              damages,&lt;br /&gt;
              bonusValues,&lt;br /&gt;
              damagesType,&lt;br /&gt;
              damagesWithPrimaryBonuses&lt;br /&gt;
            );&lt;br /&gt;
            addKeyValue(damagesWeighted, finalDamages, weight / 5);&lt;br /&gt;
          }&lt;br /&gt;
        } else {&lt;br /&gt;
          var finalDamages = calcSkillDamageWithSecondaryBonuses(&lt;br /&gt;
            damagesWithPrimaryBonuses,&lt;br /&gt;
            bonusValues,&lt;br /&gt;
            damagesType,&lt;br /&gt;
            damagesWithPrimaryBonuses&lt;br /&gt;
          );&lt;br /&gt;
&lt;br /&gt;
          savedDamages[rawDamages] = finalDamages;&lt;br /&gt;
          addKeyValue(damagesWeighted, finalDamages, weight);&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return damagesWeightedByType;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcDamages(&lt;br /&gt;
  attacker,&lt;br /&gt;
  victim,&lt;br /&gt;
  attackType,&lt;br /&gt;
  battle,&lt;br /&gt;
  removeSkillVariation&lt;br /&gt;
) {&lt;br /&gt;
  var damagesCalculator, skillId, skillType;&lt;br /&gt;
&lt;br /&gt;
  if (attackType === &amp;quot;physical&amp;quot;) {&lt;br /&gt;
    damagesCalculator = calcPhysicalDamages;&lt;br /&gt;
  } else if (attackType.startsWith(&amp;quot;attackSkill&amp;quot;)) {&lt;br /&gt;
    skillId = Number(attackType.split(&amp;quot;attackSkill&amp;quot;)[1]);&lt;br /&gt;
&lt;br /&gt;
    if (isMagicClass(attacker) || isDispell(attacker, skillId)) {&lt;br /&gt;
      skillType = &amp;quot;magic&amp;quot;;&lt;br /&gt;
      damagesCalculator = calcMagicSkillDamages;&lt;br /&gt;
    } else {&lt;br /&gt;
      skillType = &amp;quot;physical&amp;quot;;&lt;br /&gt;
      damagesCalculator = calcPhysicalSkillDamages;&lt;br /&gt;
    }&lt;br /&gt;
  } else if (attackType.startsWith(&amp;quot;horseSkill&amp;quot;)) {&lt;br /&gt;
    skillType = &amp;quot;physical&amp;quot;;&lt;br /&gt;
    skillId = Number(attackType.split(&amp;quot;horseSkill&amp;quot;)[1]);&lt;br /&gt;
    damagesCalculator = calcPhysicalSkillDamages;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var battleValues = createBattleValues(attacker, victim, battle, skillType);&lt;br /&gt;
&lt;br /&gt;
  if (skillId) {&lt;br /&gt;
    getSkillFormula(battle, skillId, battleValues, removeSkillVariation);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var {&lt;br /&gt;
    attackValues: { totalCardinal, possibleDamagesCount },&lt;br /&gt;
  } = battleValues;&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    damagesWeightedByType: damagesCalculator(battleValues),&lt;br /&gt;
    totalCardinal: totalCardinal,&lt;br /&gt;
    possibleDamagesCount: possibleDamagesCount,&lt;br /&gt;
    skillType: skillType,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function damagesWithoutVariation(&lt;br /&gt;
  attacker,&lt;br /&gt;
  victim,&lt;br /&gt;
  attackType,&lt;br /&gt;
  battle,&lt;br /&gt;
  characters&lt;br /&gt;
) {&lt;br /&gt;
  startDamagesTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
  var {&lt;br /&gt;
    damagesWeightedByType,&lt;br /&gt;
    totalCardinal,&lt;br /&gt;
    possibleDamagesCount,&lt;br /&gt;
    skillType,&lt;br /&gt;
  } = calcDamages(attacker, victim, attackType, battle);&lt;br /&gt;
&lt;br /&gt;
  endDamagesTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
  possibleDamagesCount = displayResults(&lt;br /&gt;
    possibleDamagesCount,&lt;br /&gt;
    totalCardinal,&lt;br /&gt;
    damagesWeightedByType,&lt;br /&gt;
    battle,&lt;br /&gt;
    attacker.name,&lt;br /&gt;
    victim.name&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  endDisplayTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
  displayFightInfo(&lt;br /&gt;
    possibleDamagesCount,&lt;br /&gt;
    endDamagesTime - startDamagesTime,&lt;br /&gt;
    endDisplayTime - endDamagesTime,&lt;br /&gt;
    battle&lt;br /&gt;
  );&lt;br /&gt;
  addPotentialErrorInformation(&lt;br /&gt;
    battle.errorInformation,&lt;br /&gt;
    attacker,&lt;br /&gt;
    victim,&lt;br /&gt;
    skillType,&lt;br /&gt;
    characters&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  hideElement(battle.bonusVariationResultContainer);&lt;br /&gt;
  showElement(battle.fightResultContainer);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function damagesWithVariation(&lt;br /&gt;
  attacker,&lt;br /&gt;
  victim,&lt;br /&gt;
  attackType,&lt;br /&gt;
  battle,&lt;br /&gt;
  entity,&lt;br /&gt;
  entityVariation&lt;br /&gt;
) {&lt;br /&gt;
  startTime = performance.now();&lt;br /&gt;
  var damagesByBonus = [];&lt;br /&gt;
  var augmentationByBonus = [];&lt;br /&gt;
  var {&lt;br /&gt;
    bonusVariationMinValue: minVariation,&lt;br /&gt;
    bonusVariationMaxValue: maxVariation,&lt;br /&gt;
  } = entity;&lt;br /&gt;
  var step = Math.ceil((maxVariation - minVariation + 1) / 500);&lt;br /&gt;
  var simulationCount = 0;&lt;br /&gt;
  var simulationTime;&lt;br /&gt;
&lt;br /&gt;
  for (&lt;br /&gt;
    var bonusValue = minVariation;&lt;br /&gt;
    bonusValue &amp;lt;= maxVariation;&lt;br /&gt;
    bonusValue += step&lt;br /&gt;
  ) {&lt;br /&gt;
    entity[entityVariation] = bonusValue;&lt;br /&gt;
&lt;br /&gt;
    var { damagesWeightedByType, totalCardinal } = calcDamages(&lt;br /&gt;
      copyObject(attacker),&lt;br /&gt;
      copyObject(victim),&lt;br /&gt;
      attackType,&lt;br /&gt;
      battle,&lt;br /&gt;
      true&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    var meanDamages = calcMeanDamages(damagesWeightedByType, totalCardinal);&lt;br /&gt;
&lt;br /&gt;
    if (bonusValue === minVariation) {&lt;br /&gt;
      var firstDamages = Math.max(meanDamages, 1e-3);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    damagesByBonus.push({ x: bonusValue, y: meanDamages });&lt;br /&gt;
    augmentationByBonus.push({&lt;br /&gt;
      x: bonusValue,&lt;br /&gt;
      y: meanDamages / firstDamages - 1,&lt;br /&gt;
    });&lt;br /&gt;
    simulationCount++;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  endTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
  battle.damagesByBonus = damagesByBonus.concat(entityVariation);&lt;br /&gt;
&lt;br /&gt;
  addToBonusVariationChart(&lt;br /&gt;
    damagesByBonus,&lt;br /&gt;
    augmentationByBonus,&lt;br /&gt;
    entity.bonusVariationDisplay,&lt;br /&gt;
    battle.bonusVariationChart&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  simulationCount = battle.numberFormats.default.format(simulationCount);&lt;br /&gt;
  simulationTime = battle.numberFormats.second.format(&lt;br /&gt;
    (endTime - startTime) / 1000&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  battle.simulationCounter.textContent = simulationCount;&lt;br /&gt;
  battle.simulationTime.textContent = simulationTime;&lt;br /&gt;
&lt;br /&gt;
  hideElement(battle.fightResultContainer);&lt;br /&gt;
  showElement(battle.bonusVariationResultContainer);&lt;br /&gt;
&lt;br /&gt;
  if (&lt;br /&gt;
    isChecked(attacker.bonusVariationActivation) &amp;amp;&amp;amp;&lt;br /&gt;
    isChecked(victim.bonusVariationActivation)&lt;br /&gt;
  ) {&lt;br /&gt;
    showElement(battle.errorInformation[&amp;quot;attacker-victim-variation&amp;quot;]);&lt;br /&gt;
  } else {&lt;br /&gt;
    hideElement(battle.errorInformation[&amp;quot;attacker-victim-variation&amp;quot;]);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function changeMonsterValues(monster, instance, attacker) {&lt;br /&gt;
  switch (instance) {&lt;br /&gt;
    case &amp;quot;SungMahiTower&amp;quot;:&lt;br /&gt;
      var sungMahiFloor = 1;&lt;br /&gt;
      var sungMahiStep = 1;&lt;br /&gt;
      var rawDefense = 120;&lt;br /&gt;
&lt;br /&gt;
      if (isPC(attacker)) {&lt;br /&gt;
        sungMahiFloor = attacker.sungMahiFloor;&lt;br /&gt;
        sungMahiStep = attacker.sungMahiStep;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (monster.rank === 5) {&lt;br /&gt;
        monster.level = 121;&lt;br /&gt;
        monster.dex = 75;&lt;br /&gt;
        rawDefense += 1;&lt;br /&gt;
      } else if (monster.rank === 6) {&lt;br /&gt;
        monster.level = 123;&lt;br /&gt;
        monster.dex = 75;&lt;br /&gt;
        rawDefense += 1;&lt;br /&gt;
      } else {&lt;br /&gt;
        monster.level = 120;&lt;br /&gt;
        monster.dex = 68;&lt;br /&gt;
      }&lt;br /&gt;
      monster.vit = 100;&lt;br /&gt;
      monster.rawDefense = rawDefense + (sungMahiStep - 1) * 6;&lt;br /&gt;
      monster.fistDefense = 0;&lt;br /&gt;
      monster.swordDefense = 0;&lt;br /&gt;
      monster.twoHandedSwordDefense = 0;&lt;br /&gt;
      monster.daggerDefense = 0;&lt;br /&gt;
      monster.bellDefense = 0;&lt;br /&gt;
      monster.fanDefense = 0;&lt;br /&gt;
      monster.arrowDefense = 0;&lt;br /&gt;
      monster.clawDefense = 0;&lt;br /&gt;
      monster.magicResistance = 0;&lt;br /&gt;
      monster.fireResistance = -20;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  // Alastor&lt;br /&gt;
  if (monster.vnum === 6790) {&lt;br /&gt;
    monster.iceResistance = 0;&lt;br /&gt;
    monster.iceBonus = 0;&lt;br /&gt;
    monster.lightningResistance = -10;&lt;br /&gt;
    monster.lightningBonus = 65;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createWeapon(vnum) {&lt;br /&gt;
  var weapon = copyObject(weaponData[vnum]);&lt;br /&gt;
  var serpentVnums = [360, 380, 1210, 2230, 3250, 5200, 6150, 7330];&lt;br /&gt;
  var weaponValues = weapon[1];&lt;br /&gt;
  var isSerpent = isValueInArray(Number(vnum), serpentVnums);&lt;br /&gt;
  var isSpecial = Array.isArray(weaponValues[0]);&lt;br /&gt;
  var isMagic;&lt;br /&gt;
&lt;br /&gt;
  if (isSpecial) {&lt;br /&gt;
    isMagic = weaponValues[0][1] &amp;gt; 0;&lt;br /&gt;
  } else {&lt;br /&gt;
    isMagic = weaponValues[1] &amp;gt; 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    type: weapon[0],&lt;br /&gt;
    maxUpgrade: weapon[2].length - 1,&lt;br /&gt;
    isSerpent: isSerpent,&lt;br /&gt;
    isMagic: isMagic,&lt;br /&gt;
    getValues: function (upgrade) {&lt;br /&gt;
      var currentWeaponValues = weaponValues;&lt;br /&gt;
&lt;br /&gt;
      if (upgrade === undefined) {&lt;br /&gt;
        // rare bug when weaponUpgrade is deleted&lt;br /&gt;
        console.warn(&amp;quot;WeaponUpgrade is missing.&amp;quot;);&lt;br /&gt;
        upgrade = this.maxUpgrade;&lt;br /&gt;
      }&lt;br /&gt;
      upgrade = Math.min(upgrade, this.maxUpgrade);&lt;br /&gt;
&lt;br /&gt;
      if (isSpecial) {&lt;br /&gt;
        currentWeaponValues = weaponValues[upgrade];&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      this.minAttackValue = currentWeaponValues[2];&lt;br /&gt;
      this.maxAttackValue = currentWeaponValues[3];&lt;br /&gt;
      this.minMagicAttackValue = currentWeaponValues[0];&lt;br /&gt;
      this.maxMagicAttackValue = currentWeaponValues[1];&lt;br /&gt;
      this.growth = weapon[2][upgrade];&lt;br /&gt;
    },&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createMonster(monsterVnum, attacker) {&lt;br /&gt;
  var monsterAttributes = monsterData[monsterVnum];&lt;br /&gt;
&lt;br /&gt;
  var monster = {&lt;br /&gt;
    vnum: Number(monsterVnum),&lt;br /&gt;
    name: monsterAttributes[36],&lt;br /&gt;
    rank: monsterAttributes[0],&lt;br /&gt;
    race: monsterAttributes[1],&lt;br /&gt;
    attack: monsterAttributes[2],&lt;br /&gt;
    level: monsterAttributes[3],&lt;br /&gt;
    type: monsterAttributes[4],&lt;br /&gt;
    str: monsterAttributes[5],&lt;br /&gt;
    dex: monsterAttributes[6],&lt;br /&gt;
    vit: monsterAttributes[7],&lt;br /&gt;
    int: monsterAttributes[8],&lt;br /&gt;
    minAttackValue: monsterAttributes[9],&lt;br /&gt;
    maxAttackValue: monsterAttributes[10],&lt;br /&gt;
    rawDefense: monsterAttributes[11],&lt;br /&gt;
    criticalHit: monsterAttributes[12],&lt;br /&gt;
    piercingHit: monsterAttributes[13],&lt;br /&gt;
    fistDefense: monsterAttributes[14],&lt;br /&gt;
    swordDefense: monsterAttributes[15],&lt;br /&gt;
    twoHandedSwordDefense: monsterAttributes[16],&lt;br /&gt;
    daggerDefense: monsterAttributes[17],&lt;br /&gt;
    bellDefense: monsterAttributes[18],&lt;br /&gt;
    fanDefense: monsterAttributes[19],&lt;br /&gt;
    arrowDefense: monsterAttributes[20],&lt;br /&gt;
    clawDefense: monsterAttributes[21],&lt;br /&gt;
    fireResistance: monsterAttributes[22],&lt;br /&gt;
    lightningResistance: monsterAttributes[23],&lt;br /&gt;
    magicResistance: monsterAttributes[24],&lt;br /&gt;
    windResistance: monsterAttributes[25],&lt;br /&gt;
    lightningBonus: monsterAttributes[26],&lt;br /&gt;
    fireBonus: monsterAttributes[27],&lt;br /&gt;
    iceBonus: monsterAttributes[28],&lt;br /&gt;
    windBonus: monsterAttributes[29],&lt;br /&gt;
    earthBonus: monsterAttributes[30],&lt;br /&gt;
    darknessBonus: monsterAttributes[31],&lt;br /&gt;
    darknessResistance: monsterAttributes[32],&lt;br /&gt;
    iceResistance: monsterAttributes[33],&lt;br /&gt;
    earthResistance: monsterAttributes[34],&lt;br /&gt;
    damageMultiplier: monsterAttributes[35],&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  // monster.instance = 0;&lt;br /&gt;
&lt;br /&gt;
  // if (attacker &amp;amp;&amp;amp; monster.instance === 0) {&lt;br /&gt;
  //   changeMonsterValues(monster, &amp;quot;SungMahiTower&amp;quot;, attacker);&lt;br /&gt;
  // }&lt;br /&gt;
&lt;br /&gt;
  changeMonsterValues(monster);&lt;br /&gt;
&lt;br /&gt;
  monster.defense = monster.rawDefense + monster.level + monster.vit;&lt;br /&gt;
&lt;br /&gt;
  return monster;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addPotentialErrorInformation(&lt;br /&gt;
  errorInformation,&lt;br /&gt;
  attacker,&lt;br /&gt;
  victim,&lt;br /&gt;
  skillType,&lt;br /&gt;
  characters&lt;br /&gt;
) {&lt;br /&gt;
  for (var error of Object.values(errorInformation)) {&lt;br /&gt;
    hideElement(error);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker)) {&lt;br /&gt;
    if (isRiding(attacker)) {&lt;br /&gt;
      if (attacker.horsePoint === 0) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;horse-level&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
      showElement(errorInformation[&amp;quot;horse-stat&amp;quot;]);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isPolymorph(attacker)) {&lt;br /&gt;
      if (attacker.polymorphPoint === 0) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;polymorph-level&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (&lt;br /&gt;
        (attacker.polymorphPoint &amp;lt;= 39 &amp;amp;&amp;amp; attacker.attackValuePercent &amp;lt;= 199) ||&lt;br /&gt;
        (attacker.polymorphPoint === 40 &amp;amp;&amp;amp; attacker.attackValuePercent &amp;lt;= 299)&lt;br /&gt;
      ) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;polymorph-bonus&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
    if (skillType === &amp;quot;magic&amp;quot;) {&lt;br /&gt;
      if (attacker.magicAttackValue) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;magic-attack-value-bonus&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
      if (victim.magicResistance) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;magic-resistance&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    showElement(errorInformation[&amp;quot;monster-attacker&amp;quot;]);&lt;br /&gt;
    if (isMagicAttacker(attacker) &amp;amp;&amp;amp; victim.magicResistance) {&lt;br /&gt;
      showElement(errorInformation[&amp;quot;magic-resistance&amp;quot;]);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (isPC(victim)) {&lt;br /&gt;
    if (isRiding(victim)) {&lt;br /&gt;
      showElement(errorInformation[&amp;quot;horse-stat&amp;quot;]);&lt;br /&gt;
    }&lt;br /&gt;
    if (isPolymorph(victim)) {&lt;br /&gt;
      if (attacker.polymorphPoint === 0) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;polymorph-level&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
      showElement(errorInformation[&amp;quot;polymorph-defense&amp;quot;]);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (characters.unsavedChanges) {&lt;br /&gt;
    showElement(errorInformation[&amp;quot;save&amp;quot;]);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function reduceChartPointsListener(battle) {&lt;br /&gt;
  var {&lt;br /&gt;
    reduceChartPointsContainer,&lt;br /&gt;
    reduceChartPoints,&lt;br /&gt;
    numberFormats: { second: numberFormat },&lt;br /&gt;
    displayTime,&lt;br /&gt;
  } = battle;&lt;br /&gt;
&lt;br /&gt;
  reduceChartPoints.addEventListener(&amp;quot;change&amp;quot;, function () {&lt;br /&gt;
    var startDisplayTime = performance.now();&lt;br /&gt;
    var scatterDataByType = battle.scatterDataByType;&lt;br /&gt;
    var {&lt;br /&gt;
      chart,&lt;br /&gt;
      maxPoints,&lt;br /&gt;
      chart: {&lt;br /&gt;
        data: { datasets },&lt;br /&gt;
      },&lt;br /&gt;
    } = battle.damagesChart;&lt;br /&gt;
    var addAnimations = false;&lt;br /&gt;
&lt;br /&gt;
    for (var index = 0; index &amp;lt; datasets.length; index++) {&lt;br /&gt;
      var dataset = datasets[index];&lt;br /&gt;
      var scatterData = scatterDataByType[dataset.name];&lt;br /&gt;
&lt;br /&gt;
      if (dataset.canBeReduced &amp;amp;&amp;amp; reduceChartPoints.checked) {&lt;br /&gt;
        dataset.data = aggregateDamages(scatterData, maxPoints);&lt;br /&gt;
        addAnimations = true;&lt;br /&gt;
      } else {&lt;br /&gt;
        dataset.data = scatterData;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    handleChartAnimations(chart, addAnimations);&lt;br /&gt;
    chart.update();&lt;br /&gt;
&lt;br /&gt;
    displayTime.textContent = numberFormat.format(&lt;br /&gt;
      (performance.now() - startDisplayTime) / 1000&lt;br /&gt;
    );&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  reduceChartPointsContainer.addEventListener(&amp;quot;pointerup&amp;quot;, function (event) {&lt;br /&gt;
    if (event.pointerType === &amp;quot;mouse&amp;quot;) {&lt;br /&gt;
      reduceChartPoints.click();&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function downloadRawDataListener(battle) {&lt;br /&gt;
  var { downLoadRawData, downLoadRawDataVariation } = battle;&lt;br /&gt;
  var fileType = &amp;quot;text/csv;charset=utf-8;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  downLoadRawData.addEventListener(&amp;quot;click&amp;quot;, function () {&lt;br /&gt;
    var damagesWeightedByType = battle.damagesWeightedByType;&lt;br /&gt;
    var filename = &amp;quot;raw_damages.csv&amp;quot;;&lt;br /&gt;
    var csvContent = &amp;quot;damage,probabilities,damageType\n&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    for (var damagesType in damagesWeightedByType) {&lt;br /&gt;
      var damagesWeighted = damagesWeightedByType[damagesType];&lt;br /&gt;
&lt;br /&gt;
      for (var damages in damagesWeighted) {&lt;br /&gt;
        csvContent +=&lt;br /&gt;
          damages + &amp;quot;,&amp;quot; + damagesWeighted[damages] + &amp;quot;,&amp;quot; + damagesType + &amp;quot;\n&amp;quot;;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    downloadData(csvContent, fileType, filename);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  downLoadRawDataVariation.addEventListener(&amp;quot;click&amp;quot;, function () {&lt;br /&gt;
    var damagesByBonus = battle.damagesByBonus;&lt;br /&gt;
    var damagesByBonusLength = damagesByBonus.length;&lt;br /&gt;
    var filename = &amp;quot;damages_variation.csv&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    if (!damagesByBonusLength) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var csvContent =&lt;br /&gt;
      damagesByBonus[damagesByBonusLength - 1] + &amp;quot;,averageDamage\n&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    for (var index = 0; index &amp;lt; damagesByBonusLength - 1; index++) {&lt;br /&gt;
      var row = damagesByBonus[index];&lt;br /&gt;
&lt;br /&gt;
      csvContent += row.x + &amp;quot;,&amp;quot; + row.y + &amp;quot;\n&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    downloadData(csvContent, fileType, filename);&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function displayResults(&lt;br /&gt;
  possibleDamagesCount,&lt;br /&gt;
  totalCardinal,&lt;br /&gt;
  damagesWeightedByType,&lt;br /&gt;
  battle,&lt;br /&gt;
  attackerName,&lt;br /&gt;
  victimName&lt;br /&gt;
) {&lt;br /&gt;
  var [&lt;br /&gt;
    meanDamages,&lt;br /&gt;
    minDamages,&lt;br /&gt;
    maxDamages,&lt;br /&gt;
    scatterDataByType,&lt;br /&gt;
    possibleDamagesCount,&lt;br /&gt;
    uniqueDamagesCount,&lt;br /&gt;
  ] = prepareDamagesData(&lt;br /&gt;
    damagesWeightedByType,&lt;br /&gt;
    possibleDamagesCount,&lt;br /&gt;
    totalCardinal&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  addToDamagesChart(&lt;br /&gt;
    scatterDataByType,&lt;br /&gt;
    battle.damagesChart,&lt;br /&gt;
    battle.reduceChartPoints.checked&lt;br /&gt;
  );&lt;br /&gt;
  updateDamagesChartDescription(&lt;br /&gt;
    battle.uniqueDamagesCounters,&lt;br /&gt;
    uniqueDamagesCount,&lt;br /&gt;
    battle.numberFormats.default&lt;br /&gt;
  );&lt;br /&gt;
  displayFightResults(&lt;br /&gt;
    battle,&lt;br /&gt;
    attackerName,&lt;br /&gt;
    victimName,&lt;br /&gt;
    meanDamages,&lt;br /&gt;
    minDamages,&lt;br /&gt;
    maxDamages&lt;br /&gt;
  );&lt;br /&gt;
  battle.damagesWeightedByType = damagesWeightedByType;&lt;br /&gt;
  battle.scatterDataByType = scatterDataByType;&lt;br /&gt;
&lt;br /&gt;
  return possibleDamagesCount;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function displayFightResults(&lt;br /&gt;
  battle,&lt;br /&gt;
  attackerName,&lt;br /&gt;
  victimName,&lt;br /&gt;
  meanDamages,&lt;br /&gt;
  minDamages,&lt;br /&gt;
  maxDamages&lt;br /&gt;
) {&lt;br /&gt;
  var {&lt;br /&gt;
    tableResultFight,&lt;br /&gt;
    tableResultHistory,&lt;br /&gt;
    attackTypeSelection,&lt;br /&gt;
    savedFights,&lt;br /&gt;
    numberFormats: { default: numberFormat },&lt;br /&gt;
    deleteFightTemplate,&lt;br /&gt;
  } = battle;&lt;br /&gt;
&lt;br /&gt;
  hideElement(tableResultHistory.rows[1]);&lt;br /&gt;
&lt;br /&gt;
  var valuesToDisplay = [&lt;br /&gt;
    attackerName,&lt;br /&gt;
    victimName,&lt;br /&gt;
    attackTypeSelection.options[attackTypeSelection.selectedIndex].textContent,&lt;br /&gt;
    meanDamages,&lt;br /&gt;
    minDamages,&lt;br /&gt;
    maxDamages,&lt;br /&gt;
  ];&lt;br /&gt;
&lt;br /&gt;
  savedFights.push(valuesToDisplay);&lt;br /&gt;
  updateSavedFights(savedFights);&lt;br /&gt;
&lt;br /&gt;
  editTableResultRow(tableResultFight.rows[1], valuesToDisplay, numberFormat);&lt;br /&gt;
  addRowToTableResultHistory(&lt;br /&gt;
    tableResultHistory,&lt;br /&gt;
    valuesToDisplay,&lt;br /&gt;
    deleteFightTemplate,&lt;br /&gt;
    numberFormat&lt;br /&gt;
  );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function displayFightInfo(&lt;br /&gt;
  possibleDamagesCount,&lt;br /&gt;
  damagesTime,&lt;br /&gt;
  displayTime,&lt;br /&gt;
  battle&lt;br /&gt;
) {&lt;br /&gt;
  var container = battle.possibleDamagesCounter.parentElement;&lt;br /&gt;
&lt;br /&gt;
  if (possibleDamagesCount &amp;lt;= 1) {&lt;br /&gt;
    hideElement(container);&lt;br /&gt;
    return;&lt;br /&gt;
  } else {&lt;br /&gt;
    showElement(container);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  possibleDamagesCount =&lt;br /&gt;
    battle.numberFormats.default.format(possibleDamagesCount);&lt;br /&gt;
  damagesTime = battle.numberFormats.second.format(damagesTime / 1000);&lt;br /&gt;
  displayTime = battle.numberFormats.second.format(displayTime / 1000);&lt;br /&gt;
&lt;br /&gt;
  battle.possibleDamagesCounter.textContent = possibleDamagesCount;&lt;br /&gt;
  battle.damagesTime.textContent = damagesTime;&lt;br /&gt;
  battle.displayTime.textContent = displayTime;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isPseudoSaved(characters, pseudo) {&lt;br /&gt;
  return characters.savedCharacters.hasOwnProperty(pseudo);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createBattle(characters, battle) {&lt;br /&gt;
  battle.battleForm.addEventListener(&amp;quot;submit&amp;quot;, function (event) {&lt;br /&gt;
    event.preventDefault();&lt;br /&gt;
&lt;br /&gt;
    // auto save&lt;br /&gt;
    if (characters.unsavedChanges) {&lt;br /&gt;
      characters.saveButton.click();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var battleInfo = new FormData(event.target);&lt;br /&gt;
    var attackerName = battleInfo.get(&amp;quot;attacker&amp;quot;);&lt;br /&gt;
    var attackType = battleInfo.get(&amp;quot;attackTypeSelection&amp;quot;);&lt;br /&gt;
    var victimName = battleInfo.get(&amp;quot;victim&amp;quot;);&lt;br /&gt;
    var attackerVariation;&lt;br /&gt;
    var victimVariation;&lt;br /&gt;
&lt;br /&gt;
    if (!attackerName &amp;amp;&amp;amp; !attackType &amp;amp;&amp;amp; !victimName) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isPseudoSaved(characters, attackerName)) {&lt;br /&gt;
      var attacker = copyObject(characters.savedCharacters[attackerName]);&lt;br /&gt;
      attackerVariation = attacker.bonusVariation;&lt;br /&gt;
    } else {&lt;br /&gt;
      var attacker = createMonster(attackerName);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isPseudoSaved(characters, victimName)) {&lt;br /&gt;
      var victim = copyObject(characters.savedCharacters[victimName]);&lt;br /&gt;
      victimVariation = victim.bonusVariation;&lt;br /&gt;
    } else {&lt;br /&gt;
      var victim = createMonster(victimName, attacker);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      isChecked(attacker.bonusVariationActivation) &amp;amp;&amp;amp;&lt;br /&gt;
      attacker.hasOwnProperty(attackerVariation) &amp;amp;&amp;amp;&lt;br /&gt;
      attacker.bonusVariationMinValue &amp;lt; attacker.bonusVariationMaxValue&lt;br /&gt;
    ) {&lt;br /&gt;
      damagesWithVariation(&lt;br /&gt;
        attacker,&lt;br /&gt;
        victim,&lt;br /&gt;
        attackType,&lt;br /&gt;
        battle,&lt;br /&gt;
        attacker,&lt;br /&gt;
        attackerVariation&lt;br /&gt;
      );&lt;br /&gt;
    } else if (&lt;br /&gt;
      isChecked(victim.bonusVariationActivation) &amp;amp;&amp;amp;&lt;br /&gt;
      victim.hasOwnProperty(victimVariation) &amp;amp;&amp;amp;&lt;br /&gt;
      victim.bonusVariationMinValue &amp;lt; victim.bonusVariationMaxValue&lt;br /&gt;
    ) {&lt;br /&gt;
      damagesWithVariation(&lt;br /&gt;
        attacker,&lt;br /&gt;
        victim,&lt;br /&gt;
        attackType,&lt;br /&gt;
        battle,&lt;br /&gt;
        victim,&lt;br /&gt;
        victimVariation&lt;br /&gt;
      );&lt;br /&gt;
    } else {&lt;br /&gt;
      damagesWithoutVariation(attacker, victim, attackType, battle, characters);&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createMapping() {&lt;br /&gt;
  mapping = {&lt;br /&gt;
    typeFlag: [&lt;br /&gt;
      &amp;quot;animalBonus&amp;quot;, // 0&lt;br /&gt;
      &amp;quot;humanBonus&amp;quot;, // 1&lt;br /&gt;
      &amp;quot;orcBonus&amp;quot;, // 2&lt;br /&gt;
      &amp;quot;mysticBonus&amp;quot;, // 3&lt;br /&gt;
      &amp;quot;undeadBonus&amp;quot;, // 4&lt;br /&gt;
      &amp;quot;insectBonus&amp;quot;, // 5&lt;br /&gt;
      &amp;quot;desertBonus&amp;quot;, // 6&lt;br /&gt;
      &amp;quot;devilBonus&amp;quot;, // 7&lt;br /&gt;
    ],&lt;br /&gt;
    raceBonus: {&lt;br /&gt;
      warrior: &amp;quot;warriorBonus&amp;quot;,&lt;br /&gt;
      sura: &amp;quot;suraBonus&amp;quot;,&lt;br /&gt;
      ninja: &amp;quot;ninjaBonus&amp;quot;,&lt;br /&gt;
      shaman: &amp;quot;shamanBonus&amp;quot;,&lt;br /&gt;
      lycan: &amp;quot;lycanBonus&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    raceResistance: {&lt;br /&gt;
      warrior: &amp;quot;warriorResistance&amp;quot;,&lt;br /&gt;
      sura: &amp;quot;suraResistance&amp;quot;,&lt;br /&gt;
      ninja: &amp;quot;ninjaResistance&amp;quot;,&lt;br /&gt;
      shaman: &amp;quot;shamanResistance&amp;quot;,&lt;br /&gt;
      lycan: &amp;quot;lycanResistance&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    defenseWeapon: [&lt;br /&gt;
      &amp;quot;swordDefense&amp;quot;, // 0&lt;br /&gt;
      &amp;quot;daggerDefense&amp;quot;, // 1&lt;br /&gt;
      &amp;quot;arrowDefense&amp;quot;, // 2&lt;br /&gt;
      &amp;quot;twoHandedSwordDefense&amp;quot;, // 3&lt;br /&gt;
      &amp;quot;bellDefense&amp;quot;, // 4&lt;br /&gt;
      &amp;quot;clawDefense&amp;quot;, // 5&lt;br /&gt;
      &amp;quot;fanDefense&amp;quot;, // 6&lt;br /&gt;
      &amp;quot;swordDefense&amp;quot;, // 7&lt;br /&gt;
      &amp;quot;fistDefense&amp;quot;, // 8&lt;br /&gt;
    ],&lt;br /&gt;
    breakWeapon: [&lt;br /&gt;
      &amp;quot;breakSwordDefense&amp;quot;, // 0&lt;br /&gt;
      &amp;quot;breakDaggerDefense&amp;quot;, // 1&lt;br /&gt;
      &amp;quot;breakArrowDefense&amp;quot;, // 2&lt;br /&gt;
      &amp;quot;breakTwoHandedSwordDefense&amp;quot;, // 3&lt;br /&gt;
      &amp;quot;breakBellDefense&amp;quot;, // 4&lt;br /&gt;
      &amp;quot;breakClawDefense&amp;quot;, // 5&lt;br /&gt;
      &amp;quot;breakFanDefense&amp;quot;, // 6&lt;br /&gt;
      &amp;quot;breakSwordDefense&amp;quot;, // 7&lt;br /&gt;
    ],&lt;br /&gt;
    elementBonus: [&lt;br /&gt;
      &amp;quot;fireBonus&amp;quot;, // 0&lt;br /&gt;
      &amp;quot;iceBonus&amp;quot;, // 1&lt;br /&gt;
      &amp;quot;windBonus&amp;quot;, // 2&lt;br /&gt;
      &amp;quot;lightningBonus&amp;quot;, // 3&lt;br /&gt;
      &amp;quot;earthBonus&amp;quot;, // 4&lt;br /&gt;
      &amp;quot;darknessBonus&amp;quot;, // 5&lt;br /&gt;
    ],&lt;br /&gt;
    elementResistance: [&lt;br /&gt;
      &amp;quot;fireResistance&amp;quot;, // 0&lt;br /&gt;
      &amp;quot;iceResistance&amp;quot;, // 1&lt;br /&gt;
      &amp;quot;windResistance&amp;quot;, // 2&lt;br /&gt;
      &amp;quot;lightningResistance&amp;quot;, // 3&lt;br /&gt;
      &amp;quot;earthResistance&amp;quot;, // 4&lt;br /&gt;
      &amp;quot;darknessResistance&amp;quot;, // 5&lt;br /&gt;
    ],&lt;br /&gt;
  };&lt;br /&gt;
  return mapping;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createConstants() {&lt;br /&gt;
  var constants = {&lt;br /&gt;
    polymorphPowerTable: [&lt;br /&gt;
      10, 11, 11, 12, 13, 13, 14, 15, 16, 17, 18, 19, 20, 22, 23, 24, 26, 27,&lt;br /&gt;
      29, 31, 33, 35, 37, 39, 41, 44, 46, 49, 52, 55, 59, 62, 66, 70, 74, 79,&lt;br /&gt;
      84, 89, 94, 100, 0,&lt;br /&gt;
    ],&lt;br /&gt;
    skillPowerTable: [&lt;br /&gt;
      0, 0.05, 0.06, 0.08, 0.1, 0.12, 0.14, 0.16, 0.18, 0.2, 0.22, 0.24, 0.26,&lt;br /&gt;
      0.28, 0.3, 0.32, 0.34, 0.36, 0.38, 0.4, 0.5, 0.52, 0.54, 0.56, 0.58, 0.6,&lt;br /&gt;
      0.63, 0.66, 0.69, 0.72, 0.82, 0.85, 0.88, 0.91, 0.94, 0.98, 1.02, 1.06,&lt;br /&gt;
      1.1, 1.15, 1.25,&lt;br /&gt;
    ],&lt;br /&gt;
    marriageTable: {&lt;br /&gt;
      harmonyEarrings: [4, 5, 6, 8],&lt;br /&gt;
      loveEarrings: [4, 5, 6, 8],&lt;br /&gt;
      harmonyBracelet: [4, 5, 6, 8],&lt;br /&gt;
      loveNecklace: [20, 25, 30, 40],&lt;br /&gt;
      harmonyNecklace: [12, 16, 20, 30],&lt;br /&gt;
    },&lt;br /&gt;
    allowedWeaponsPerRace: {&lt;br /&gt;
      warrior: [0, 3, 8],&lt;br /&gt;
      ninja: [0, 1, 2, 8],&lt;br /&gt;
      sura: [0, 7, 8],&lt;br /&gt;
      shaman: [4, 6, 8],&lt;br /&gt;
      lycan: [5, 8],&lt;br /&gt;
    },&lt;br /&gt;
    translation: {&lt;br /&gt;
      fr: {&lt;br /&gt;
        damages: &amp;quot;Dégâts&amp;quot;,&lt;br /&gt;
        percentage: &amp;quot;Pourcentage&amp;quot;,&lt;br /&gt;
        miss: &amp;quot;Miss&amp;quot;,&lt;br /&gt;
        normalHit: &amp;quot;Coup classique&amp;quot;,&lt;br /&gt;
        criticalHit: &amp;quot;Coup critique&amp;quot;,&lt;br /&gt;
        piercingHit: &amp;quot;Coup perçant&amp;quot;,&lt;br /&gt;
        criticalPiercingHit: &amp;quot;Coup critique perçant&amp;quot;,&lt;br /&gt;
        damagesRepartition: &amp;quot;Distribution des dégâts&amp;quot;,&lt;br /&gt;
        averageDamages: &amp;quot;Dégâts moyens&amp;quot;,&lt;br /&gt;
        damagesAugmentation: &amp;quot;Augmentation des dégâts&amp;quot;,&lt;br /&gt;
        bonusVariationTitle: [&lt;br /&gt;
          &amp;quot;Évolution des dégâts moyens&amp;quot;,&lt;br /&gt;
          &amp;quot;par rapport à la valeur d'un bonus&amp;quot;,&lt;br /&gt;
        ],&lt;br /&gt;
      },&lt;br /&gt;
      en: {&lt;br /&gt;
        damages: &amp;quot;Damage&amp;quot;,&lt;br /&gt;
        percentage: &amp;quot;Percentage&amp;quot;,&lt;br /&gt;
        miss: &amp;quot;Miss&amp;quot;,&lt;br /&gt;
        normalHit: &amp;quot;Normal Hit&amp;quot;,&lt;br /&gt;
        criticalHit: &amp;quot;Critical Hit&amp;quot;,&lt;br /&gt;
        piercingHit: &amp;quot;Piercing Hit&amp;quot;,&lt;br /&gt;
        criticalPiercingHit: &amp;quot;Critical Piercing Hit&amp;quot;,&lt;br /&gt;
        damagesRepartition: &amp;quot;Damage Repartition&amp;quot;,&lt;br /&gt;
        averageDamages: &amp;quot;Average Damage&amp;quot;,&lt;br /&gt;
        damagesAugmentation: &amp;quot;Damage Augmentation&amp;quot;,&lt;br /&gt;
        bonusVariationTitle: [&lt;br /&gt;
          &amp;quot;Evolution of Average Damage&amp;quot;,&lt;br /&gt;
          &amp;quot;Relative to a Bonus Value&amp;quot;,&lt;br /&gt;
        ],&lt;br /&gt;
      },&lt;br /&gt;
      tr: {&lt;br /&gt;
        damages: &amp;quot;Hasar&amp;quot;,&lt;br /&gt;
        percentage: &amp;quot;Yüzde&amp;quot;,&lt;br /&gt;
        miss: &amp;quot;Miss Vuruş&amp;quot;,&lt;br /&gt;
        normalHit: &amp;quot;Düz Vuruş&amp;quot;,&lt;br /&gt;
        criticalHit: &amp;quot;Kritik Vuruş&amp;quot;,&lt;br /&gt;
        piercingHit: &amp;quot;Delici Vuruş&amp;quot;,&lt;br /&gt;
        criticalPiercingHit: &amp;quot;Kritikli Delici Vuruş&amp;quot;,&lt;br /&gt;
        damagesRepartition: &amp;quot;Hasar Dağılımı&amp;quot;,&lt;br /&gt;
        averageDamages: &amp;quot;Ortalama Hasar&amp;quot;,&lt;br /&gt;
        damagesAugmentation: &amp;quot;Ortalama Hasar Artışı&amp;quot;,&lt;br /&gt;
        bonusVariationTitle: [&lt;br /&gt;
          &amp;quot;Bir bonusun değerine kıyasla&amp;quot;,&lt;br /&gt;
          &amp;quot;Ortalama Hasar Çizelgesi&amp;quot;,&lt;br /&gt;
        ],&lt;br /&gt;
      },&lt;br /&gt;
      ro: {&lt;br /&gt;
        damages: &amp;quot;Daune&amp;quot;,&lt;br /&gt;
        percentage: &amp;quot;Procent&amp;quot;,&lt;br /&gt;
        miss: &amp;quot;Miss&amp;quot;,&lt;br /&gt;
        normalHit: &amp;quot;Lovitura normala&amp;quot;,&lt;br /&gt;
        criticalHit: &amp;quot;Lovitura critica&amp;quot;,&lt;br /&gt;
        piercingHit: &amp;quot;Lovitura patrunzatoare&amp;quot;,&lt;br /&gt;
        criticalPiercingHit: &amp;quot;Lovitura critica si patrunzatoare&amp;quot;,&lt;br /&gt;
        damagesRepartition: &amp;quot;Distribuția daunelor&amp;quot;,&lt;br /&gt;
        averageDamages: &amp;quot;Media damageului&amp;quot;,&lt;br /&gt;
        damagesAugmentation: &amp;quot;Damage imbunatatit&amp;quot;,&lt;br /&gt;
        bonusVariationTitle: [&lt;br /&gt;
          &amp;quot;Evolutia mediei damageului&amp;quot;,&lt;br /&gt;
          &amp;quot;relativ la o valoare bonus&amp;quot;,&lt;br /&gt;
        ],&lt;br /&gt;
      },&lt;br /&gt;
      de: {&lt;br /&gt;
        damages: &amp;quot;Schäden&amp;quot;,&lt;br /&gt;
        percentage: &amp;quot;Prozentsatz&amp;quot;,&lt;br /&gt;
        miss: &amp;quot;Verfehlen&amp;quot;,&lt;br /&gt;
        normalHit: &amp;quot;Normaler Treffer&amp;quot;,&lt;br /&gt;
        criticalHit: &amp;quot;Kritischer Treffer&amp;quot;,&lt;br /&gt;
        piercingHit: &amp;quot;Durchdringender Treffer&amp;quot;,&lt;br /&gt;
        criticalPiercingHit: &amp;quot;Kritischer durchdringender Treffer&amp;quot;,&lt;br /&gt;
        damagesRepartition: &amp;quot;Schadensverteilung&amp;quot;,&lt;br /&gt;
        averageDamages: &amp;quot;Durchschnittlicher Schaden&amp;quot;,&lt;br /&gt;
        damagesAugmentation: &amp;quot;Schadenserhöhung&amp;quot;,&lt;br /&gt;
        bonusVariationTitle: [&lt;br /&gt;
          &amp;quot;Entwicklung des durchschnittlichen Schadens&amp;quot;,&lt;br /&gt;
          &amp;quot;im Verhältnis zu einem Bonus&amp;quot;,&lt;br /&gt;
        ],&lt;br /&gt;
      },&lt;br /&gt;
      pt: {&lt;br /&gt;
        damages: &amp;quot;Dano&amp;quot;,&lt;br /&gt;
        percentage: &amp;quot;Percentagem&amp;quot;,&lt;br /&gt;
        miss: &amp;quot;Miss&amp;quot;,&lt;br /&gt;
        normalHit: &amp;quot;Dano normal&amp;quot;,&lt;br /&gt;
        criticalHit: &amp;quot;Dano crítico&amp;quot;,&lt;br /&gt;
        piercingHit: &amp;quot;Dano perfurante&amp;quot;,&lt;br /&gt;
        criticalPiercingHit: &amp;quot;Dano crítico perfurante&amp;quot;,&lt;br /&gt;
        damagesRepartition: &amp;quot;Repartição de dano&amp;quot;,&lt;br /&gt;
        averageDamages: &amp;quot;Dano médio&amp;quot;,&lt;br /&gt;
        damagesAugmentation: &amp;quot;Aumento de dano&amp;quot;,&lt;br /&gt;
        bonusVariationTitle: [&amp;quot;Evolução do dano médio&amp;quot;, &amp;quot;relativo a um bónus&amp;quot;],&lt;br /&gt;
      },&lt;br /&gt;
      // es: {&lt;br /&gt;
      //   damages: &amp;quot;Daño&amp;quot;,&lt;br /&gt;
      //   percentage: &amp;quot;Porcentaje&amp;quot;,&lt;br /&gt;
      //   miss: &amp;quot;Miss&amp;quot;,&lt;br /&gt;
      //   normalHit: &amp;quot;Daño normal&amp;quot;,&lt;br /&gt;
      //   criticalHit: &amp;quot;Daño crítico&amp;quot;,&lt;br /&gt;
      //   piercingHit: &amp;quot;Daño perforante&amp;quot;,&lt;br /&gt;
      //   criticalPiercingHit: &amp;quot;Daño crítico perforante&amp;quot;,&lt;br /&gt;
      //   damagesRepartition: &amp;quot;Repartición de daños&amp;quot;,&lt;br /&gt;
      //   averageDamages: &amp;quot;Daño medio&amp;quot;,&lt;br /&gt;
      //   damagesAugmentation: &amp;quot;Aumento de daño&amp;quot;,&lt;br /&gt;
      //   bonusVariationTitle: [&amp;quot;Evolución del daño medio&amp;quot;, &amp;quot;Relativo a una bonificación&amp;quot;]&lt;br /&gt;
      // },&lt;br /&gt;
    },&lt;br /&gt;
  };&lt;br /&gt;
  return constants;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initResultTableHistory(battle) {&lt;br /&gt;
  var {&lt;br /&gt;
    tableResultHistory,&lt;br /&gt;
    savedFights,&lt;br /&gt;
    deleteFightTemplate,&lt;br /&gt;
    numberFormats: { default: numberFormat },&lt;br /&gt;
  } = battle;&lt;br /&gt;
  var startIndex = 3;&lt;br /&gt;
&lt;br /&gt;
  if (savedFights.length) {&lt;br /&gt;
    hideElement(tableResultHistory.rows[1]);&lt;br /&gt;
&lt;br /&gt;
    for (var savedFight of savedFights) {&lt;br /&gt;
      addRowToTableResultHistory(&lt;br /&gt;
        tableResultHistory,&lt;br /&gt;
        savedFight,&lt;br /&gt;
        deleteFightTemplate,&lt;br /&gt;
        numberFormat&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  tableResultHistory.addEventListener(&amp;quot;click&amp;quot;, function (event) {&lt;br /&gt;
    var deleteButton = event.target.closest(&amp;quot;.svg-icon-delete&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (deleteButton) {&lt;br /&gt;
      var row = deleteButton.closest(&amp;quot;tr&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
      if (row) {&lt;br /&gt;
        savedFights.splice(row.rowIndex - startIndex, 1);&lt;br /&gt;
        updateSavedFights(savedFights);&lt;br /&gt;
&lt;br /&gt;
        row.remove();&lt;br /&gt;
&lt;br /&gt;
        if (tableResultHistory.rows.length === startIndex) {&lt;br /&gt;
          showElement(tableResultHistory.rows[1]);&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initDamagesChart(battle) {&lt;br /&gt;
  var { translation, reduceChartPointsContainer, reduceChartPoints } = battle;&lt;br /&gt;
  var percentFormat = battle.numberFormats.percent;&lt;br /&gt;
  var customPlugins = {&lt;br /&gt;
    id: &amp;quot;customPlugins&amp;quot;,&lt;br /&gt;
    afterDraw(chart) {&lt;br /&gt;
      var missPercentage = chart.data.missPercentage;&lt;br /&gt;
&lt;br /&gt;
      if (!missPercentage) {&lt;br /&gt;
        return;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      var {&lt;br /&gt;
        ctx,&lt;br /&gt;
        chartArea: { top, right },&lt;br /&gt;
      } = chart;&lt;br /&gt;
      ctx.save();&lt;br /&gt;
      var text =&lt;br /&gt;
        translation.miss + &amp;quot; : &amp;quot; + percentFormat.format(missPercentage);&lt;br /&gt;
      var padding = 4;&lt;br /&gt;
      var fontSize = 14;&lt;br /&gt;
&lt;br /&gt;
      ctx.font = fontSize + &amp;quot;px Helvetica Neue&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
      var textWidth = ctx.measureText(text).width;&lt;br /&gt;
      var xPosition = right - textWidth - 5;&lt;br /&gt;
      var yPosition = top + 5;&lt;br /&gt;
&lt;br /&gt;
      ctx.fillStyle = &amp;quot;rgba(255, 0, 0, 0.2)&amp;quot;;&lt;br /&gt;
      ctx.fillRect(&lt;br /&gt;
        xPosition - padding,&lt;br /&gt;
        yPosition - padding,&lt;br /&gt;
        textWidth + 2 * padding,&lt;br /&gt;
        fontSize + 2 * padding&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      ctx.strokeStyle = &amp;quot;red&amp;quot;;&lt;br /&gt;
      ctx.strokeRect(&lt;br /&gt;
        xPosition - padding,&lt;br /&gt;
        yPosition - padding,&lt;br /&gt;
        textWidth + 2 * padding,&lt;br /&gt;
        fontSize + 2 * padding&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      ctx.fillStyle = &amp;quot;#666&amp;quot;;&lt;br /&gt;
      ctx.textBaseline = &amp;quot;top&amp;quot;;&lt;br /&gt;
      ctx.fillText(text, xPosition, yPosition + 1);&lt;br /&gt;
&lt;br /&gt;
      ctx.restore();&lt;br /&gt;
    },&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  Chart.register(customPlugins);&lt;br /&gt;
&lt;br /&gt;
  var ctx = battle.plotDamages.getContext(&amp;quot;2d&amp;quot;);&lt;br /&gt;
  var maxLabelsInTooltip = 10;&lt;br /&gt;
  var nullLabelText = &amp;quot; ...&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  var chart = new Chart(ctx, {&lt;br /&gt;
    type: &amp;quot;scatter&amp;quot;,&lt;br /&gt;
    data: {&lt;br /&gt;
      missPercentage: 0,&lt;br /&gt;
      datasets: [],&lt;br /&gt;
    },&lt;br /&gt;
    options: {&lt;br /&gt;
      responsive: true,&lt;br /&gt;
      maintainAspectRatio: false,&lt;br /&gt;
      plugins: {&lt;br /&gt;
        legend: {&lt;br /&gt;
          display: true,&lt;br /&gt;
          onHover: function (e) {&lt;br /&gt;
            e.native.target.style.cursor = &amp;quot;pointer&amp;quot;;&lt;br /&gt;
          },&lt;br /&gt;
          onLeave: function (e) {&lt;br /&gt;
            e.native.target.style.cursor = &amp;quot;default&amp;quot;;&lt;br /&gt;
          },&lt;br /&gt;
          onClick: function (e, legendItem, legend) {&lt;br /&gt;
            var currentIndex = legendItem.datasetIndex;&lt;br /&gt;
            var ci = legend.chart;&lt;br /&gt;
            var isCurrentDatasetVisible = ci.isDatasetVisible(currentIndex);&lt;br /&gt;
            var datasets = ci.data.datasets;&lt;br /&gt;
            var hideReducePoints = true;&lt;br /&gt;
            var isReducePointsChecked = reduceChartPoints.checked;&lt;br /&gt;
&lt;br /&gt;
            datasets[currentIndex].hidden = isCurrentDatasetVisible;&lt;br /&gt;
            legendItem.hidden = isCurrentDatasetVisible;&lt;br /&gt;
&lt;br /&gt;
            for (var index in datasets) {&lt;br /&gt;
              if (ci.isDatasetVisible(index) &amp;amp;&amp;amp; datasets[index].canBeReduced) {&lt;br /&gt;
                showElement(reduceChartPointsContainer);&lt;br /&gt;
                hideReducePoints = false;&lt;br /&gt;
                break;&lt;br /&gt;
              }&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            if (hideReducePoints) {&lt;br /&gt;
              hideElement(reduceChartPointsContainer);&lt;br /&gt;
              handleChartAnimations(ci, true);&lt;br /&gt;
            } else {&lt;br /&gt;
              handleChartAnimations(ci, isReducePointsChecked);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            ci.update();&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        title: {&lt;br /&gt;
          display: true,&lt;br /&gt;
          text: translation.damagesRepartition,&lt;br /&gt;
          font: {&lt;br /&gt;
            size: 20,&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        tooltip: {&lt;br /&gt;
          callbacks: {&lt;br /&gt;
            label: function (context) {&lt;br /&gt;
              if (context.label === null) {&lt;br /&gt;
                return nullLabelText;&lt;br /&gt;
              }&lt;br /&gt;
&lt;br /&gt;
              var xValue = battle.numberFormats.default.format(&lt;br /&gt;
                context.parsed.x&lt;br /&gt;
              );&lt;br /&gt;
              var yValue = battle.numberFormats.percent.format(&lt;br /&gt;
                context.parsed.y&lt;br /&gt;
              );&lt;br /&gt;
&lt;br /&gt;
              label =&lt;br /&gt;
                &amp;quot; &amp;quot; +&lt;br /&gt;
                context.dataset.label +&lt;br /&gt;
                &amp;quot; : (&amp;quot; +&lt;br /&gt;
                xValue +&lt;br /&gt;
                &amp;quot;, &amp;quot; +&lt;br /&gt;
                yValue +&lt;br /&gt;
                &amp;quot;)&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
              return label;&lt;br /&gt;
            },&lt;br /&gt;
            beforeBody: function (tooltipItems) {&lt;br /&gt;
              if (tooltipItems.length &amp;gt; maxLabelsInTooltip + 1) {&lt;br /&gt;
                tooltipItems.splice(maxLabelsInTooltip + 1);&lt;br /&gt;
                tooltipItems[maxLabelsInTooltip].label = null;&lt;br /&gt;
              }&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          caretPadding: 10,&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
      scales: {&lt;br /&gt;
        x: {&lt;br /&gt;
          type: &amp;quot;linear&amp;quot;,&lt;br /&gt;
          position: &amp;quot;bottom&amp;quot;,&lt;br /&gt;
          title: {&lt;br /&gt;
            display: true,&lt;br /&gt;
            text: translation.damages,&lt;br /&gt;
            font: {&lt;br /&gt;
              size: 16,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        y: {&lt;br /&gt;
          title: {&lt;br /&gt;
            display: true,&lt;br /&gt;
            text: translation.percentage,&lt;br /&gt;
            font: {&lt;br /&gt;
              size: 16,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          ticks: {&lt;br /&gt;
            format: {&lt;br /&gt;
              style: &amp;quot;percent&amp;quot;,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
      elements: {&lt;br /&gt;
        point: {&lt;br /&gt;
          borderWidth: 1,&lt;br /&gt;
          radius: 3,&lt;br /&gt;
          hitRadius: 3,&lt;br /&gt;
          hoverRadius: 6,&lt;br /&gt;
          hoverBorderWidth: 2,&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
    },&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  var datasetsStyle = [&lt;br /&gt;
    {&lt;br /&gt;
      name: &amp;quot;normalHit&amp;quot;,&lt;br /&gt;
      canBeReduced: false,&lt;br /&gt;
      label: translation.normalHit,&lt;br /&gt;
      backgroundColor: &amp;quot;rgba(75, 192, 192, 0.2)&amp;quot;,&lt;br /&gt;
      borderColor: &amp;quot;rgba(75, 192, 192, 1)&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      name: &amp;quot;piercingHit&amp;quot;,&lt;br /&gt;
      canBeReduced: false,&lt;br /&gt;
      label: translation.piercingHit,&lt;br /&gt;
      backgroundColor: &amp;quot;rgba(192, 192, 75, 0.2)&amp;quot;,&lt;br /&gt;
      borderColor: &amp;quot;rgba(192, 192, 75, 1)&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      name: &amp;quot;criticalHit&amp;quot;,&lt;br /&gt;
      canBeReduced: false,&lt;br /&gt;
      label: translation.criticalHit,&lt;br /&gt;
      backgroundColor: &amp;quot;rgba(192, 75, 192, 0.2)&amp;quot;,&lt;br /&gt;
      borderColor: &amp;quot;rgba(192, 75, 192, 1)&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      name: &amp;quot;criticalPiercingHit&amp;quot;,&lt;br /&gt;
      canBeReduced: false,&lt;br /&gt;
      label: translation.criticalPiercingHit,&lt;br /&gt;
      backgroundColor: &amp;quot;rgba(75, 75, 192, 0.2)&amp;quot;,&lt;br /&gt;
      borderColor: &amp;quot;rgba(75, 75, 192, 1)&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
  ];&lt;br /&gt;
  battle.damagesChart = {&lt;br /&gt;
    chart: chart,&lt;br /&gt;
    datasetsStyle: datasetsStyle,&lt;br /&gt;
    maxPoints: 500,&lt;br /&gt;
    reduceChartPointsContainer: reduceChartPointsContainer,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initBonusVariationChart(battle) {&lt;br /&gt;
  var translation = battle.translation;&lt;br /&gt;
&lt;br /&gt;
  var ctx = battle.plotBonusVariation.getContext(&amp;quot;2d&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  var chart = new Chart(ctx, {&lt;br /&gt;
    type: &amp;quot;line&amp;quot;,&lt;br /&gt;
    data: {&lt;br /&gt;
      datasets: [&lt;br /&gt;
        {&lt;br /&gt;
          label: translation.averageDamages,&lt;br /&gt;
          backgroundColor: &amp;quot;rgba(75, 192, 192, 0.2)&amp;quot;,&lt;br /&gt;
          borderColor: &amp;quot;rgba(75, 192, 192, 1)&amp;quot;,&lt;br /&gt;
          fill: true,&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          label: translation.damagesAugmentation,&lt;br /&gt;
          backgroundColor: &amp;quot;rgba(192, 192, 75, 0.2)&amp;quot;,&lt;br /&gt;
          borderColor: &amp;quot;rgba(192, 192, 75, 1)&amp;quot;,&lt;br /&gt;
          hidden: true,&lt;br /&gt;
          yTicksFormat: { style: &amp;quot;percent&amp;quot; },&lt;br /&gt;
          fill: true,&lt;br /&gt;
        },&lt;br /&gt;
      ],&lt;br /&gt;
    },&lt;br /&gt;
    options: {&lt;br /&gt;
      responsive: true,&lt;br /&gt;
      maintainAspectRatio: false,&lt;br /&gt;
      plugins: {&lt;br /&gt;
        legend: {&lt;br /&gt;
          display: true,&lt;br /&gt;
          onHover: function (e) {&lt;br /&gt;
            e.native.target.style.cursor = &amp;quot;pointer&amp;quot;;&lt;br /&gt;
          },&lt;br /&gt;
          onLeave: function (e) {&lt;br /&gt;
            e.native.target.style.cursor = &amp;quot;default&amp;quot;;&lt;br /&gt;
          },&lt;br /&gt;
          onClick: function (e, legendItem, legend) {&lt;br /&gt;
            var currentIndex = legendItem.datasetIndex;&lt;br /&gt;
            var ci = legend.chart;&lt;br /&gt;
            var datasets = ci.data.datasets;&lt;br /&gt;
            var isCurrentDatasetVisible = ci.isDatasetVisible(currentIndex);&lt;br /&gt;
            var yAxis = ci.options.scales.y;&lt;br /&gt;
&lt;br /&gt;
            var otherIndex = currentIndex === 0 ? 1 : 0;&lt;br /&gt;
            var visibleDataset = isCurrentDatasetVisible&lt;br /&gt;
              ? datasets[otherIndex]&lt;br /&gt;
              : datasets[currentIndex];&lt;br /&gt;
&lt;br /&gt;
            datasets[currentIndex].hidden = isCurrentDatasetVisible;&lt;br /&gt;
            datasets[otherIndex].hidden = !isCurrentDatasetVisible;&lt;br /&gt;
&lt;br /&gt;
            yAxis.title.text = visibleDataset.label;&lt;br /&gt;
            yAxis.ticks.format = visibleDataset.yTicksFormat;&lt;br /&gt;
&lt;br /&gt;
            ci.update();&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        title: {&lt;br /&gt;
          display: true,&lt;br /&gt;
          text: translation.bonusVariationTitle,&lt;br /&gt;
          font: {&lt;br /&gt;
            size: 18,&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        tooltip: {&lt;br /&gt;
          caretPadding: 10,&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
      scales: {&lt;br /&gt;
        x: {&lt;br /&gt;
          type: &amp;quot;linear&amp;quot;,&lt;br /&gt;
          position: &amp;quot;bottom&amp;quot;,&lt;br /&gt;
          title: {&lt;br /&gt;
            display: true,&lt;br /&gt;
            text: &amp;quot;Bonus&amp;quot;,&lt;br /&gt;
            font: {&lt;br /&gt;
              size: 16,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          ticks: {&lt;br /&gt;
            callback: function (value) {&lt;br /&gt;
              if (Number.isInteger(value)) {&lt;br /&gt;
                return Number(value);&lt;br /&gt;
              }&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        y: {&lt;br /&gt;
          title: {&lt;br /&gt;
            display: true,&lt;br /&gt;
            text: translation.averageDamages,&lt;br /&gt;
            font: {&lt;br /&gt;
              size: 16,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
      elements: {&lt;br /&gt;
        point: {&lt;br /&gt;
          borderWidth: 1,&lt;br /&gt;
          radius: 3,&lt;br /&gt;
          hitRadius: 3,&lt;br /&gt;
          hoverRadius: 6,&lt;br /&gt;
          hoverBorderWidth: 2,&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
    },&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  battle.bonusVariationChart = chart;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function attackSelectonListener(&lt;br /&gt;
  characters,&lt;br /&gt;
  attackerSelection,&lt;br /&gt;
  attackTypeSelection&lt;br /&gt;
) {&lt;br /&gt;
  attackerSelection.addEventListener(&amp;quot;change&amp;quot;, function (event) {&lt;br /&gt;
    var attackerName = event.target.value;&lt;br /&gt;
&lt;br /&gt;
    if (isPseudoSaved(characters, attackerName)) {&lt;br /&gt;
      var attacker = characters.savedCharacters[attackerName];&lt;br /&gt;
      filterAttackTypeSelection(attacker, attackTypeSelection);&lt;br /&gt;
    } else {&lt;br /&gt;
      filterAttackTypeSelectionMonster(attackTypeSelection);&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getTranslation(translation) {&lt;br /&gt;
  var userLanguage = navigator.language;&lt;br /&gt;
  var langToUse = &amp;quot;en&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  for (var lang in translation) {&lt;br /&gt;
    if (userLanguage.startsWith(lang)) {&lt;br /&gt;
      langToUse = lang;&lt;br /&gt;
      break;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return translation[langToUse];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createDamageCalculatorInformation(chartSource) {&lt;br /&gt;
  var characters = {&lt;br /&gt;
    unsavedChanges: false,&lt;br /&gt;
    savedCharacters: {},&lt;br /&gt;
    currentCharacter: null,&lt;br /&gt;
    savedMonsters: getSavedMonsters(),&lt;br /&gt;
    characterCreation: document.getElementById(&amp;quot;character-creation&amp;quot;),&lt;br /&gt;
    addNewCharacterButton: document.getElementById(&amp;quot;add-new-character&amp;quot;),&lt;br /&gt;
    dropZone: document.getElementById(&amp;quot;character-drop-zone&amp;quot;),&lt;br /&gt;
    characterInput: document.getElementById(&amp;quot;character-input&amp;quot;),&lt;br /&gt;
    newCharacterTemplate: document.getElementById(&amp;quot;new-character-template&amp;quot;)&lt;br /&gt;
      .children[0],&lt;br /&gt;
    charactersContainer: document.getElementById(&amp;quot;characters-container&amp;quot;),&lt;br /&gt;
    monsterButtonTemplates: document.getElementById(&amp;quot;monster-button-templates&amp;quot;),&lt;br /&gt;
    monsterTemplate: document.getElementById(&amp;quot;new-monster-template&amp;quot;)&lt;br /&gt;
      .children[0],&lt;br /&gt;
    monstersContainer: document.getElementById(&amp;quot;monsters-container&amp;quot;),&lt;br /&gt;
    monsteriFrame: document.getElementById(&amp;quot;monster-iframe&amp;quot;),&lt;br /&gt;
    stoneiFrame: document.getElementById(&amp;quot;stone-iframe&amp;quot;),&lt;br /&gt;
    saveButton: document.getElementById(&amp;quot;save-character&amp;quot;),&lt;br /&gt;
    weaponCategory: document.getElementById(&amp;quot;weapon-category&amp;quot;),&lt;br /&gt;
    weaponDisplay: document.getElementById(&amp;quot;weapon-display&amp;quot;),&lt;br /&gt;
    randomAttackValue: document.getElementById(&amp;quot;random-attack-value&amp;quot;),&lt;br /&gt;
    randomMagicAttackValue: document.getElementById(&lt;br /&gt;
      &amp;quot;random-magic-attack-value&amp;quot;&lt;br /&gt;
    ),&lt;br /&gt;
    yoharaCreation: document.getElementById(&amp;quot;yohara-creation&amp;quot;),&lt;br /&gt;
    blessingCreation: document.getElementById(&amp;quot;blessing-creation&amp;quot;),&lt;br /&gt;
    marriageCreation: document.getElementById(&amp;quot;marriage-creation&amp;quot;),&lt;br /&gt;
    bonusVariation: {&lt;br /&gt;
      tab: document.getElementById(&amp;quot;Variation&amp;quot;),&lt;br /&gt;
      activation: document.getElementById(&amp;quot;bonus-variation-activation&amp;quot;),&lt;br /&gt;
      input: document.getElementById(&amp;quot;bonus-variation&amp;quot;),&lt;br /&gt;
      inputDisplay: document.getElementById(&amp;quot;bonus-variation-display&amp;quot;),&lt;br /&gt;
      container: document.getElementById(&amp;quot;bonus-variation-range&amp;quot;),&lt;br /&gt;
      minValue: document.getElementById(&amp;quot;bonus-variation-min-value&amp;quot;),&lt;br /&gt;
      maxValue: document.getElementById(&amp;quot;bonus-variation-max-value&amp;quot;),&lt;br /&gt;
    },&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  characters.bonusVariation.inputDisplay.setAttribute(&amp;quot;readonly&amp;quot;, &amp;quot;&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  for (var [pseudo, character] of Object.entries(getSavedCharacters())) {&lt;br /&gt;
    characters.savedCharacters[pseudo] = character;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var skillContainer = document.getElementById(&amp;quot;skill-container&amp;quot;);&lt;br /&gt;
  characters.skillElementsToFilter =&lt;br /&gt;
    skillContainer.querySelectorAll(&amp;quot;[data-class]&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  var mapping = createMapping();&lt;br /&gt;
  var constants = createConstants();&lt;br /&gt;
&lt;br /&gt;
  var battle = {&lt;br /&gt;
    resetAttackType: false,&lt;br /&gt;
    savedFights: getSavedFights(),&lt;br /&gt;
    battleForm: document.getElementById(&amp;quot;create-battle&amp;quot;),&lt;br /&gt;
    attackerSelection: document.getElementById(&amp;quot;attacker-selection&amp;quot;),&lt;br /&gt;
    attackTypeSelection: document.getElementById(&amp;quot;attack-type-selection&amp;quot;),&lt;br /&gt;
    victimSelection: document.getElementById(&amp;quot;victim-selection&amp;quot;),&lt;br /&gt;
    damagesWeightedByType: {},&lt;br /&gt;
    scatterDataByType: {},&lt;br /&gt;
    damagesByBonus: [],&lt;br /&gt;
    tableResultFight: document.getElementById(&amp;quot;result-table-fight&amp;quot;),&lt;br /&gt;
    tableResultHistory: document.getElementById(&amp;quot;result-table-history&amp;quot;),&lt;br /&gt;
    deleteFightTemplate: document.getElementById(&amp;quot;delete-fight-template&amp;quot;)&lt;br /&gt;
      .children[0],&lt;br /&gt;
    errorInformation: {},&lt;br /&gt;
    fightResultContainer: document.getElementById(&amp;quot;fight-result-container&amp;quot;),&lt;br /&gt;
    downLoadRawData: document.getElementById(&amp;quot;download-raw-data&amp;quot;),&lt;br /&gt;
    downLoadRawDataVariation: document.getElementById(&lt;br /&gt;
      &amp;quot;download-raw-data-variation&amp;quot;&lt;br /&gt;
    ),&lt;br /&gt;
    bonusVariationResultContainer: document.getElementById(&lt;br /&gt;
      &amp;quot;bonus-variation-result-container&amp;quot;&lt;br /&gt;
    ),&lt;br /&gt;
    reduceChartPointsContainer: document.getElementById(&lt;br /&gt;
      &amp;quot;reduce-chart-points-container&amp;quot;&lt;br /&gt;
    ),&lt;br /&gt;
    reduceChartPoints: document.getElementById(&amp;quot;reduce-chart-points&amp;quot;),&lt;br /&gt;
    plotDamages: document.getElementById(&amp;quot;plot-damages&amp;quot;),&lt;br /&gt;
    plotBonusVariation: document.getElementById(&amp;quot;plot-bonus-variation&amp;quot;),&lt;br /&gt;
    uniqueDamagesCounters: document.querySelectorAll(&amp;quot;.unique-damages-counter&amp;quot;),&lt;br /&gt;
    possibleDamagesCounter: document.getElementById(&amp;quot;possible-damages-counter&amp;quot;),&lt;br /&gt;
    damagesTime: document.getElementById(&amp;quot;damages-time&amp;quot;),&lt;br /&gt;
    displayTime: document.getElementById(&amp;quot;display-time&amp;quot;),&lt;br /&gt;
    simulationCounter: document.getElementById(&amp;quot;simulation-counter&amp;quot;),&lt;br /&gt;
    simulationTime: document.getElementById(&amp;quot;simulation-time&amp;quot;),&lt;br /&gt;
    numberFormats: {&lt;br /&gt;
      default: new Intl.NumberFormat(undefined, {&lt;br /&gt;
        minimumFractionDigits: 0,&lt;br /&gt;
        maximumFractionDigits: 1,&lt;br /&gt;
      }),&lt;br /&gt;
      percent: new Intl.NumberFormat(undefined, {&lt;br /&gt;
        style: &amp;quot;percent&amp;quot;,&lt;br /&gt;
        maximumFractionDigits: 3,&lt;br /&gt;
      }),&lt;br /&gt;
      second: new Intl.NumberFormat(undefined, {&lt;br /&gt;
        style: &amp;quot;unit&amp;quot;,&lt;br /&gt;
        unit: &amp;quot;second&amp;quot;,&lt;br /&gt;
        unitDisplay: &amp;quot;long&amp;quot;,&lt;br /&gt;
        maximumFractionDigits: 3,&lt;br /&gt;
      }),&lt;br /&gt;
    },&lt;br /&gt;
    mapping: mapping,&lt;br /&gt;
    constants: constants,&lt;br /&gt;
    translation: getTranslation(constants.translation),&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  attackSelectonListener(&lt;br /&gt;
    characters,&lt;br /&gt;
    battle.attackerSelection,&lt;br /&gt;
    battle.attackTypeSelection&lt;br /&gt;
  );&lt;br /&gt;
  initResultTableHistory(battle);&lt;br /&gt;
  addScript(chartSource, function () {&lt;br /&gt;
    initDamagesChart(battle);&lt;br /&gt;
    initBonusVariationChart(battle);&lt;br /&gt;
  });&lt;br /&gt;
  reduceChartPointsListener(battle);&lt;br /&gt;
  downloadRawDataListener(battle);&lt;br /&gt;
&lt;br /&gt;
  var errorElements = document.querySelectorAll(&amp;quot;[data-error]&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; errorElements.length; index++) {&lt;br /&gt;
    var errorElement = errorElements[index];&lt;br /&gt;
    battle.errorInformation[errorElement.dataset.error] = errorElement;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return [characters, battle];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadStyle(src) {&lt;br /&gt;
  var link = document.createElement(&amp;quot;link&amp;quot;);&lt;br /&gt;
  link.href = src;&lt;br /&gt;
  link.rel = &amp;quot;stylesheet&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  document.head.appendChild(link);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
(function () {&lt;br /&gt;
  var javascriptSource =&lt;br /&gt;
    &amp;quot;/index.php?title=Utilisateur:Ankhseram/Calculator.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&amp;quot;;&lt;br /&gt;
  var cssSource =&lt;br /&gt;
    &amp;quot;/index.php?title=Utilisateur:Ankhseram/Style.css&amp;amp;action=raw&amp;amp;ctype=text/css&amp;quot;;&lt;br /&gt;
  var chartSource = &amp;quot;https://cdn.jsdelivr.net/npm/chart.js&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  loadStyle(cssSource);&lt;br /&gt;
&lt;br /&gt;
  function main() {&lt;br /&gt;
    var [characters, battle] = createDamageCalculatorInformation(chartSource);&lt;br /&gt;
&lt;br /&gt;
    characterManagement(characters, battle);&lt;br /&gt;
    monsterManagement(characters, battle);&lt;br /&gt;
&lt;br /&gt;
    updateBattleChoice(characters, battle);&lt;br /&gt;
    createBattle(characters, battle);&lt;br /&gt;
  }&lt;br /&gt;
  addScript(javascriptSource, main);&lt;br /&gt;
})();&lt;/div&gt;</summary>
		<author><name>Dexter</name></author>
		
	</entry>
	<entry>
		<id>https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Script/Filter.js&amp;diff=105850</id>
		<title>MediaWiki:Script/Filter.js</title>
		<link rel="alternate" type="text/html" href="https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Script/Filter.js&amp;diff=105850"/>
		<updated>2024-12-17T18:21:27Z</updated>

		<summary type="html">&lt;p&gt;Dexter : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;function removeAccent(str) {&lt;br /&gt;
  return str&lt;br /&gt;
    .normalize(&amp;quot;NFD&amp;quot;)&lt;br /&gt;
    .replace(/[\u0300-\u036f]/g, &amp;quot;&amp;quot;)&lt;br /&gt;
    .toLowerCase();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function toNormalForm(str) {&lt;br /&gt;
  return removeAccent(str)&lt;br /&gt;
    .replace(/-/g, &amp;quot; &amp;quot;)&lt;br /&gt;
    .replace(/[^a-zA-Z0-9 ]/g, &amp;quot;&amp;quot;)&lt;br /&gt;
    .replace(/\s+/g, &amp;quot; &amp;quot;)&lt;br /&gt;
    .trim();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function editCardData(cardsData) {&lt;br /&gt;
  for (let cardIndex = 0; cardIndex &amp;lt; cardsData.length; cardIndex++) {&lt;br /&gt;
    const cardData = cardsData[cardIndex];&lt;br /&gt;
    const cardName = cardData.card.querySelector(&amp;quot;[data-name]&amp;quot;).textContent;&lt;br /&gt;
&lt;br /&gt;
    cardData.name = toNormalForm(cardName);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function observeLanguageChange(filterName, cardsData) {&lt;br /&gt;
  if (!filterName) {&lt;br /&gt;
    return;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  const observer = new MutationObserver(function (mutation) {&lt;br /&gt;
    editCardData(cardsData);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  observer.observe(filterName, { attributes: true });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function openFilter() {&lt;br /&gt;
  const filterButton = document.getElementById(&amp;quot;open-filter&amp;quot;);&lt;br /&gt;
  const filterDropdown = filterButton.nextElementSibling;&lt;br /&gt;
&lt;br /&gt;
  hideElement(filterDropdown);&lt;br /&gt;
&lt;br /&gt;
  filterButton.addEventListener(&amp;quot;click&amp;quot;, handleDropdown);&lt;br /&gt;
&lt;br /&gt;
  function handleDropdown() {&lt;br /&gt;
    toggleElement(filterDropdown);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  document.addEventListener(&amp;quot;mousedown&amp;quot;, function (event) {&lt;br /&gt;
    if (&lt;br /&gt;
      !filterButton.contains(event.target) &amp;amp;&amp;amp;&lt;br /&gt;
      !filterDropdown.contains(event.target)&lt;br /&gt;
    ) {&lt;br /&gt;
      hideElement(filterDropdown);&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function fillData(filter, filterData) {&lt;br /&gt;
  const { filter: category, value } = filter.dataset;&lt;br /&gt;
&lt;br /&gt;
  if (filter.type === &amp;quot;checkbox&amp;quot;) {&lt;br /&gt;
    const span = filter.parentElement.querySelector(&amp;quot;span.counter&amp;quot;);&lt;br /&gt;
    const filterInfo = { value: 0, span };&lt;br /&gt;
    const { checkbox } = filterData;&lt;br /&gt;
&lt;br /&gt;
    checkbox[category] = checkbox[category] || {};&lt;br /&gt;
    checkbox[category][value] = filterInfo;&lt;br /&gt;
  } else if (filter.type === &amp;quot;number&amp;quot;) {&lt;br /&gt;
    const { range } = filterData;&lt;br /&gt;
    if (range.hasOwnProperty(category)) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
    const init = { min: Number(filter.min), max: Number(filter.max) };&lt;br /&gt;
    range[category] = { init: init };&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function extractInitData(card, cardData) {&lt;br /&gt;
  const cardNameElement = card.querySelector(&amp;quot;[data-name]&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  cardData.card = card;&lt;br /&gt;
  cardData.name = toNormalForm(cardNameElement.textContent);&lt;br /&gt;
  cardData.trueName = cardNameElement.firstChild.title;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function extractLevelData(card, cardData) {&lt;br /&gt;
  const levelElement = card.querySelector(&amp;quot;[data-level]&amp;quot;);&lt;br /&gt;
  const [level, rank] = levelElement.textContent.slice(1, -1).split(&amp;quot;, &amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  cardData[&amp;quot;level&amp;quot;] = Number(level);&lt;br /&gt;
  cardData[&amp;quot;rank&amp;quot;] = removeAccent(rank);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function extractElementData(card, cardData) {&lt;br /&gt;
  const elementChild = card.querySelector(&amp;quot;[data-elem]&amp;quot;).children;&lt;br /&gt;
  let elementValue = &amp;quot;&amp;quot;;&lt;br /&gt;
  if (elementChild.length) {&lt;br /&gt;
    for (&lt;br /&gt;
      let elementIndex = 0;&lt;br /&gt;
      elementIndex &amp;lt; elementChild.length;&lt;br /&gt;
      elementIndex++&lt;br /&gt;
    ) {&lt;br /&gt;
      elementValue += elementChild[elementIndex].title + &amp;quot; &amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  elementValue = elementValue.trim() || &amp;quot;Aucun&amp;quot;;&lt;br /&gt;
  cardData.elem = removeAccent(elementValue);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function extractTypeData(card, cardData) {&lt;br /&gt;
  const typeElement = card.querySelector(&amp;quot;[data-type]&amp;quot;);&lt;br /&gt;
  cardData.type = removeAccent(typeElement.textContent.split(&amp;quot; &amp;quot;)[0]);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function extractDamageData(card, cardData) {&lt;br /&gt;
  const damageElement = card.querySelector(&amp;quot;[data-damage]&amp;quot;);&lt;br /&gt;
  cardData.damage = removeAccent(damageElement.textContent.replace(&amp;quot; + &amp;quot;, &amp;quot; &amp;quot;));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function extractLocData(card, cardData) {&lt;br /&gt;
  const locElement = card.querySelector(&amp;quot;[data-loc]&amp;quot;);&lt;br /&gt;
  cardData.loc = locElement.dataset.loc;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getCardsData(cardsContainer, filterData, dataExtractionMapping) {&lt;br /&gt;
  const cards = cardsContainer.children;&lt;br /&gt;
  const activeExtractors = [extractInitData];&lt;br /&gt;
&lt;br /&gt;
  for (const [key, extractorFunction] of Object.entries(&lt;br /&gt;
    dataExtractionMapping&lt;br /&gt;
  )) {&lt;br /&gt;
    if (&lt;br /&gt;
      filterData.range.hasOwnProperty(key) ||&lt;br /&gt;
      filterData.checkbox.hasOwnProperty(key)&lt;br /&gt;
    ) {&lt;br /&gt;
      activeExtractors.push(extractorFunction);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  const cardsData = [];&lt;br /&gt;
&lt;br /&gt;
  for (let cardIndex = 0; cardIndex &amp;lt; cards.length; cardIndex++) {&lt;br /&gt;
    const card = cards[cardIndex];&lt;br /&gt;
    const cardData = {};&lt;br /&gt;
&lt;br /&gt;
    for (const extractor of activeExtractors) {&lt;br /&gt;
      extractor(card, cardData);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    cardsData.push(cardData);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return cardsData;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterInitialization(filterForm) {&lt;br /&gt;
  const filterData = {&lt;br /&gt;
    form: filterForm,&lt;br /&gt;
    filters: { filterName: &amp;quot;&amp;quot;, filter: {}, rangeFilter: {} },&lt;br /&gt;
    range: {},&lt;br /&gt;
    checkbox: {},&lt;br /&gt;
    reverse: false,&lt;br /&gt;
  };&lt;br /&gt;
  const filters = filterForm.querySelectorAll(&amp;quot;[data-filter]&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  filters.forEach((filter) =&amp;gt; fillData(filter, filterData));&lt;br /&gt;
&lt;br /&gt;
  return filterData;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function displayCounterValue(checkbox) {&lt;br /&gt;
  for (let filterCategory in checkbox) {&lt;br /&gt;
    const category = checkbox[filterCategory];&lt;br /&gt;
&lt;br /&gt;
    for (let filterValue in category) {&lt;br /&gt;
      const valueData = category[filterValue];&lt;br /&gt;
&lt;br /&gt;
      valueData.span.textContent = &amp;quot; (&amp;quot; + valueData.value + &amp;quot;)&amp;quot;;&lt;br /&gt;
      valueData.value = 0;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateCounter(cardData, checkbox, filterCategory) {&lt;br /&gt;
  cardData[filterCategory].split(&amp;quot; &amp;quot;).forEach((cardValue) =&amp;gt; {&lt;br /&gt;
    checkbox[filterCategory][cardValue].value += 1;&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isObjectValuesInRangeFilter(parameters, rangeFilter) {&lt;br /&gt;
  return Object.entries(rangeFilter).every(&lt;br /&gt;
    ([property, { min, max }]) =&amp;gt;&lt;br /&gt;
      parameters[property] &amp;gt;= min &amp;amp;&amp;amp; parameters[property] &amp;lt;= max&lt;br /&gt;
  );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterByName(parameters, filterName) {&lt;br /&gt;
  if (filterName) {&lt;br /&gt;
    return parameters.name.includes(filterName);&lt;br /&gt;
  }&lt;br /&gt;
  return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isObjectValuesInFilter(parameters, filter) {&lt;br /&gt;
  return Object.entries(filter).every(([property, values]) =&amp;gt;&lt;br /&gt;
    parameters[property].split(&amp;quot; &amp;quot;).some((value) =&amp;gt; values.includes(value))&lt;br /&gt;
  );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isObjectValuesInFilters(parameters, filter, rangeFilter, filterName) {&lt;br /&gt;
  return (&lt;br /&gt;
    isObjectValuesInFilter(parameters, filter) &amp;amp;&amp;amp;&lt;br /&gt;
    filterByName(parameters, filterName) &amp;amp;&amp;amp;&lt;br /&gt;
    isObjectValuesInRangeFilter(parameters, rangeFilter)&lt;br /&gt;
  );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterCards(cardsContainer, filterData, cardsData) {&lt;br /&gt;
  const { filters, checkbox } = filterData;&lt;br /&gt;
  const { filter, rangeFilter, filterName } = filters;&lt;br /&gt;
&lt;br /&gt;
  if (filterData.reverse) {&lt;br /&gt;
    for (&lt;br /&gt;
      let reverseIndex = 1;&lt;br /&gt;
      reverseIndex &amp;lt; cardsData.length;&lt;br /&gt;
      reverseIndex++&lt;br /&gt;
    ) {&lt;br /&gt;
      cardsContainer.insertBefore(&lt;br /&gt;
        cardsData[reverseIndex].card,&lt;br /&gt;
        cardsContainer.firstChild&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
    cardsData.reverse();&lt;br /&gt;
    filterData.reverse = false;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (let cardIndex = 0; cardIndex &amp;lt; cardsData.length; cardIndex++) {&lt;br /&gt;
    const cardData = cardsData[cardIndex];&lt;br /&gt;
&lt;br /&gt;
    if (isObjectValuesInFilters(cardData, filter, rangeFilter, filterName)) {&lt;br /&gt;
      showElement(cardData.card);&lt;br /&gt;
      for (let filterCategory in checkbox) {&lt;br /&gt;
        updateCounter(cardData, checkbox, filterCategory);&lt;br /&gt;
      }&lt;br /&gt;
    } else {&lt;br /&gt;
      hideElement(cardData.card);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  displayCounterValue(checkbox);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleCheckbox(target, filter) {&lt;br /&gt;
  const { filter: category, value } = target.dataset;&lt;br /&gt;
&lt;br /&gt;
  if (target.checked) {&lt;br /&gt;
    filter[category] = filter[category] || [];&lt;br /&gt;
    filter[category].push(value);&lt;br /&gt;
  } else {&lt;br /&gt;
    const index = filter[category].indexOf(value);&lt;br /&gt;
    if (index !== -1) {&lt;br /&gt;
      filter[category].splice(index, 1);&lt;br /&gt;
    }&lt;br /&gt;
    if (!filter[category].length) {&lt;br /&gt;
      delete filter[category];&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleNumberType(target, rangeFilter, range) {&lt;br /&gt;
  const { filter: category, value: extremum } = target.dataset;&lt;br /&gt;
  const currentValue = Number(target.value);&lt;br /&gt;
  const initialRange = range[category].init;&lt;br /&gt;
&lt;br /&gt;
  if (rangeFilter[category]) {&lt;br /&gt;
    rangeFilter[category][extremum] = currentValue;&lt;br /&gt;
  } else {&lt;br /&gt;
    rangeFilter[category] = {&lt;br /&gt;
      min: initialRange.min,&lt;br /&gt;
      max: initialRange.max,&lt;br /&gt;
    };&lt;br /&gt;
    rangeFilter[category][extremum] = currentValue;&lt;br /&gt;
  }&lt;br /&gt;
  if (&lt;br /&gt;
    rangeFilter[category].max === initialRange.max &amp;amp;&amp;amp;&lt;br /&gt;
    rangeFilter[category].min === initialRange.min&lt;br /&gt;
  ) {&lt;br /&gt;
    delete rangeFilter[category];&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleFormEvents(cardsContainer, filterForm, filterData, cardsData) {&lt;br /&gt;
  const { filters, range } = filterData;&lt;br /&gt;
  let debounceTimer;&lt;br /&gt;
&lt;br /&gt;
  filterForm.addEventListener(&amp;quot;submit&amp;quot;, function (event) {&lt;br /&gt;
    event.preventDefault();&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  filterForm.addEventListener(&amp;quot;change&amp;quot;, updateFilter);&lt;br /&gt;
&lt;br /&gt;
  filterForm.addEventListener(&amp;quot;input&amp;quot;, function (event) {&lt;br /&gt;
    clearTimeout(debounceTimer);&lt;br /&gt;
    debounceTimer = setTimeout(() =&amp;gt; {&lt;br /&gt;
      if (event.target.id === &amp;quot;filter-name&amp;quot;) {&lt;br /&gt;
        updateFilter(event, true);&lt;br /&gt;
      }&lt;br /&gt;
    }, 500);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  function updateFilter(event, filterByName = false) {&lt;br /&gt;
    const target = event.target;&lt;br /&gt;
    const targetType = target.type;&lt;br /&gt;
&lt;br /&gt;
    if (filterByName) {&lt;br /&gt;
      filters.filterName = toNormalForm(target.value);&lt;br /&gt;
    } else if (targetType === &amp;quot;checkbox&amp;quot;) {&lt;br /&gt;
      handleCheckbox(target, filters.filter);&lt;br /&gt;
    } else if (targetType === &amp;quot;number&amp;quot;) {&lt;br /&gt;
      handleNumberType(target, filters.rangeFilter, range);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    filterCards(cardsContainer, filterData, cardsData);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function processUrlParameter(filterName, filterData, key, value) {&lt;br /&gt;
  const { filters } = filterData;&lt;br /&gt;
&lt;br /&gt;
  if (key === &amp;quot;name&amp;quot;) {&lt;br /&gt;
    filterName.value = toNormalForm(value);&lt;br /&gt;
    filters.filterName = value;&lt;br /&gt;
  } else if (Object.keys(filterData.checkbox).indexOf(key) !== -1) {&lt;br /&gt;
    const checkboxElement = document.getElementById(key + &amp;quot;-&amp;quot; + value);&lt;br /&gt;
&lt;br /&gt;
    if (!checkboxElement) return;&lt;br /&gt;
&lt;br /&gt;
    checkboxElement.checked = true;&lt;br /&gt;
    filters.filter[key] = filters.filter[key] || [];&lt;br /&gt;
    filters.filter[key].push(value);&lt;br /&gt;
  } else if (key === &amp;quot;reverse&amp;quot;) {&lt;br /&gt;
    if (value === &amp;quot;1&amp;quot;) {&lt;br /&gt;
      filterData.reverse = true;&lt;br /&gt;
      const reverseElement = document.getElementById(&amp;quot;filter-reverse&amp;quot;);&lt;br /&gt;
      if (reverseElement) {&lt;br /&gt;
        reverseElement.checked = true;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    const [splitKey, extremum] = key.split(&amp;quot;-&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (Object.keys(filterData.range).indexOf(splitKey) !== -1) {&lt;br /&gt;
      const rangeElement = document.getElementById(key);&lt;br /&gt;
&lt;br /&gt;
      if (!rangeElement) return;&lt;br /&gt;
&lt;br /&gt;
      rangeElement.value = value;&lt;br /&gt;
&lt;br /&gt;
      const rangeData = filterData.range[splitKey];&lt;br /&gt;
      const rangeFilter = filters.rangeFilter;&lt;br /&gt;
&lt;br /&gt;
      if (rangeFilter[splitKey]) {&lt;br /&gt;
        rangeFilter[splitKey][extremum] = value;&lt;br /&gt;
      } else {&lt;br /&gt;
        rangeFilter[splitKey] = {&lt;br /&gt;
          min: rangeData.init.min,&lt;br /&gt;
          max: rangeData.init.max,&lt;br /&gt;
        };&lt;br /&gt;
        rangeFilter[splitKey][extremum] = value;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterWithUrl(filterName, filterData) {&lt;br /&gt;
  const url = new URL(window.location.href);&lt;br /&gt;
  const { hash, search } = url;&lt;br /&gt;
  let useParams = true;&lt;br /&gt;
&lt;br /&gt;
  if (hash) {&lt;br /&gt;
    const start = &amp;quot;.3F&amp;quot;;&lt;br /&gt;
    const equal = &amp;quot;.3D&amp;quot;;&lt;br /&gt;
    const and = &amp;quot;.26&amp;quot;;&lt;br /&gt;
    const startParametersIndex = hash.indexOf(start);&lt;br /&gt;
&lt;br /&gt;
    if (startParametersIndex !== -1) {&lt;br /&gt;
      const parameters = hash.slice(startParametersIndex + start.length);&lt;br /&gt;
&lt;br /&gt;
      parameters.split(and).forEach(function (keyValue) {&lt;br /&gt;
        const [key, value] = keyValue.split(equal);&lt;br /&gt;
        processUrlParameter(filterName, filterData, key, value);&lt;br /&gt;
      });&lt;br /&gt;
&lt;br /&gt;
      useParams = false;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (useParams) {&lt;br /&gt;
    const URLparams = new URLSearchParams(search);&lt;br /&gt;
&lt;br /&gt;
    for (const [key, value] of URLparams.entries()) {&lt;br /&gt;
      processUrlParameter(filterName, filterData, key, value);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function main_filter() {&lt;br /&gt;
  const filterForm = document.getElementById(&amp;quot;filter-form&amp;quot;);&lt;br /&gt;
  const filterName = document.getElementById(&amp;quot;filter-name&amp;quot;);&lt;br /&gt;
  const cardsContainer = document.getElementById(&amp;quot;cards-container&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  const dataExtractionMapping = {&lt;br /&gt;
    level: extractLevelData,&lt;br /&gt;
    elem: extractElementData,&lt;br /&gt;
    type: extractTypeData,&lt;br /&gt;
    damage: extractDamageData,&lt;br /&gt;
    loc: extractLocData&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  const filterData = filterInitialization(filterForm);&lt;br /&gt;
  const cardsData = getCardsData(&lt;br /&gt;
    cardsContainer,&lt;br /&gt;
    filterData,&lt;br /&gt;
    dataExtractionMapping&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  observeLanguageChange(filterName, cardsData);&lt;br /&gt;
  openFilter();&lt;br /&gt;
  filterWithUrl(filterName, filterData);&lt;br /&gt;
  filterCards(cardsContainer, filterData, cardsData);&lt;br /&gt;
  handleFormEvents(cardsContainer, filterForm, filterData, cardsData);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
main_filter();&lt;/div&gt;</summary>
		<author><name>Dexter</name></author>
		
	</entry>
	<entry>
		<id>https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Script/Calculator.js&amp;diff=105849</id>
		<title>MediaWiki:Script/Calculator.js</title>
		<link rel="alternate" type="text/html" href="https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Script/Calculator.js&amp;diff=105849"/>
		<updated>2024-12-17T18:20:57Z</updated>

		<summary type="html">&lt;p&gt;Dexter : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;function removeAccent(str) {&lt;br /&gt;
  return str.normalize(&amp;quot;NFD&amp;quot;).replace(/[\u0300-\u036f]/g, &amp;quot;&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function pseudoFormat(str) {&lt;br /&gt;
  return removeAccent(str).replace(/[^A-Za-z0-9 \(\)\+_-]+/g, &amp;quot;&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isValueInArray(value, array) {&lt;br /&gt;
  return array.indexOf(value) !== -1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function copyObject(object) {&lt;br /&gt;
  var copy = {};&lt;br /&gt;
  for (var key in object) {&lt;br /&gt;
    copy[key] = object[key];&lt;br /&gt;
  }&lt;br /&gt;
  return copy;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function compareNumbers(a, b) {&lt;br /&gt;
  return b - a;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isChecked(attribute) {&lt;br /&gt;
  return attribute === &amp;quot;on&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function floorMultiplication(firstFactor, secondFactor) {&lt;br /&gt;
  return Math.floor((firstFactor * secondFactor).toFixed(8));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function truncateNumber(number, precision) {&lt;br /&gt;
  return Math.floor(number * 10 ** precision) / 10 ** precision;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addKeyValue(object, key, value) {&lt;br /&gt;
  if (object.hasOwnProperty(key)) {&lt;br /&gt;
    object[key] += value;&lt;br /&gt;
  } else {&lt;br /&gt;
    object[key] = value;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function editTableResultRow(row, valuesToDisplay, numberFormat) {&lt;br /&gt;
  row.innerHTML = &amp;quot;&amp;quot;;&lt;br /&gt;
  for (var index = 0; index &amp;lt; valuesToDisplay.length; index++) {&lt;br /&gt;
    var cell = row.insertCell();&lt;br /&gt;
    var textContent;&lt;br /&gt;
&lt;br /&gt;
    if (index &amp;gt;= 3) {&lt;br /&gt;
      textContent = numberFormat.format(valuesToDisplay[index]);&lt;br /&gt;
    } else {&lt;br /&gt;
      textContent = valuesToDisplay[index];&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    cell.textContent = textContent;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return row;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addRowToTableResultHistory(&lt;br /&gt;
  tableResultHistory,&lt;br /&gt;
  valuesToDisplay,&lt;br /&gt;
  deleteFightTemplate,&lt;br /&gt;
  numberFormat&lt;br /&gt;
) {&lt;br /&gt;
  var row = tableResultHistory.insertRow();&lt;br /&gt;
  editTableResultRow(row, valuesToDisplay, numberFormat);&lt;br /&gt;
  var cell = row.insertCell();&lt;br /&gt;
  cell.appendChild(deleteFightTemplate.cloneNode(true));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcMeanDamages(damagesWeightedByType, totalCardinal) {&lt;br /&gt;
  var sumDamages = 0;&lt;br /&gt;
&lt;br /&gt;
  for (var damagesTypeName in damagesWeightedByType) {&lt;br /&gt;
    if (damagesTypeName === &amp;quot;miss&amp;quot;) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var damagesWeighted = damagesWeightedByType[damagesTypeName];&lt;br /&gt;
&lt;br /&gt;
    for (var damages in damagesWeighted) {&lt;br /&gt;
      sumDamages += damages * damagesWeighted[damages];&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return sumDamages / totalCardinal;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function prepareDamagesData(&lt;br /&gt;
  damagesWeightedByType,&lt;br /&gt;
  possibleDamagesCountTemp,&lt;br /&gt;
  totalCardinal&lt;br /&gt;
) {&lt;br /&gt;
  var minDamages = Infinity;&lt;br /&gt;
  var maxDamages = 0;&lt;br /&gt;
  var scatterDataByType = {};&lt;br /&gt;
  var sumDamages = 0;&lt;br /&gt;
  var possibleDamagesCount = 0;&lt;br /&gt;
  var uniqueDamagesCount = 0;&lt;br /&gt;
&lt;br /&gt;
  for (var damagesTypeName in damagesWeightedByType) {&lt;br /&gt;
    if (damagesTypeName === &amp;quot;miss&amp;quot;) {&lt;br /&gt;
      scatterDataByType.miss = damagesWeightedByType.miss;&lt;br /&gt;
      possibleDamagesCount++;&lt;br /&gt;
      uniqueDamagesCount++;&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var firstIteration = true;&lt;br /&gt;
    var damagesWeighted = damagesWeightedByType[damagesTypeName];&lt;br /&gt;
    var scatterData = [];&lt;br /&gt;
    scatterDataByType[damagesTypeName] = scatterData;&lt;br /&gt;
&lt;br /&gt;
    for (var damages in damagesWeighted) {&lt;br /&gt;
      damages = +damages;&lt;br /&gt;
&lt;br /&gt;
      if (firstIteration) {&lt;br /&gt;
        if (damages &amp;lt; minDamages) {&lt;br /&gt;
          minDamages = damages;&lt;br /&gt;
        }&lt;br /&gt;
        firstIteration = false;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      var weight = damagesWeighted[damages];&lt;br /&gt;
      var probability = weight / totalCardinal;&lt;br /&gt;
&lt;br /&gt;
      sumDamages += damages * weight;&lt;br /&gt;
      damagesWeighted[damages] = probability;&lt;br /&gt;
      scatterData.push({ x: damages, y: probability });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var scatterDataLength = scatterData.length;&lt;br /&gt;
&lt;br /&gt;
    possibleDamagesCount += possibleDamagesCountTemp;&lt;br /&gt;
    uniqueDamagesCount += scatterDataLength;&lt;br /&gt;
&lt;br /&gt;
    if (damages &amp;gt; maxDamages) {&lt;br /&gt;
      maxDamages = damages;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (minDamages === Infinity) {&lt;br /&gt;
    minDamages = 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return [&lt;br /&gt;
    sumDamages / totalCardinal,&lt;br /&gt;
    minDamages,&lt;br /&gt;
    maxDamages,&lt;br /&gt;
    scatterDataByType,&lt;br /&gt;
    possibleDamagesCount,&lt;br /&gt;
    uniqueDamagesCount,&lt;br /&gt;
  ];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function aggregateDamages(scatterData, maxPoints) {&lt;br /&gt;
  var dataLength = scatterData.length;&lt;br /&gt;
  var remainingData = dataLength;&lt;br /&gt;
  var aggregateScatterData = [];&lt;br /&gt;
&lt;br /&gt;
  for (var groupIndex = 0; groupIndex &amp;lt; maxPoints; groupIndex++) {&lt;br /&gt;
    var groupLength = Math.floor(remainingData / (maxPoints - groupIndex));&lt;br /&gt;
    var startIndex = dataLength - remainingData;&lt;br /&gt;
    var aggregateDamages = 0;&lt;br /&gt;
    var aggregateProbability = 0;&lt;br /&gt;
&lt;br /&gt;
    for (var index = startIndex; index &amp;lt; startIndex + groupLength; index++) {&lt;br /&gt;
      var { x: damages, y: probability } = scatterData[index];&lt;br /&gt;
      aggregateDamages += damages * probability;&lt;br /&gt;
      aggregateProbability += probability;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    aggregateScatterData.push({&lt;br /&gt;
      x: aggregateDamages / aggregateProbability,&lt;br /&gt;
      y: aggregateProbability,&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    remainingData -= groupLength;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return aggregateScatterData;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addToDamagesChart(&lt;br /&gt;
  scatterDataByType,&lt;br /&gt;
  damagesChart,&lt;br /&gt;
  isReducePointsChecked&lt;br /&gt;
) {&lt;br /&gt;
  var { chart, datasetsStyle, maxPoints, reduceChartPointsContainer } =&lt;br /&gt;
    damagesChart;&lt;br /&gt;
  var isFirstDataset = true;&lt;br /&gt;
  var datasets = chart.data.datasets;&lt;br /&gt;
&lt;br /&gt;
  datasets.length = 0;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; datasetsStyle.length; index++) {&lt;br /&gt;
    var dataset = copyObject(datasetsStyle[index]);&lt;br /&gt;
&lt;br /&gt;
    if (!scatterDataByType.hasOwnProperty(dataset.name)) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var scatterData = scatterDataByType[dataset.name];&lt;br /&gt;
    var canBeReduced = scatterData.length &amp;gt; 2 * maxPoints;&lt;br /&gt;
&lt;br /&gt;
    dataset.hidden = !isFirstDataset;&lt;br /&gt;
    dataset.canBeReduced = canBeReduced;&lt;br /&gt;
&lt;br /&gt;
    if (canBeReduced &amp;amp;&amp;amp; isReducePointsChecked) {&lt;br /&gt;
      dataset.data = aggregateDamages(scatterData, maxPoints);&lt;br /&gt;
    } else {&lt;br /&gt;
      dataset.data = scatterData;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isFirstDataset) {&lt;br /&gt;
      isFirstDataset = false;&lt;br /&gt;
&lt;br /&gt;
      if (canBeReduced) {&lt;br /&gt;
        showElement(reduceChartPointsContainer);&lt;br /&gt;
&lt;br /&gt;
        if (!isReducePointsChecked) {&lt;br /&gt;
          handleChartAnimations(chart, false);&lt;br /&gt;
        }&lt;br /&gt;
      } else {&lt;br /&gt;
        hideElement(reduceChartPointsContainer);&lt;br /&gt;
        handleChartAnimations(chart, true);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    datasets.push(dataset);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  chart.data.missPercentage = scatterDataByType.miss;&lt;br /&gt;
  chart.update();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addToBonusVariationChart(&lt;br /&gt;
  damagesByBonus,&lt;br /&gt;
  augmentationByBonus,&lt;br /&gt;
  xLabel,&lt;br /&gt;
  chart&lt;br /&gt;
) {&lt;br /&gt;
  chart.data.datasets[0].data = damagesByBonus;&lt;br /&gt;
  chart.data.datasets[1].data = augmentationByBonus;&lt;br /&gt;
  chart.options.scales.x.title.text = xLabel;&lt;br /&gt;
  chart.update();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleChartAnimations(chart, addAnimations) {&lt;br /&gt;
  chart.options.animation = addAnimations;&lt;br /&gt;
  chart.options.animations.colors = addAnimations;&lt;br /&gt;
  chart.options.animations.x = addAnimations;&lt;br /&gt;
  chart.options.transitions.active.animation.duration = addAnimations * 1000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateDamagesChartDescription(&lt;br /&gt;
  uniqueDamagesCounters,&lt;br /&gt;
  uniqueDamagesCount,&lt;br /&gt;
  formatNumber&lt;br /&gt;
) {&lt;br /&gt;
  uniqueDamagesCounters.forEach(function (element) {&lt;br /&gt;
    if (uniqueDamagesCount &amp;lt;= 1) {&lt;br /&gt;
      hideElement(element.parentElement);&lt;br /&gt;
    } else {&lt;br /&gt;
      showElement(element.parentElement);&lt;br /&gt;
      element.textContent = formatNumber.format(uniqueDamagesCount);&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getMonsterName(monsterVnum) {&lt;br /&gt;
  var monsterAttributes = monsterData[monsterVnum];&lt;br /&gt;
  return monsterAttributes[monsterAttributes.length - 1];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterClass(selectedRace, classChoice, selectValueIsChanged = false) {&lt;br /&gt;
  showElement(classChoice.parentElement);&lt;br /&gt;
&lt;br /&gt;
  for (var option of classChoice.options) {&lt;br /&gt;
    if (option.getAttribute(&amp;quot;data-race&amp;quot;) === selectedRace) {&lt;br /&gt;
      if (!selectValueIsChanged) {&lt;br /&gt;
        classChoice.value = option.value;&lt;br /&gt;
        selectValueIsChanged = true;&lt;br /&gt;
      }&lt;br /&gt;
      showElement(option);&lt;br /&gt;
    } else {&lt;br /&gt;
      hideElement(option);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  if (selectedRace == &amp;quot;lycan&amp;quot;) {&lt;br /&gt;
    hideElement(classChoice.parentElement);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterWeapon(&lt;br /&gt;
  selectedRace,&lt;br /&gt;
  weaponElement,&lt;br /&gt;
  weaponCategory,&lt;br /&gt;
  allowedWeaponsPerRace,&lt;br /&gt;
  selectValueIsChanged = false&lt;br /&gt;
) {&lt;br /&gt;
  var allowedWeapons = allowedWeaponsPerRace[selectedRace];&lt;br /&gt;
&lt;br /&gt;
  if (!selectValueIsChanged) {&lt;br /&gt;
    var weaponType = createWeapon(weaponElement.value).type;&lt;br /&gt;
&lt;br /&gt;
    if (!isValueInArray(weaponType, allowedWeapons)) {&lt;br /&gt;
      weaponElement.value = 0;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var children = weaponCategory.children;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; children.length; index++) {&lt;br /&gt;
    var child = children[index];&lt;br /&gt;
&lt;br /&gt;
    if (isValueInArray(index, allowedWeapons)) {&lt;br /&gt;
      showElement(child);&lt;br /&gt;
    } else {&lt;br /&gt;
      hideElement(child);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSelectedWeapon(weaponCategory) {&lt;br /&gt;
  return weaponCategory.querySelector(&amp;quot;input[type='radio']:checked&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleWeaponDisplay(weaponCategory, weaponDisplay, weaponVnum, newWeapon) {&lt;br /&gt;
  var newWeapon = newWeapon || getSelectedWeapon(weaponCategory);&lt;br /&gt;
&lt;br /&gt;
  var newImage = newWeapon.nextElementSibling;&lt;br /&gt;
  var newText = document.createElement(&amp;quot;span&amp;quot;);&lt;br /&gt;
  var oldImage = weaponDisplay.firstChild;&lt;br /&gt;
  var oldText = oldImage.nextElementSibling;&lt;br /&gt;
  var weaponName = newImage.nextElementSibling.dataset.o;&lt;br /&gt;
&lt;br /&gt;
  if (weaponVnum == 0) {&lt;br /&gt;
    newText.textContent = &amp;quot; &amp;quot; + weaponName + &amp;quot; &amp;quot;;&lt;br /&gt;
  } else {&lt;br /&gt;
    var weaponLink = document.createElement(&amp;quot;a&amp;quot;);&lt;br /&gt;
    weaponLink.href = mw.util.getUrl(weaponName);&lt;br /&gt;
    weaponLink.title = weaponName;&lt;br /&gt;
    weaponLink.textContent = weaponName;&lt;br /&gt;
&lt;br /&gt;
    newText.appendChild(document.createTextNode(&amp;quot; &amp;quot;));&lt;br /&gt;
    newText.appendChild(weaponLink);&lt;br /&gt;
    newText.appendChild(document.createTextNode(&amp;quot; &amp;quot;));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  weaponDisplay.replaceChild(newImage.cloneNode(), oldImage);&lt;br /&gt;
  weaponDisplay.replaceChild(newText, oldText);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterUpgrade(&lt;br /&gt;
  weaponUpgrade,&lt;br /&gt;
  weaponVnum,&lt;br /&gt;
  randomAttackValue,&lt;br /&gt;
  randomMagicAttackValue,&lt;br /&gt;
) {&lt;br /&gt;
  var weapon = createWeapon(weaponVnum);&lt;br /&gt;
  var currentUpgrade = Number(weaponUpgrade.value);&lt;br /&gt;
&lt;br /&gt;
  if (weapon.isSerpent) {&lt;br /&gt;
    showElement(randomAttackValue);&lt;br /&gt;
&lt;br /&gt;
    if (weapon.isMagic) {&lt;br /&gt;
      showElement(randomMagicAttackValue);&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    hideElement(randomAttackValue);&lt;br /&gt;
    hideElement(randomMagicAttackValue);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (weapon.maxUpgrade &amp;lt; 1) {&lt;br /&gt;
    hideElement(weaponUpgrade.parentElement);&lt;br /&gt;
  } else {&lt;br /&gt;
    showElement(weaponUpgrade.parentElement);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  weaponUpgrade.innerHTML = &amp;quot;&amp;quot;;&lt;br /&gt;
  var lastOption;&lt;br /&gt;
&lt;br /&gt;
  for (var upgrade = 0; upgrade &amp;lt;= weapon.maxUpgrade; upgrade++) {&lt;br /&gt;
    var option = document.createElement(&amp;quot;option&amp;quot;);&lt;br /&gt;
    option.value = upgrade;&lt;br /&gt;
    option.textContent = &amp;quot;+&amp;quot; + upgrade;&lt;br /&gt;
    weaponUpgrade.appendChild(option);&lt;br /&gt;
&lt;br /&gt;
    if (upgrade === currentUpgrade) {&lt;br /&gt;
      option.selected = true;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    lastOption = option;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if ((currentUpgrade &amp;gt; weapon.maxUpgrade || !currentUpgrade) &amp;amp;&amp;amp; lastOption) {&lt;br /&gt;
    lastOption.selected = true;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterCheckbox(checkbox, element) {&lt;br /&gt;
  if (checkbox.checked) {&lt;br /&gt;
    showElement(element);&lt;br /&gt;
  } else {&lt;br /&gt;
    hideElement(element);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterSkills(selectedClass, skillElementsToFilter) {&lt;br /&gt;
  for (var element of skillElementsToFilter) {&lt;br /&gt;
    if (isValueInArray(selectedClass, element.dataset.class)) {&lt;br /&gt;
      showElement(element);&lt;br /&gt;
    } else {&lt;br /&gt;
      hideElement(element);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterAttackTypeSelection(attacker, attackTypeSelection) {&lt;br /&gt;
  var attackerClass = attacker.class;&lt;br /&gt;
  var selectedOption =&lt;br /&gt;
    attackTypeSelection.options[attackTypeSelection.selectedIndex];&lt;br /&gt;
  var attackerIsNotPolymorph = !isPolymorph(attacker);&lt;br /&gt;
&lt;br /&gt;
  for (var index = 2; index &amp;lt; attackTypeSelection.options.length; index++) {&lt;br /&gt;
    var option = attackTypeSelection.options[index];&lt;br /&gt;
    var optionClass = option.dataset.class;&lt;br /&gt;
    var optionValue = option.value;&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      attackerIsNotPolymorph &amp;amp;&amp;amp;&lt;br /&gt;
      attacker[optionValue] &amp;amp;&amp;amp;&lt;br /&gt;
      (attackerClass === optionClass ||&lt;br /&gt;
        (optionValue.startsWith(&amp;quot;horseSkill&amp;quot;) &amp;amp;&amp;amp;&lt;br /&gt;
          isRiding(attacker) &amp;amp;&amp;amp;&lt;br /&gt;
          (!optionClass || isValueInArray(attackerClass, optionClass))))&lt;br /&gt;
    ) {&lt;br /&gt;
      showElement(option);&lt;br /&gt;
    } else {&lt;br /&gt;
      hideElement(option);&lt;br /&gt;
&lt;br /&gt;
      if (selectedOption === option) {&lt;br /&gt;
        attackTypeSelection.selectedIndex = 0;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterAttackTypeSelectionMonster(attackTypeSelection) {&lt;br /&gt;
  for (var index = 2; index &amp;lt; attackTypeSelection.options.length; index++) {&lt;br /&gt;
    hideElement(attackTypeSelection.options[index]);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (attackTypeSelection.selectedIndex !== 1) {&lt;br /&gt;
    attackTypeSelection.selectedIndex = 0;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterForm(characters, battle) {&lt;br /&gt;
  var characterCreation = characters.characterCreation;&lt;br /&gt;
  var allowedWeaponsPerRace = battle.constants.allowedWeaponsPerRace;&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;change&amp;quot;, function (event) {&lt;br /&gt;
    var target = event.target;&lt;br /&gt;
    var targetName = target.name;&lt;br /&gt;
&lt;br /&gt;
    switch (targetName) {&lt;br /&gt;
      case &amp;quot;race&amp;quot;:&lt;br /&gt;
        var selectedRace = target.value;&lt;br /&gt;
        var classChoice = characterCreation.class;&lt;br /&gt;
        var weaponElement = characterCreation.weapon;&lt;br /&gt;
&lt;br /&gt;
        filterClass(selectedRace, classChoice);&lt;br /&gt;
        filterWeapon(&lt;br /&gt;
          selectedRace,&lt;br /&gt;
          weaponElement,&lt;br /&gt;
          characters.weaponCategory,&lt;br /&gt;
          allowedWeaponsPerRace&lt;br /&gt;
        );&lt;br /&gt;
        handleWeaponDisplay(&lt;br /&gt;
          characters.weaponCategory,&lt;br /&gt;
          characters.weaponDisplay,&lt;br /&gt;
          weaponElement.value&lt;br /&gt;
        );&lt;br /&gt;
        filterUpgrade(&lt;br /&gt;
          characterCreation.weaponUpgrade,&lt;br /&gt;
          weaponElement.value,&lt;br /&gt;
          characters.randomAttackValue,&lt;br /&gt;
          characters.randomMagicAttackValue,&lt;br /&gt;
        );&lt;br /&gt;
        filterSkills(classChoice.value, characters.skillElementsToFilter);&lt;br /&gt;
&lt;br /&gt;
        if (characterCreation.name.value === battle.attackerSelection.value) {&lt;br /&gt;
          battle.resetAttackType = true;&lt;br /&gt;
        }&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;class&amp;quot;:&lt;br /&gt;
        filterSkills(target.value, characters.skillElementsToFilter);&lt;br /&gt;
&lt;br /&gt;
        if (characterCreation.name.value === battle.attackerSelection.value) {&lt;br /&gt;
          battle.resetAttackType = true;&lt;br /&gt;
        }&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;weapon&amp;quot;:&lt;br /&gt;
        var weaponElement = characterCreation.weapon;&lt;br /&gt;
&lt;br /&gt;
        handleWeaponDisplay(&lt;br /&gt;
          characters.weaponCategory,&lt;br /&gt;
          characters.weaponDisplay,&lt;br /&gt;
          weaponElement.value,&lt;br /&gt;
          target&lt;br /&gt;
        );&lt;br /&gt;
        filterUpgrade(&lt;br /&gt;
          characterCreation.weaponUpgrade,&lt;br /&gt;
          target.value,&lt;br /&gt;
          characters.randomAttackValue,&lt;br /&gt;
          characters.randomMagicAttackValue&lt;br /&gt;
        );&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;isPolymorph&amp;quot;:&lt;br /&gt;
        filterCheckbox(&lt;br /&gt;
          target,&lt;br /&gt;
          characterCreation.polymorphMonster.parentElement&lt;br /&gt;
        );&lt;br /&gt;
        if (characterCreation.name.value === battle.attackerSelection.value) {&lt;br /&gt;
          battle.resetAttackType = true;&lt;br /&gt;
        }&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;lowRank&amp;quot;:&lt;br /&gt;
        filterCheckbox(target, characterCreation.playerRank.parentElement);&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;isBlessed&amp;quot;:&lt;br /&gt;
        filterCheckbox(target, characters.blessingCreation);&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;onYohara&amp;quot;:&lt;br /&gt;
        filterCheckbox(target, characters.yoharaCreation);&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;isMarried&amp;quot;:&lt;br /&gt;
        filterCheckbox(target, characters.marriageCreation);&lt;br /&gt;
        break;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      targetName.startsWith(&amp;quot;attackSkill&amp;quot;) ||&lt;br /&gt;
      targetName.startsWith(&amp;quot;horseSkill&amp;quot;)&lt;br /&gt;
    ) {&lt;br /&gt;
      battle.resetAttackType = true;&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addUniquePseudo(characterDataObject, savedCharactersPseudo) {&lt;br /&gt;
  var characterPseudo = String(characterDataObject.name);&lt;br /&gt;
  var originalPseudo = characterPseudo;&lt;br /&gt;
  var count = 0;&lt;br /&gt;
&lt;br /&gt;
  var regex = /(.*)(\d)$/;&lt;br /&gt;
  var match = characterPseudo.match(regex);&lt;br /&gt;
&lt;br /&gt;
  if (match) {&lt;br /&gt;
    originalPseudo = match[1];&lt;br /&gt;
    count = match[2];&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  while (isValueInArray(characterPseudo, savedCharactersPseudo)) {&lt;br /&gt;
    characterPseudo = originalPseudo + count;&lt;br /&gt;
    count++;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  characterDataObject.name = characterPseudo;&lt;br /&gt;
  return [characterDataObject, characterPseudo];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function convertToNumber(value) {&lt;br /&gt;
  var valueNumber = Number(value);&lt;br /&gt;
  return isNaN(valueNumber) ? value : valueNumber;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getLocalStorageValue(key, defaultValue) {&lt;br /&gt;
  var storedValue = localStorage.getItem(key);&lt;br /&gt;
&lt;br /&gt;
  if (storedValue) {&lt;br /&gt;
    return JSON.parse(storedValue);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return defaultValue;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSavedCharacters() {&lt;br /&gt;
  return getLocalStorageValue(&amp;quot;savedCharactersCalculator&amp;quot;, {});&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSavedMonsters() {&lt;br /&gt;
  var savedMonsters = getLocalStorageValue(&amp;quot;savedMonstersCalculator&amp;quot;, {});&lt;br /&gt;
&lt;br /&gt;
  if (Array.isArray(savedMonsters)) {&lt;br /&gt;
    return {};&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var filteredMonsters = {};&lt;br /&gt;
&lt;br /&gt;
  for (var vnum in savedMonsters) {&lt;br /&gt;
    if (String(Number(vnum)) === vnum) {&lt;br /&gt;
      filteredMonsters[vnum] = savedMonsters[vnum];&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return filteredMonsters;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSavedFights() {&lt;br /&gt;
  return getLocalStorageValue(&amp;quot;savedFightsCalculator&amp;quot;, []);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveToLocalStorage(key, value) {&lt;br /&gt;
  localStorage.setItem(key, JSON.stringify(value));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateSavedCharacters(savedCharacters) {&lt;br /&gt;
  saveToLocalStorage(&amp;quot;savedCharactersCalculator&amp;quot;, savedCharacters);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateSavedMonsters(savedMonsters) {&lt;br /&gt;
  saveToLocalStorage(&amp;quot;savedMonstersCalculator&amp;quot;, savedMonsters);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateSavedFights(savedFights) {&lt;br /&gt;
  saveToLocalStorage(&amp;quot;savedFightsCalculator&amp;quot;, savedFights);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveCharacter(&lt;br /&gt;
  savedCharacters,&lt;br /&gt;
  characterCreation,&lt;br /&gt;
  battle,&lt;br /&gt;
  newCharacter,&lt;br /&gt;
  characterDataObject&lt;br /&gt;
) {&lt;br /&gt;
  if (!characterDataObject) {&lt;br /&gt;
    var characterData = new FormData(characterCreation);&lt;br /&gt;
    var characterDataObject = {};&lt;br /&gt;
&lt;br /&gt;
    characterData.forEach(function (value, key) {&lt;br /&gt;
      characterDataObject[key] = convertToNumber(value);&lt;br /&gt;
    });&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  savedCharacters[characterDataObject.name] = characterDataObject;&lt;br /&gt;
  updateSavedCharacters(savedCharacters);&lt;br /&gt;
&lt;br /&gt;
  if (newCharacter) {&lt;br /&gt;
    addBattleChoice(battle, characterDataObject.name);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (battle.resetAttackType) {&lt;br /&gt;
    filterAttackTypeSelection(characterDataObject, battle.attackTypeSelection);&lt;br /&gt;
    battle.resetAttackType = false;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveButtonGreen(saveButton) {&lt;br /&gt;
  saveButton.classList.remove(&amp;quot;unsaved-character&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveButtonOrange(saveButton) {&lt;br /&gt;
  saveButton.classList.add(&amp;quot;unsaved-character&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function characterCreationListener(characters, battle) {&lt;br /&gt;
  var { characterCreation, saveButton, weaponCategory } = characters;&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;submit&amp;quot;, function (event) {&lt;br /&gt;
    event.preventDefault();&lt;br /&gt;
&lt;br /&gt;
    if (characters.unsavedChanges) {&lt;br /&gt;
      saveCharacter(characters.savedCharacters, characterCreation, battle);&lt;br /&gt;
      saveButtonGreen(saveButton);&lt;br /&gt;
      characters.unsavedChanges = false;&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  document.addEventListener(&amp;quot;keydown&amp;quot;, function (event) {&lt;br /&gt;
    if (event.ctrlKey &amp;amp;&amp;amp; event.key === &amp;quot;s&amp;quot;) {&lt;br /&gt;
      event.preventDefault();&lt;br /&gt;
      saveButton.click();&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  weaponCategory.addEventListener(&amp;quot;mouseover&amp;quot;, function (event) {&lt;br /&gt;
    label = event.target.closest(&amp;quot;label&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (label) {&lt;br /&gt;
      var tooltip = label.lastChild;&lt;br /&gt;
&lt;br /&gt;
      if (tooltip.classList.contains(&amp;quot;popContenu&amp;quot;)) {&lt;br /&gt;
        var tooltipRect = tooltip.getBoundingClientRect();&lt;br /&gt;
        var modalRect = weaponCategory.getBoundingClientRect();&lt;br /&gt;
&lt;br /&gt;
        if (tooltipRect.right &amp;gt; modalRect.right) {&lt;br /&gt;
          tooltip.style.left = &amp;quot;-100%&amp;quot;;&lt;br /&gt;
        } else if (tooltipRect.left &amp;lt; modalRect.left) {&lt;br /&gt;
          tooltip.style.left = &amp;quot;200%&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function downloadData(content, type, filename) {&lt;br /&gt;
  var link = document.createElement(&amp;quot;a&amp;quot;);&lt;br /&gt;
  var blob = new Blob([content], { type: type });&lt;br /&gt;
  var blobURL = URL.createObjectURL(blob);&lt;br /&gt;
&lt;br /&gt;
  link.href = blobURL;&lt;br /&gt;
  link.download = filename;&lt;br /&gt;
  document.body.appendChild(link);&lt;br /&gt;
&lt;br /&gt;
  link.click();&lt;br /&gt;
  document.body.removeChild(link);&lt;br /&gt;
  URL.revokeObjectURL(blobURL);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function uploadCharacter(&lt;br /&gt;
  selectedFiles,&lt;br /&gt;
  characters,&lt;br /&gt;
  characterTemplate,&lt;br /&gt;
  charactersContainer,&lt;br /&gt;
  battle&lt;br /&gt;
) {&lt;br /&gt;
  var selectFilesLength = selectedFiles.length;&lt;br /&gt;
&lt;br /&gt;
  for (var fileIndex = 0; fileIndex &amp;lt; selectFilesLength; fileIndex++) {&lt;br /&gt;
    var selectedFile = selectedFiles[fileIndex];&lt;br /&gt;
&lt;br /&gt;
    if (selectedFile.type === &amp;quot;text/plain&amp;quot;) {&lt;br /&gt;
      var reader = new FileReader();&lt;br /&gt;
      reader.onload = function (e) {&lt;br /&gt;
        var fileContent = e.target.result;&lt;br /&gt;
        try {&lt;br /&gt;
          var characterDataObject = JSON.parse(fileContent);&lt;br /&gt;
&lt;br /&gt;
          if (characterDataObject.hasOwnProperty(&amp;quot;name&amp;quot;)) {&lt;br /&gt;
            var characterPseudo = String(characterDataObject.name);&lt;br /&gt;
&lt;br /&gt;
            hideElement(characters.characterCreation);&lt;br /&gt;
            characterPseudo = validPseudo(characterPseudo);&lt;br /&gt;
&lt;br /&gt;
            [characterDataObject, characterPseudo] = addUniquePseudo(&lt;br /&gt;
              characterDataObject,&lt;br /&gt;
              Object.keys(characters.savedCharacters)&lt;br /&gt;
            );&lt;br /&gt;
            var selectedCharacter = handleNewCharacter(&lt;br /&gt;
              characters,&lt;br /&gt;
              characterTemplate,&lt;br /&gt;
              charactersContainer,&lt;br /&gt;
              battle,&lt;br /&gt;
              characterPseudo&lt;br /&gt;
            )[0];&lt;br /&gt;
&lt;br /&gt;
            if (selectFilesLength === 1) {&lt;br /&gt;
              updateForm(&lt;br /&gt;
                characterDataObject,&lt;br /&gt;
                characters.characterCreation,&lt;br /&gt;
                characters,&lt;br /&gt;
                selectedCharacter,&lt;br /&gt;
                battle&lt;br /&gt;
              );&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            saveCharacter(&lt;br /&gt;
              characters.savedCharacters,&lt;br /&gt;
              characters.characterCreation,&lt;br /&gt;
              battle,&lt;br /&gt;
              true,&lt;br /&gt;
              characterDataObject&lt;br /&gt;
            );&lt;br /&gt;
          }&lt;br /&gt;
        } catch (error) {&lt;br /&gt;
          console.log(error);&lt;br /&gt;
          if (error.name === &amp;quot;TypeError&amp;quot;) {&lt;br /&gt;
            // delete the character&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
      };&lt;br /&gt;
      reader.readAsText(selectedFile);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleUploadCharacter(&lt;br /&gt;
  characters,&lt;br /&gt;
  characterTemplate,&lt;br /&gt;
  charactersContainer,&lt;br /&gt;
  battle&lt;br /&gt;
) {&lt;br /&gt;
  var characterInput = characters.characterInput;&lt;br /&gt;
  var dropZone = characters.dropZone;&lt;br /&gt;
&lt;br /&gt;
  characterInput.accept = &amp;quot;.txt&amp;quot;;&lt;br /&gt;
  characterInput.multiple = true;&lt;br /&gt;
  dropZone.setAttribute(&amp;quot;tabindex&amp;quot;, &amp;quot;0&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  dropZone.addEventListener(&amp;quot;click&amp;quot;, function () {&lt;br /&gt;
    characterInput.click();&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  dropZone.addEventListener(&amp;quot;dragover&amp;quot;, function (event) {&lt;br /&gt;
    event.preventDefault();&lt;br /&gt;
    dropZone.classList.add(&amp;quot;drop-zone--dragover&amp;quot;);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  [&amp;quot;dragleave&amp;quot;, &amp;quot;dragend&amp;quot;].forEach(function (type) {&lt;br /&gt;
    dropZone.addEventListener(type, function () {&lt;br /&gt;
      dropZone.classList.remove(&amp;quot;drop-zone--dragover&amp;quot;);&lt;br /&gt;
    });&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  dropZone.addEventListener(&amp;quot;drop&amp;quot;, function (event) {&lt;br /&gt;
    event.preventDefault();&lt;br /&gt;
    uploadCharacter(&lt;br /&gt;
      event.dataTransfer.files,&lt;br /&gt;
      characters,&lt;br /&gt;
      characterTemplate,&lt;br /&gt;
      charactersContainer,&lt;br /&gt;
      battle&lt;br /&gt;
    );&lt;br /&gt;
    dropZone.classList.remove(&amp;quot;drop-zone--dragover&amp;quot;);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  characterInput.addEventListener(&amp;quot;change&amp;quot;, function (event) {&lt;br /&gt;
    uploadCharacter(&lt;br /&gt;
      event.target.files,&lt;br /&gt;
      characters,&lt;br /&gt;
      characterTemplate,&lt;br /&gt;
      charactersContainer,&lt;br /&gt;
      battle&lt;br /&gt;
    );&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function deleteCharacter(characters, pseudo, element, battle) {&lt;br /&gt;
  battle.battleForm.reset();&lt;br /&gt;
  delete characters.savedCharacters[pseudo];&lt;br /&gt;
  element.remove();&lt;br /&gt;
&lt;br /&gt;
  updateSavedCharacters(characters.savedCharacters);&lt;br /&gt;
  removeBattleChoice(battle, pseudo);&lt;br /&gt;
&lt;br /&gt;
  if (&lt;br /&gt;
    !Object.keys(characters.savedCharacters).length ||&lt;br /&gt;
    characters.characterCreation.name.value === pseudo&lt;br /&gt;
  ) {&lt;br /&gt;
    saveButtonGreen(characters.saveButton);&lt;br /&gt;
    characters.unsavedChanges = false;&lt;br /&gt;
    hideElement(characters.characterCreation);&lt;br /&gt;
    showElement(characters.characterCreation.previousElementSibling);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function deleteMonster(characters, battle, monsterVnum, monsterElement) {&lt;br /&gt;
  var monsterElement =&lt;br /&gt;
    monsterElement ||&lt;br /&gt;
    characters.monstersContainer.querySelector(&lt;br /&gt;
      &amp;quot;[data-monster-id='&amp;quot; + monsterVnum + &amp;quot;']&amp;quot;&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
  if (monsterElement) {&lt;br /&gt;
    monsterElement.remove();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  battle.battleForm.reset();&lt;br /&gt;
  delete characters.savedMonsters[monsterVnum];&lt;br /&gt;
&lt;br /&gt;
  updateSavedMonsters(characters.savedMonsters);&lt;br /&gt;
  removeBattleChoice(battle, monsterVnum);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleStyle(characters, selectedElement) {&lt;br /&gt;
  var currentCharacter = characters.currentCharacter;&lt;br /&gt;
&lt;br /&gt;
  if (currentCharacter) {&lt;br /&gt;
    currentCharacter.classList.remove(&amp;quot;selected-character&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  selectedElement.classList.add(&amp;quot;selected-character&amp;quot;);&lt;br /&gt;
  characters.currentCharacter = selectedElement;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateForm(&lt;br /&gt;
  formData,&lt;br /&gt;
  characterCreation,&lt;br /&gt;
  characters,&lt;br /&gt;
  selectedElement,&lt;br /&gt;
  battle&lt;br /&gt;
) {&lt;br /&gt;
  saveButtonGreen(characters.saveButton);&lt;br /&gt;
  hideElement(characterCreation.previousElementSibling);&lt;br /&gt;
  showElement(characterCreation);&lt;br /&gt;
  handleStyle(characters, selectedElement);&lt;br /&gt;
&lt;br /&gt;
  characterCreation.reset();&lt;br /&gt;
&lt;br /&gt;
  for (var [name, value] of Object.entries(formData)) {&lt;br /&gt;
    var formElement = characterCreation[name];&lt;br /&gt;
&lt;br /&gt;
    if (!formElement) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (formElement.type === &amp;quot;checkbox&amp;quot;) {&lt;br /&gt;
      if (isChecked(value)) {&lt;br /&gt;
        formElement.checked = true;&lt;br /&gt;
      }&lt;br /&gt;
    } else {&lt;br /&gt;
      formElement.value = value;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  var selectedRace = characterCreation.race.value;&lt;br /&gt;
  var classChoice = characterCreation.class;&lt;br /&gt;
  var weaponElement = characterCreation.weapon;&lt;br /&gt;
&lt;br /&gt;
  filterClass(selectedRace, classChoice, true);&lt;br /&gt;
  filterWeapon(&lt;br /&gt;
    selectedRace,&lt;br /&gt;
    weaponElement,&lt;br /&gt;
    characters.weaponCategory,&lt;br /&gt;
    battle.constants.allowedWeaponsPerRace,&lt;br /&gt;
    true&lt;br /&gt;
  );&lt;br /&gt;
  handleWeaponDisplay(characters.weaponCategory, characters.weaponDisplay, weaponElement.value);&lt;br /&gt;
  filterUpgrade(&lt;br /&gt;
    characterCreation.weaponUpgrade,&lt;br /&gt;
    weaponElement.value,&lt;br /&gt;
    characters.randomAttackValue,&lt;br /&gt;
    characters.randomMagicAttackValue,&lt;br /&gt;
  );&lt;br /&gt;
  filterCheckbox(&lt;br /&gt;
    characterCreation.isPolymorph,&lt;br /&gt;
    characterCreation.polymorphMonster.parentElement&lt;br /&gt;
  );&lt;br /&gt;
  filterCheckbox(&lt;br /&gt;
    characterCreation.lowRank,&lt;br /&gt;
    characterCreation.playerRank.parentElement&lt;br /&gt;
  );&lt;br /&gt;
  filterCheckbox(characterCreation.onYohara, characters.yoharaCreation);&lt;br /&gt;
  filterCheckbox(characterCreation.isBlessed, characters.blessingCreation);&lt;br /&gt;
  filterCheckbox(characterCreation.isMarried, characters.marriageCreation);&lt;br /&gt;
  filterSkills(classChoice.value, characters.skillElementsToFilter);&lt;br /&gt;
  handleBonusVariationUpdate(characterCreation, characters.bonusVariation);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleClickOnCharacter(&lt;br /&gt;
  spanInput,&lt;br /&gt;
  target,&lt;br /&gt;
  characters,&lt;br /&gt;
  characterElement,&lt;br /&gt;
  battle,&lt;br /&gt;
  edition&lt;br /&gt;
) {&lt;br /&gt;
  var displayedPseudo = characters.characterCreation.name.value;&lt;br /&gt;
  var pseudo = spanInput.dataset.name;&lt;br /&gt;
&lt;br /&gt;
  if (edition) {&lt;br /&gt;
    if (!characters.unsavedChanges) {&lt;br /&gt;
      updateForm(&lt;br /&gt;
        characters.savedCharacters[pseudo],&lt;br /&gt;
        characters.characterCreation,&lt;br /&gt;
        characters,&lt;br /&gt;
        characterElement,&lt;br /&gt;
        battle&lt;br /&gt;
      );&lt;br /&gt;
    } else if (displayedPseudo === pseudo) {&lt;br /&gt;
      // pass&lt;br /&gt;
    } else {&lt;br /&gt;
      var result = confirm(&lt;br /&gt;
        &amp;quot;Voulez-vous continuer ? Les dernières modifications ne seront pas sauvegardées.&amp;quot;&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      if (result) {&lt;br /&gt;
        updateForm(&lt;br /&gt;
          characters.savedCharacters[pseudo],&lt;br /&gt;
          characters.characterCreation,&lt;br /&gt;
          characters,&lt;br /&gt;
          characterElement,&lt;br /&gt;
          battle&lt;br /&gt;
        );&lt;br /&gt;
        characters.unsavedChanges = false;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    if (target.tagName === &amp;quot;path&amp;quot;) {&lt;br /&gt;
      target = target.parentElement;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    switch (target.dataset.icon) {&lt;br /&gt;
      case &amp;quot;duplicate&amp;quot;:&lt;br /&gt;
        if (!characters.unsavedChanges) {&lt;br /&gt;
          addNewCharacter(&lt;br /&gt;
            characters,&lt;br /&gt;
            characters.newCharacterTemplate,&lt;br /&gt;
            characters.charactersContainer,&lt;br /&gt;
            battle,&lt;br /&gt;
            pseudo&lt;br /&gt;
          );&lt;br /&gt;
        } else {&lt;br /&gt;
          var result = confirm(&lt;br /&gt;
            &amp;quot;Voulez-vous continuer ? Les dernières modifications ne seront pas sauvegardées.&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
&lt;br /&gt;
          if (result) {&lt;br /&gt;
            addNewCharacter(&lt;br /&gt;
              characters,&lt;br /&gt;
              characters.newCharacterTemplate,&lt;br /&gt;
              characters.charactersContainer,&lt;br /&gt;
              battle,&lt;br /&gt;
              pseudo&lt;br /&gt;
            );&lt;br /&gt;
            saveButtonGreen(characters.saveButton);&lt;br /&gt;
            characters.unsavedChanges = false;&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
        break;&lt;br /&gt;
&lt;br /&gt;
      case &amp;quot;download&amp;quot;:&lt;br /&gt;
        var character = characters.savedCharacters[pseudo];&lt;br /&gt;
        downloadData(&lt;br /&gt;
          JSON.stringify(character),&lt;br /&gt;
          &amp;quot;text/plain&amp;quot;,&lt;br /&gt;
          character.name + &amp;quot;.txt&amp;quot;&lt;br /&gt;
        );&lt;br /&gt;
        break;&lt;br /&gt;
&lt;br /&gt;
      case &amp;quot;delete&amp;quot;:&lt;br /&gt;
        var result = confirm(&lt;br /&gt;
          &amp;quot;Voulez-vous vraiment supprimer définitivement le personnage &amp;quot; +&lt;br /&gt;
          pseudo +&lt;br /&gt;
          &amp;quot; ?&amp;quot;&lt;br /&gt;
        );&lt;br /&gt;
        if (result) {&lt;br /&gt;
          deleteCharacter(characters, pseudo, characterElement, battle);&lt;br /&gt;
        }&lt;br /&gt;
        break;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleNewCharacter(&lt;br /&gt;
  characters,&lt;br /&gt;
  characterTemplate,&lt;br /&gt;
  charactersContainer,&lt;br /&gt;
  battle,&lt;br /&gt;
  pseudo&lt;br /&gt;
) {&lt;br /&gt;
  var newCharacterTemplate = characterTemplate.cloneNode(true);&lt;br /&gt;
  var spanInput = newCharacterTemplate.querySelector(&amp;quot;span.input&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  newCharacterTemplate.setAttribute(&amp;quot;tabindex&amp;quot;, &amp;quot;0&amp;quot;);&lt;br /&gt;
  charactersContainer.appendChild(newCharacterTemplate);&lt;br /&gt;
&lt;br /&gt;
  if (pseudo) {&lt;br /&gt;
    spanInput.textContent = pseudo;&lt;br /&gt;
    spanInput.setAttribute(&amp;quot;data-name&amp;quot;, pseudo);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  newCharacterTemplate.addEventListener(&amp;quot;click&amp;quot;, function (event) {&lt;br /&gt;
    var target = event.target;&lt;br /&gt;
&lt;br /&gt;
    if (target.tagName === &amp;quot;path&amp;quot; || target.tagName === &amp;quot;svg&amp;quot;) {&lt;br /&gt;
      handleClickOnCharacter(&lt;br /&gt;
        spanInput,&lt;br /&gt;
        target,&lt;br /&gt;
        characters,&lt;br /&gt;
        newCharacterTemplate,&lt;br /&gt;
        battle&lt;br /&gt;
      );&lt;br /&gt;
    } else {&lt;br /&gt;
      handleClickOnCharacter(&lt;br /&gt;
        spanInput,&lt;br /&gt;
        null,&lt;br /&gt;
        characters,&lt;br /&gt;
        newCharacterTemplate,&lt;br /&gt;
        battle,&lt;br /&gt;
        true&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  newCharacterTemplate.addEventListener(&amp;quot;keydown&amp;quot;, function (event) {&lt;br /&gt;
    if (event.keyCode === 13) {&lt;br /&gt;
      event.target.click();&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  return [newCharacterTemplate, spanInput];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function validPseudo(pseudo) {&lt;br /&gt;
  var newPseudo = pseudoFormat(pseudo);&lt;br /&gt;
&lt;br /&gt;
  if (!newPseudo) {&lt;br /&gt;
    return &amp;quot;Pseudo&amp;quot;;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return newPseudo;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addNewCharacter(&lt;br /&gt;
  characters,&lt;br /&gt;
  characterTemplate,&lt;br /&gt;
  charactersContainer,&lt;br /&gt;
  battle,&lt;br /&gt;
  pseudoToDuplicate&lt;br /&gt;
) {&lt;br /&gt;
  function editAndSetCharacterPseudoInput(selectedCharacter, spanInput) {&lt;br /&gt;
    var maxPseudoLength = 20;&lt;br /&gt;
&lt;br /&gt;
    var selection = window.getSelection();&lt;br /&gt;
    var range = document.createRange();&lt;br /&gt;
&lt;br /&gt;
    if (pseudoToDuplicate) {&lt;br /&gt;
      spanInput.textContent = pseudoToDuplicate;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    spanInput.contentEditable = true;&lt;br /&gt;
    spanInput.focus();&lt;br /&gt;
    range.selectNodeContents(spanInput);&lt;br /&gt;
    selection.removeAllRanges();&lt;br /&gt;
    selection.addRange(range);&lt;br /&gt;
&lt;br /&gt;
    function pseudoValidation() {&lt;br /&gt;
      var characterPseudo = validPseudo(spanInput.textContent);&lt;br /&gt;
      var characterDataObject = { name: characterPseudo };&lt;br /&gt;
&lt;br /&gt;
      if (pseudoToDuplicate) {&lt;br /&gt;
        characterDataObject = copyObject(&lt;br /&gt;
          characters.savedCharacters[pseudoToDuplicate]&lt;br /&gt;
        );&lt;br /&gt;
        characterDataObject.name = characterPseudo;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      [characterDataObject, characterPseudo] = addUniquePseudo(&lt;br /&gt;
        characterDataObject,&lt;br /&gt;
        Object.keys(characters.savedCharacters)&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      selection.removeAllRanges();&lt;br /&gt;
      spanInput.contentEditable = false;&lt;br /&gt;
      spanInput.textContent = characterPseudo;&lt;br /&gt;
      spanInput.setAttribute(&amp;quot;data-name&amp;quot;, characterPseudo);&lt;br /&gt;
&lt;br /&gt;
      updateForm(&lt;br /&gt;
        characterDataObject,&lt;br /&gt;
        characters.characterCreation,&lt;br /&gt;
        characters,&lt;br /&gt;
        selectedCharacter,&lt;br /&gt;
        battle&lt;br /&gt;
      );&lt;br /&gt;
      saveCharacter(&lt;br /&gt;
        characters.savedCharacters,&lt;br /&gt;
        characters.characterCreation,&lt;br /&gt;
        battle,&lt;br /&gt;
        true&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handleMaxLength(event) {&lt;br /&gt;
      if (spanInput.textContent.length &amp;gt; maxPseudoLength) {&lt;br /&gt;
        spanInput.textContent = spanInput.textContent.slice(0, maxPseudoLength);&lt;br /&gt;
        range.setStart(spanInput.childNodes[0], maxPseudoLength);&lt;br /&gt;
        selection.removeAllRanges();&lt;br /&gt;
        selection.addRange(range);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handleBlur() {&lt;br /&gt;
      spanInput.removeEventListener(&amp;quot;blur&amp;quot;, handleBlur);&lt;br /&gt;
      spanInput.removeEventListener(&amp;quot;input&amp;quot;, handleMaxLength);&lt;br /&gt;
      pseudoValidation();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handleKeyDown(event) {&lt;br /&gt;
      if (event.key === &amp;quot;Enter&amp;quot;) {&lt;br /&gt;
        event.preventDefault();&lt;br /&gt;
&lt;br /&gt;
        spanInput.removeEventListener(&amp;quot;keydown&amp;quot;, handleKeyDown);&lt;br /&gt;
        spanInput.removeEventListener(&amp;quot;blur&amp;quot;, handleBlur);&lt;br /&gt;
        spanInput.removeEventListener(&amp;quot;input&amp;quot;, handleMaxLength);&lt;br /&gt;
&lt;br /&gt;
        pseudoValidation();&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    spanInput.addEventListener(&amp;quot;input&amp;quot;, handleMaxLength);&lt;br /&gt;
    spanInput.addEventListener(&amp;quot;keydown&amp;quot;, handleKeyDown);&lt;br /&gt;
    spanInput.addEventListener(&amp;quot;blur&amp;quot;, handleBlur);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  hideElement(characters.characterCreation);&lt;br /&gt;
  var [selectedCharacter, spanInput] = handleNewCharacter(&lt;br /&gt;
    characters,&lt;br /&gt;
    characterTemplate,&lt;br /&gt;
    charactersContainer,&lt;br /&gt;
    battle&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  editAndSetCharacterPseudoInput(selectedCharacter, spanInput);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleFocus() {&lt;br /&gt;
  var tooltipLinks = document.querySelectorAll(&amp;quot;div.tooltip a&amp;quot;);&lt;br /&gt;
  tooltipLinks.forEach(function (link) {&lt;br /&gt;
    link.setAttribute(&amp;quot;tabindex&amp;quot;, -1);&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleBonusVariationUpdate(characterCreation, bonusVariation) {&lt;br /&gt;
  var selectedBonus = characterCreation.bonusVariation.value;&lt;br /&gt;
&lt;br /&gt;
  if (characterCreation.hasOwnProperty(selectedBonus)) {&lt;br /&gt;
    handleBonusVariation(characterCreation[selectedBonus], bonusVariation);&lt;br /&gt;
  } else {&lt;br /&gt;
    var { minValue, maxValue } = bonusVariation;&lt;br /&gt;
&lt;br /&gt;
    minValue.removeAttribute(&amp;quot;min&amp;quot;);&lt;br /&gt;
    minValue.removeAttribute(&amp;quot;max&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    maxValue.removeAttribute(&amp;quot;min&amp;quot;);&lt;br /&gt;
    maxValue.removeAttribute(&amp;quot;max&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    hideElement(bonusVariation.container);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getTargetContent(targetParent, targetName, isSkill) {&lt;br /&gt;
  var targetContent = &amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  if (targetParent.children.length &amp;lt;= 1) {&lt;br /&gt;
    targetContent = targetParent.textContent;&lt;br /&gt;
  } else if (targetName === &amp;quot;weaponUpgrade&amp;quot;) {&lt;br /&gt;
    targetContent = targetParent.children[1].textContent;&lt;br /&gt;
  } else if (isSkill) {&lt;br /&gt;
    var container = targetParent.children[1];&lt;br /&gt;
&lt;br /&gt;
    for (var index = 1; index &amp;lt; container.children.length; index++) {&lt;br /&gt;
      var element = container.children[index];&lt;br /&gt;
&lt;br /&gt;
      if (element.checkVisibility()) {&lt;br /&gt;
        targetContent += element.textContent;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    for (var index = 1; index &amp;lt; targetParent.children.length; index++) {&lt;br /&gt;
      var element = targetParent.children[index];&lt;br /&gt;
&lt;br /&gt;
      if (element.checkVisibility()) {&lt;br /&gt;
        targetContent += element.textContent;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return targetContent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleBonusVariation(target, bonusVariation, isSelectedByUser) {&lt;br /&gt;
  var { activation, inputDisplay, minValue, maxValue, container } =&lt;br /&gt;
    bonusVariation;&lt;br /&gt;
&lt;br /&gt;
  var {&lt;br /&gt;
    min: targetMin,&lt;br /&gt;
    max: targetMax,&lt;br /&gt;
    name: targetName,&lt;br /&gt;
    value: targetValue,&lt;br /&gt;
    parentElement: targetParent,&lt;br /&gt;
    tagName,&lt;br /&gt;
  } = target;&lt;br /&gt;
&lt;br /&gt;
  targetMin = Number(targetMin);&lt;br /&gt;
  targetMax = Number(targetMax);&lt;br /&gt;
  targetValue = Number(targetValue);&lt;br /&gt;
&lt;br /&gt;
  var isSkill = tagName === &amp;quot;SELECT&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  if (container.contains(target) || targetName == 0) {&lt;br /&gt;
    if (!isSelectedByUser) {&lt;br /&gt;
      hideElement(container);&lt;br /&gt;
    }&lt;br /&gt;
    return;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (isSkill) {&lt;br /&gt;
    var options = target.options;&lt;br /&gt;
&lt;br /&gt;
    targetMin = options[0].value;&lt;br /&gt;
    targetMax = options[options.length - 1].value;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  minValue.min = targetMin;&lt;br /&gt;
  minValue.max = targetMax;&lt;br /&gt;
&lt;br /&gt;
  maxValue.min = targetMin;&lt;br /&gt;
  maxValue.max = targetMax;&lt;br /&gt;
&lt;br /&gt;
  if (isSelectedByUser) {&lt;br /&gt;
    var { input, tab } = bonusVariation;&lt;br /&gt;
&lt;br /&gt;
    inputDisplay.value = getTargetContent(targetParent, targetName, isSkill);&lt;br /&gt;
&lt;br /&gt;
    input.value = targetName;&lt;br /&gt;
    minValue.value = Math.max(targetValue - 10, targetMin);&lt;br /&gt;
    maxValue.value = Math.min(targetValue + 10, targetMax);&lt;br /&gt;
&lt;br /&gt;
    activation.checked = true;&lt;br /&gt;
&lt;br /&gt;
    tab.click();&lt;br /&gt;
    tab.scrollIntoView(true);&lt;br /&gt;
&lt;br /&gt;
    input.dispatchEvent(new Event(&amp;quot;change&amp;quot;, { bubbles: true }));&lt;br /&gt;
  } else {&lt;br /&gt;
    if (minValue.value &amp;lt; targetMin) {&lt;br /&gt;
      minValue.value = targetMin;&lt;br /&gt;
      minValue.dispatchEvent(new Event(&amp;quot;change&amp;quot;, { bubbles: true }));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (maxValue.value &amp;gt; targetMax) {&lt;br /&gt;
      maxValue.value = targetMax;&lt;br /&gt;
      maxValue.dispatchEvent(new Event(&amp;quot;change&amp;quot;, { bubbles: true }));&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  inputDisplay.style.width = inputDisplay.value.length * 0.55 + &amp;quot;em&amp;quot;;&lt;br /&gt;
  showElement(container);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function characterManagement(characters, battle) {&lt;br /&gt;
  var {&lt;br /&gt;
    newCharacterTemplate: characterTemplate,&lt;br /&gt;
    charactersContainer,&lt;br /&gt;
    addNewCharacterButton,&lt;br /&gt;
    saveButton,&lt;br /&gt;
    characterCreation,&lt;br /&gt;
    bonusVariation,&lt;br /&gt;
  } = characters;&lt;br /&gt;
&lt;br /&gt;
  Object.keys(characters.savedCharacters).forEach(function (pseudo) {&lt;br /&gt;
    handleNewCharacter(&lt;br /&gt;
      characters,&lt;br /&gt;
      characterTemplate,&lt;br /&gt;
      charactersContainer,&lt;br /&gt;
      battle,&lt;br /&gt;
      pseudo&lt;br /&gt;
    );&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  addNewCharacterButton.addEventListener(&amp;quot;click&amp;quot;, function (event) {&lt;br /&gt;
    if (!characters.unsavedChanges) {&lt;br /&gt;
      addNewCharacter(&lt;br /&gt;
        characters,&lt;br /&gt;
        characterTemplate,&lt;br /&gt;
        charactersContainer,&lt;br /&gt;
        battle&lt;br /&gt;
      );&lt;br /&gt;
    } else {&lt;br /&gt;
      var result = confirm(&lt;br /&gt;
        &amp;quot;Voulez-vous continuer ? Les dernières modifications ne seront pas sauvegardées.&amp;quot;&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      if (result) {&lt;br /&gt;
        addNewCharacter(&lt;br /&gt;
          characters,&lt;br /&gt;
          characterTemplate,&lt;br /&gt;
          charactersContainer,&lt;br /&gt;
          battle&lt;br /&gt;
        );&lt;br /&gt;
        saveButtonGreen(saveButton);&lt;br /&gt;
        characters.unsavedChanges = false;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  handleUploadCharacter(&lt;br /&gt;
    characters,&lt;br /&gt;
    characterTemplate,&lt;br /&gt;
    charactersContainer,&lt;br /&gt;
    battle&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;change&amp;quot;, function () {&lt;br /&gt;
    saveButtonOrange(saveButton);&lt;br /&gt;
    characters.unsavedChanges = true;&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  function handleLongPress(target) {&lt;br /&gt;
    if (target.tagName !== &amp;quot;INPUT&amp;quot; &amp;amp;&amp;amp; target.tagName !== &amp;quot;SELECT&amp;quot;) {&lt;br /&gt;
      target = target.querySelector(&amp;quot;input&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      !target ||&lt;br /&gt;
      (target.type !== &amp;quot;number&amp;quot; &amp;amp;&amp;amp;&lt;br /&gt;
        !target.classList.contains(&amp;quot;skill-select&amp;quot;) &amp;amp;&amp;amp;&lt;br /&gt;
        target.name !== &amp;quot;weaponUpgrade&amp;quot;)&lt;br /&gt;
    ) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    handleBonusVariation(target, bonusVariation, true);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;click&amp;quot;, function (event) {&lt;br /&gt;
    if (event.shiftKey || event.ctrlKey) {&lt;br /&gt;
      handleLongPress(event.target);&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  var longPressTimer;&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;touchstart&amp;quot;, function (event) {&lt;br /&gt;
    longPressTimer = setTimeout(function () {&lt;br /&gt;
      handleLongPress(event.target);&lt;br /&gt;
    }, 800);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;touchend&amp;quot;, function () {&lt;br /&gt;
    clearTimeout(longPressTimer);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;touchmove&amp;quot;, function () {&lt;br /&gt;
    clearTimeout(longPressTimer);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  filterForm(characters, battle);&lt;br /&gt;
  characterCreationListener(characters, battle);&lt;br /&gt;
  handleFocus();&lt;br /&gt;
&lt;br /&gt;
  window.addEventListener(&amp;quot;beforeunload&amp;quot;, function (event) {&lt;br /&gt;
    if (characters.unsavedChanges) {&lt;br /&gt;
      event.preventDefault();&lt;br /&gt;
      return &amp;quot;&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function removeFromIframe(iframe, monsterVnum, addButton) {&lt;br /&gt;
  var iframeDoc = iframe.contentDocument || iframe.contentWindow.document;&lt;br /&gt;
  var removeButton = iframeDoc.querySelector(&lt;br /&gt;
    &amp;quot;.handle-monster[data-monster-id='&amp;quot; + monsterVnum + &amp;quot;']&amp;quot;&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  if (removeButton) {&lt;br /&gt;
    replaceMonsterButton(removeButton, addButton, monsterVnum);&lt;br /&gt;
    return true;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return false;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addMonsterElement(characters, battle, monsterVnum) {&lt;br /&gt;
  var {&lt;br /&gt;
    monsteriFrame,&lt;br /&gt;
    stoneiFrame,&lt;br /&gt;
    monsterTemplate,&lt;br /&gt;
    monstersContainer,&lt;br /&gt;
    monsterButtonTemplates,&lt;br /&gt;
  } = characters;&lt;br /&gt;
  var addButton = monsterButtonTemplates.children[0];&lt;br /&gt;
  var monsterElement = monsterTemplate.cloneNode(true);&lt;br /&gt;
&lt;br /&gt;
  var spanInput = monsterElement.querySelector(&amp;quot;span.input&amp;quot;);&lt;br /&gt;
  var deleteSvg = monsterElement.querySelector(&amp;quot;svg&amp;quot;);&lt;br /&gt;
  var monsterName = getMonsterName(monsterVnum);&lt;br /&gt;
&lt;br /&gt;
  var link = document.createElement(&amp;quot;a&amp;quot;);&lt;br /&gt;
  link.href = mw.util.getUrl(monsterName);&lt;br /&gt;
  link.title = monsterName;&lt;br /&gt;
  link.textContent = monsterName;&lt;br /&gt;
&lt;br /&gt;
  spanInput.appendChild(link);&lt;br /&gt;
&lt;br /&gt;
  monsterElement.setAttribute(&amp;quot;tabindex&amp;quot;, &amp;quot;0&amp;quot;);&lt;br /&gt;
  monsterElement.setAttribute(&amp;quot;data-monster-id&amp;quot;, monsterVnum);&lt;br /&gt;
&lt;br /&gt;
  monstersContainer.appendChild(monsterElement);&lt;br /&gt;
&lt;br /&gt;
  deleteSvg.addEventListener(&amp;quot;click&amp;quot;, function () {&lt;br /&gt;
    deleteMonster(characters, battle, monsterVnum, monsterElement);&lt;br /&gt;
    var isRemoved = removeFromIframe(monsteriFrame, monsterVnum, addButton);&lt;br /&gt;
    if (!isRemoved) {&lt;br /&gt;
      removeFromIframe(stoneiFrame, monsterVnum, addButton);&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addNewMonster(characters, battle, monsterVnum, monsterImage) {&lt;br /&gt;
  if (isValueInArray(monsterVnum, Object.keys(characters.savedMonsters)))&lt;br /&gt;
    return;&lt;br /&gt;
&lt;br /&gt;
  characters.savedMonsters[monsterVnum] = { image: monsterImage };&lt;br /&gt;
  addMonsterElement(characters, battle, monsterVnum);&lt;br /&gt;
  updateSavedMonsters(characters.savedMonsters);&lt;br /&gt;
  addBattleChoice(battle, monsterVnum, true);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function replaceMonsterButton(currentButton, newButton, monsterVnum) {&lt;br /&gt;
  var newButtonClone = newButton.cloneNode(true);&lt;br /&gt;
  newButtonClone.dataset.monsterId = monsterVnum;&lt;br /&gt;
  currentButton.replaceWith(newButtonClone);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addButtonsToCards(&lt;br /&gt;
  iframeDoc,&lt;br /&gt;
  nameToVnum,&lt;br /&gt;
  addButton,&lt;br /&gt;
  removeButton,&lt;br /&gt;
  characters&lt;br /&gt;
) {&lt;br /&gt;
  var cardToEdit = iframeDoc.getElementById(&amp;quot;cards-container&amp;quot;).children;&lt;br /&gt;
  var addedMonsters = Object.keys(characters.savedMonsters);&lt;br /&gt;
&lt;br /&gt;
  for (var cardIndex = 0; cardIndex &amp;lt; cardToEdit.length; cardIndex++) {&lt;br /&gt;
    var card = cardToEdit[cardIndex];&lt;br /&gt;
    var cardName = card.querySelector(&amp;quot;[data-name]&amp;quot;).firstChild.title;&lt;br /&gt;
&lt;br /&gt;
    cardName = cardName.replace(/\s/g, &amp;quot; &amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (!nameToVnum.hasOwnProperty(cardName)) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var monsterVnum = nameToVnum[cardName];&lt;br /&gt;
    var buttonClone;&lt;br /&gt;
&lt;br /&gt;
    if (isValueInArray(monsterVnum, addedMonsters)) {&lt;br /&gt;
      buttonClone = removeButton.cloneNode(true);&lt;br /&gt;
    } else {&lt;br /&gt;
      buttonClone = addButton.cloneNode(true);&lt;br /&gt;
    }&lt;br /&gt;
    buttonClone.dataset.monsterId = monsterVnum;&lt;br /&gt;
    card.lastElementChild.appendChild(buttonClone);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getMonsterImage(addButton) {&lt;br /&gt;
  var elder = addButton.parentElement.firstElementChild;&lt;br /&gt;
  var image = elder.querySelector(&amp;quot;img&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (image) {&lt;br /&gt;
    return image.getAttribute(&amp;quot;src&amp;quot;) || &amp;quot;&amp;quot;;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return &amp;quot;&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleiFrame(category, iframe, nameToVnum, characters, battle) {&lt;br /&gt;
  var [addButton, removeButton] = characters.monsterButtonTemplates.children;&lt;br /&gt;
&lt;br /&gt;
  iframe.src = mw.util.getUrl(category);&lt;br /&gt;
&lt;br /&gt;
  iframe.addEventListener(&amp;quot;load&amp;quot;, function () {&lt;br /&gt;
    var iframeDoc = this.contentDocument || this.contentWindow.document;&lt;br /&gt;
    var iframeBody = iframeDoc.body;&lt;br /&gt;
&lt;br /&gt;
    content = iframeDoc.getElementById(&amp;quot;show-after-loading&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    iframeBody.firstElementChild.replaceWith(content);&lt;br /&gt;
&lt;br /&gt;
    iframeBody.style.background = &amp;quot;transparent&amp;quot;;&lt;br /&gt;
    iframeBody.style.paddingRight = &amp;quot;10px&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    addButtonsToCards(&lt;br /&gt;
      iframeDoc,&lt;br /&gt;
      nameToVnum,&lt;br /&gt;
      addButton,&lt;br /&gt;
      removeButton,&lt;br /&gt;
      characters&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    iframeDoc.addEventListener(&amp;quot;click&amp;quot;, function (event) {&lt;br /&gt;
      var target = event.target;&lt;br /&gt;
      var link = target.closest(&amp;quot;a&amp;quot;);&lt;br /&gt;
      var currentButton = target.closest(&amp;quot;.handle-monster&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
      if (link) {&lt;br /&gt;
        event.preventDefault();&lt;br /&gt;
        window.open(link.href, &amp;quot;_blank&amp;quot;);&lt;br /&gt;
      } else if (currentButton) {&lt;br /&gt;
        var { monsterId: monsterVnum, action } = currentButton.dataset;&lt;br /&gt;
        var newButton;&lt;br /&gt;
&lt;br /&gt;
        if (action === &amp;quot;add&amp;quot;) {&lt;br /&gt;
          var monsterImage = getMonsterImage(currentButton);&lt;br /&gt;
          addNewMonster(characters, battle, monsterVnum, monsterImage);&lt;br /&gt;
          newButton = removeButton;&lt;br /&gt;
        } else if (action === &amp;quot;remove&amp;quot;) {&lt;br /&gt;
          deleteMonster(characters, battle, monsterVnum);&lt;br /&gt;
          newButton = addButton;&lt;br /&gt;
        }&lt;br /&gt;
        replaceMonsterButton(currentButton, newButton, monsterVnum);&lt;br /&gt;
      }&lt;br /&gt;
    });&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getNameToVnumMapping() {&lt;br /&gt;
  var nameToVnum = {};&lt;br /&gt;
&lt;br /&gt;
  for (var monsterVnum in monsterData) {&lt;br /&gt;
    nameToVnum[monsterData[monsterVnum][monsterData[monsterVnum].length - 1]] =&lt;br /&gt;
      monsterVnum;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return nameToVnum;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function monsterManagement(characters, battle) {&lt;br /&gt;
  var { monsteriFrame, stoneiFrame } = characters;&lt;br /&gt;
  var nameToVnum = getNameToVnumMapping();&lt;br /&gt;
  var monsterVnums = Object.keys(monsterData);&lt;br /&gt;
&lt;br /&gt;
  var iframeLoaded = { monster: false, stone: false };&lt;br /&gt;
&lt;br /&gt;
  document.addEventListener(&amp;quot;modalOpen&amp;quot;, function (event) {&lt;br /&gt;
    var modalName = event.detail.name;&lt;br /&gt;
&lt;br /&gt;
    if (modalName === &amp;quot;monster&amp;quot; &amp;amp;&amp;amp; !iframeLoaded.monster) {&lt;br /&gt;
      handleiFrame(&amp;quot;Monstres&amp;quot;, monsteriFrame, nameToVnum, characters, battle);&lt;br /&gt;
      iframeLoaded.monster = true;&lt;br /&gt;
    } else if (modalName === &amp;quot;stone&amp;quot; &amp;amp;&amp;amp; !iframeLoaded.stone) {&lt;br /&gt;
      handleiFrame(&lt;br /&gt;
        &amp;quot;Pierres Metin&amp;quot;,&lt;br /&gt;
        stoneiFrame,&lt;br /&gt;
        nameToVnum,&lt;br /&gt;
        characters,&lt;br /&gt;
        battle&lt;br /&gt;
      );&lt;br /&gt;
      iframeLoaded.stone = true;&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  Object.keys(characters.savedMonsters)&lt;br /&gt;
    .slice()&lt;br /&gt;
    .forEach(function (monsterVnum) {&lt;br /&gt;
      if (isValueInArray(monsterVnum, monsterVnums)) {&lt;br /&gt;
        addMonsterElement(characters, battle, monsterVnum);&lt;br /&gt;
      } else {&lt;br /&gt;
        deleteMonster(characters, battle, monsterVnum);&lt;br /&gt;
      }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function removeBattleChoice(battle, name) {&lt;br /&gt;
  var battleSelects = [battle.attackerSelection, battle.victimSelection];&lt;br /&gt;
&lt;br /&gt;
  battleSelects.forEach(function (battleSelect) {&lt;br /&gt;
    for (&lt;br /&gt;
      var optionIndex = 0;&lt;br /&gt;
      optionIndex &amp;lt; battleSelect.options.length;&lt;br /&gt;
      optionIndex++&lt;br /&gt;
    ) {&lt;br /&gt;
      if (battleSelect.options[optionIndex].value === name) {&lt;br /&gt;
        battleSelect.remove(optionIndex);&lt;br /&gt;
        break;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addBattleChoice(battle, name, isMonster = false) {&lt;br /&gt;
  function createOption(text, vnum) {&lt;br /&gt;
    var option = document.createElement(&amp;quot;option&amp;quot;);&lt;br /&gt;
    option.textContent = text;&lt;br /&gt;
    option.value = vnum;&lt;br /&gt;
&lt;br /&gt;
    if (!isMonster) {&lt;br /&gt;
      option.classList.add(&amp;quot;notranslate&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return option;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var vnum = name;&lt;br /&gt;
&lt;br /&gt;
  if (isMonster) {&lt;br /&gt;
    name = getMonsterName(name);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (isMonster &amp;amp;&amp;amp; monsterData[vnum][1]) {&lt;br /&gt;
    // pass&lt;br /&gt;
  } else {&lt;br /&gt;
    battle.attackerSelection.appendChild(createOption(name, vnum));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  battle.victimSelection.appendChild(createOption(name, vnum));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateBattleChoice(characters, battle) {&lt;br /&gt;
  function addChoices(names, isMonster) {&lt;br /&gt;
    for (var index = 0; index &amp;lt; names.length; index++) {&lt;br /&gt;
      addBattleChoice(battle, names[index], isMonster);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var characterNames = Object.keys(characters.savedCharacters);&lt;br /&gt;
  var monsterNames = Object.keys(characters.savedMonsters);&lt;br /&gt;
&lt;br /&gt;
  addChoices(characterNames, false);&lt;br /&gt;
  addChoices(monsterNames, true);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isPC(character) {&lt;br /&gt;
  if (character.race === 0 || character.race === 1) {&lt;br /&gt;
    return false;&lt;br /&gt;
  }&lt;br /&gt;
  return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isBoss(character) {&lt;br /&gt;
  return character.race === 0 &amp;amp;&amp;amp; character.rank &amp;gt;= 5;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isStone(character) {&lt;br /&gt;
  return character.race === 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isMeleeAttacker(monster) {&lt;br /&gt;
  return monster.attack == 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isRangeAttacker(monster) {&lt;br /&gt;
  return monster.attack == 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isMagicAttacker(monster) {&lt;br /&gt;
  return monster.attack == 2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isMagicClass(character) {&lt;br /&gt;
  return character.race === &amp;quot;shaman&amp;quot; || character.class === &amp;quot;black_magic&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isDispell(character, skillId) {&lt;br /&gt;
  return character.class === &amp;quot;weaponary&amp;quot; &amp;amp;&amp;amp; skillId === 6;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isPolymorph(character) {&lt;br /&gt;
  return isChecked(character.isPolymorph);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isRiding(character) {&lt;br /&gt;
  return isChecked(character.isRiding);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isBow(weaponType) {&lt;br /&gt;
  return weaponType === 2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcAttackFactor(attacker, victim) {&lt;br /&gt;
  function calcCoeffK(dex, level) {&lt;br /&gt;
    return Math.min(90, Math.floor((2 * dex + level) / 3));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var K1 = calcCoeffK(attacker.polymorphDex, attacker.level);&lt;br /&gt;
  var K2 = calcCoeffK(victim.polymorphDex, attacker.level);&lt;br /&gt;
&lt;br /&gt;
  var AR = (K1 + 210) / 300;&lt;br /&gt;
  var ER = (((2 * K2 + 5) / (K2 + 95)) * 3) / 10;&lt;br /&gt;
&lt;br /&gt;
  return truncateNumber(AR - ER, 8);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcMainAttackValue(attacker) {&lt;br /&gt;
  var leadership = 0;&lt;br /&gt;
  var weaponGrowth = 0;&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker)) {&lt;br /&gt;
    weaponGrowth = attacker.weapon.growth;&lt;br /&gt;
    leadership = attacker.leadership;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return 2 * (attacker.level + weaponGrowth) + leadership;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcStatAttackValue(character) {&lt;br /&gt;
  switch (character.race) {&lt;br /&gt;
    case &amp;quot;warrior&amp;quot;:&lt;br /&gt;
    case &amp;quot;sura&amp;quot;:&lt;br /&gt;
      return 2 * character.str;&lt;br /&gt;
    case &amp;quot;ninja&amp;quot;:&lt;br /&gt;
      return Math.floor((1 / 4) * (character.str + 7 * character.dex));&lt;br /&gt;
    case &amp;quot;shaman&amp;quot;:&lt;br /&gt;
      return Math.floor((1 / 3) * (5 * character.int + character.dex));&lt;br /&gt;
    case &amp;quot;lycan&amp;quot;:&lt;br /&gt;
      return character.vit + 2 * character.dex;&lt;br /&gt;
    default:&lt;br /&gt;
      return 2 * character.str;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcSecondaryAttackValue(attacker) {&lt;br /&gt;
  var attackValueOther = 0;&lt;br /&gt;
&lt;br /&gt;
  var minAttackValue = 0;&lt;br /&gt;
  var maxAttackValue = 0;&lt;br /&gt;
&lt;br /&gt;
  var minAttackValueSlash = 0;&lt;br /&gt;
  var maxAttackValueSlash = 0;&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker)) {&lt;br /&gt;
    var { type, isSerpent, minAttackValue, maxAttackValue, growth } =&lt;br /&gt;
      attacker.weapon;&lt;br /&gt;
&lt;br /&gt;
    if (isSerpent) {&lt;br /&gt;
      minAttackValue = attacker.minAttackValueRandom - growth;&lt;br /&gt;
      maxAttackValue = attacker.maxAttackValueRandom - growth;&lt;br /&gt;
&lt;br /&gt;
      minAttackValue = Math.max(0, minAttackValue);&lt;br /&gt;
      maxAttackValue = Math.max(minAttackValue, maxAttackValue);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    minAttackValueSlash = Math.min(&lt;br /&gt;
      attacker.minAttackValueSlash,&lt;br /&gt;
      attacker.maxAttackValueSlash&lt;br /&gt;
    );&lt;br /&gt;
    maxAttackValueSlash = Math.max(&lt;br /&gt;
      attacker.minAttackValueSlash,&lt;br /&gt;
      attacker.maxAttackValueSlash&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    attackValueOther += attacker.attackValue;&lt;br /&gt;
&lt;br /&gt;
    if (isBow(type) &amp;amp;&amp;amp; !isPolymorph(attacker)) {&lt;br /&gt;
      attackValueOther += 25;&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    minAttackValue = attacker.minAttackValue;&lt;br /&gt;
    maxAttackValue = attacker.maxAttackValue;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  minAttackValue += attacker.minAttackValuePolymorph;&lt;br /&gt;
  maxAttackValue += attacker.maxAttackValuePolymorph;&lt;br /&gt;
&lt;br /&gt;
  attackValueOther += attacker.statAttackValue;&lt;br /&gt;
  attackValueOther += attacker.horseAttackValue;&lt;br /&gt;
&lt;br /&gt;
  var weaponInterval = maxAttackValue - minAttackValue + 1;&lt;br /&gt;
  var slashInterval = maxAttackValueSlash - minAttackValueSlash + 1;&lt;br /&gt;
&lt;br /&gt;
  var totalCardinal = weaponInterval * slashInterval * 1_000_000;&lt;br /&gt;
  var minInterval = Math.min(weaponInterval, slashInterval);&lt;br /&gt;
&lt;br /&gt;
  minAttackValue += minAttackValueSlash;&lt;br /&gt;
  maxAttackValue += maxAttackValueSlash;&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    minAttackValue: minAttackValue,&lt;br /&gt;
    maxAttackValue: maxAttackValue,&lt;br /&gt;
    attackValueOther: attackValueOther,&lt;br /&gt;
    totalCardinal: totalCardinal,&lt;br /&gt;
    weights: calcWeights(minAttackValue, maxAttackValue, minInterval),&lt;br /&gt;
    possibleDamagesCount: maxAttackValue - minAttackValue + 1,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcMagicAttackValue(attacker) {&lt;br /&gt;
  var minMagicAttackValueSlash = 0;&lt;br /&gt;
  var maxMagicAttackValueSlash = 0;&lt;br /&gt;
&lt;br /&gt;
  var { isSerpent, minMagicAttackValue, maxMagicAttackValue, growth } = attacker.weapon;&lt;br /&gt;
&lt;br /&gt;
  if (isSerpent) {&lt;br /&gt;
    minMagicAttackValue = attacker.minMagicAttackValueRandom;&lt;br /&gt;
    maxMagicAttackValue = attacker.maxMagicAttackValueRandom;&lt;br /&gt;
&lt;br /&gt;
    maxMagicAttackValue = Math.max(minMagicAttackValue, maxMagicAttackValue);&lt;br /&gt;
  } else {&lt;br /&gt;
    minMagicAttackValue += growth;&lt;br /&gt;
    maxMagicAttackValue += growth;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  minMagicAttackValueSlash = Math.min(&lt;br /&gt;
    attacker.minMagicAttackValueSlash,&lt;br /&gt;
    attacker.maxMagicAttackValueSlash&lt;br /&gt;
  );&lt;br /&gt;
  maxMagicAttackValueSlash = Math.max(&lt;br /&gt;
    attacker.minMagicAttackValueSlash,&lt;br /&gt;
    attacker.maxMagicAttackValueSlash&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  var weaponInterval = maxMagicAttackValue - minMagicAttackValue + 1;&lt;br /&gt;
  var slashInterval = maxMagicAttackValueSlash - minMagicAttackValueSlash + 1;&lt;br /&gt;
&lt;br /&gt;
  var totalCardinal = weaponInterval * slashInterval * 1_000_000;&lt;br /&gt;
  var minInterval = Math.min(weaponInterval, slashInterval);&lt;br /&gt;
&lt;br /&gt;
  minMagicAttackValue += minMagicAttackValueSlash;&lt;br /&gt;
  maxMagicAttackValue += maxMagicAttackValueSlash;&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    minMagicAttackValue: minMagicAttackValue,&lt;br /&gt;
    maxMagicAttackValue: maxMagicAttackValue,&lt;br /&gt;
    magicAttackValueAugmentation: getMagicAttackValueAugmentation(&lt;br /&gt;
      minMagicAttackValue,&lt;br /&gt;
      maxMagicAttackValue,&lt;br /&gt;
      attacker.magicAttackValue&lt;br /&gt;
    ),&lt;br /&gt;
    totalCardinal: totalCardinal,&lt;br /&gt;
    weights: calcWeights(minMagicAttackValue, maxMagicAttackValue, minInterval),&lt;br /&gt;
    possibleDamagesCount: maxMagicAttackValue - minMagicAttackValue + 1,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getPolymorphPower(polymorphPoint, polymorphPowerTable) {&lt;br /&gt;
  return polymorphPowerTable[polymorphPoint];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSkillPower(skillPoint, skillPowerTable) {&lt;br /&gt;
  return skillPowerTable[skillPoint];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getMarriageBonusValue(character, marriageTable, itemName) {&lt;br /&gt;
  var index;&lt;br /&gt;
  var lovePoint = character.lovePoint;&lt;br /&gt;
&lt;br /&gt;
  if (lovePoint &amp;lt; 65) {&lt;br /&gt;
    index = 0;&lt;br /&gt;
  } else if (lovePoint &amp;lt; 80) {&lt;br /&gt;
    index = 1;&lt;br /&gt;
  } else if (lovePoint &amp;lt; 100) {&lt;br /&gt;
    index = 2;&lt;br /&gt;
  } else {&lt;br /&gt;
    index = 3;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return marriageTable[itemName][index];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcDamageWithPrimaryBonuses(damages, bonusValues) {&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.attackValueCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  damages += bonusValues.attackValueMarriage;&lt;br /&gt;
&lt;br /&gt;
  damages = Math.floor(&lt;br /&gt;
    (damages * bonusValues.monsterResistanceMarriageCoeff) / 100&lt;br /&gt;
  );&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.monsterResistanceCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  damages += Math.floor((damages * bonusValues.typeBonusCoeff) / 100);&lt;br /&gt;
  damages +=&lt;br /&gt;
    Math.floor((damages * bonusValues.raceBonusCoeff) / 100) -&lt;br /&gt;
    Math.floor((damages * bonusValues.raceResistanceCoeff) / 100);&lt;br /&gt;
  damages += Math.floor((damages * bonusValues.stoneBonusCoeff) / 100);&lt;br /&gt;
  damages += Math.floor((damages * bonusValues.monsterBonusCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  var elementBonusCoeff = bonusValues.elementBonusCoeff;&lt;br /&gt;
&lt;br /&gt;
  damages +=&lt;br /&gt;
    Math.trunc((damages * elementBonusCoeff[0]) / 10000) +&lt;br /&gt;
    Math.trunc((damages * elementBonusCoeff[1]) / 10000) +&lt;br /&gt;
    Math.trunc((damages * elementBonusCoeff[2]) / 10000) +&lt;br /&gt;
    Math.trunc((damages * elementBonusCoeff[3]) / 10000) +&lt;br /&gt;
    Math.trunc((damages * elementBonusCoeff[4]) / 10000) +&lt;br /&gt;
    Math.trunc((damages * elementBonusCoeff[5]) / 10000);&lt;br /&gt;
&lt;br /&gt;
  damages = Math.floor(damages * bonusValues.damageMultiplier);&lt;br /&gt;
&lt;br /&gt;
  return damages;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcDamageWithSecondaryBonuses(&lt;br /&gt;
  damages,&lt;br /&gt;
  bonusValues,&lt;br /&gt;
  damagesType,&lt;br /&gt;
  minPiercingDamages,&lt;br /&gt;
  damagesWithPrimaryBonuses&lt;br /&gt;
) {&lt;br /&gt;
  damages = Math.floor(damages * bonusValues.magicResistanceCoeff);&lt;br /&gt;
  damages = Math.trunc((damages * bonusValues.weaponDefenseCoeff) / 100);&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.tigerStrengthCoeff) / 100);&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.blessingBonusCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  if (damagesType.criticalHit) {&lt;br /&gt;
    damages *= 2;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (damagesType.piercingHit) {&lt;br /&gt;
    damages += bonusValues.defenseBoost + Math.min(0, minPiercingDamages);&lt;br /&gt;
    damages += Math.floor(&lt;br /&gt;
      (damagesWithPrimaryBonuses * bonusValues.extraPiercingHitCoeff) / 1000&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.averageDamageCoeff) / 100);&lt;br /&gt;
  damages = Math.floor(&lt;br /&gt;
    (damages * bonusValues.averageDamageResistanceCoeff) / 100&lt;br /&gt;
  );&lt;br /&gt;
  damages = Math.floor(&lt;br /&gt;
    (damages * bonusValues.skillDamageResistanceCoeff) / 100&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.rankBonusCoeff) / 100);&lt;br /&gt;
  damages = Math.max(0, damages + bonusValues.defensePercent);&lt;br /&gt;
  damages += Math.min(&lt;br /&gt;
    300,&lt;br /&gt;
    Math.floor((damages * bonusValues.damageBonusCoeff) / 100)&lt;br /&gt;
  );&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.empireMalusCoeff) / 10);&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.sungMaStrBonusCoeff) / 10000);&lt;br /&gt;
  damages -= Math.floor(damages * bonusValues.sungmaStrMalusCoeff);&lt;br /&gt;
&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.whiteDragonElixirCoeff) / 100);&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.steelDragonElixirCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  return damages;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcSkillDamageWithSecondaryBonuses(&lt;br /&gt;
  damages,&lt;br /&gt;
  bonusValues,&lt;br /&gt;
  damagesType,&lt;br /&gt;
  minPiercingDamages&lt;br /&gt;
) {&lt;br /&gt;
  damages = Math.floor(damages * bonusValues.magicResistanceCoeff);&lt;br /&gt;
  damages = Math.trunc((damages * bonusValues.weaponDefenseCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  damages -= bonusValues.defense;&lt;br /&gt;
&lt;br /&gt;
  damages = floorMultiplication(damages, bonusValues.skillWardCoeff);&lt;br /&gt;
  damages = floorMultiplication(damages, bonusValues.skillBonusCoeff);&lt;br /&gt;
&lt;br /&gt;
  var tempDamages = Math.floor(&lt;br /&gt;
    (damages * bonusValues.skillBonusByBonusCoeff) / 100&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  damages = Math.floor(&lt;br /&gt;
    (tempDamages * bonusValues.magicAttackValueCoeff) / 100 + 0.5&lt;br /&gt;
  );&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.tigerStrengthCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  if (damagesType.criticalHit) {&lt;br /&gt;
    damages *= 2;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (damagesType.piercingHit) {&lt;br /&gt;
    damages += bonusValues.defenseBoost + Math.min(0, minPiercingDamages);&lt;br /&gt;
    damages += Math.floor(&lt;br /&gt;
      (tempDamages * bonusValues.extraPiercingHitCoeff) / 1000&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.skillDamageCoeff) / 100);&lt;br /&gt;
  damages = Math.floor(&lt;br /&gt;
    (damages * bonusValues.skillDamageResistanceCoeff) / 100&lt;br /&gt;
  );&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.rankBonusCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  damages = Math.max(0, damages + bonusValues.defensePercent);&lt;br /&gt;
  damages += Math.min(&lt;br /&gt;
    300,&lt;br /&gt;
    Math.floor((damages * bonusValues.damageBonusCoeff) / 100)&lt;br /&gt;
  );&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.empireMalusCoeff) / 10);&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.sungMaStrBonusCoeff) / 10000);&lt;br /&gt;
  damages -= Math.floor(damages * bonusValues.sungmaStrMalusCoeff);&lt;br /&gt;
&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.whiteDragonElixirCoeff) / 100);&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.steelDragonElixirCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  return damages;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function computePolymorphPoint(attacker, victim, polymorphPowerTable) {&lt;br /&gt;
  attacker.statAttackValue = 0;&lt;br /&gt;
&lt;br /&gt;
  attacker.polymorphDex = attacker.dex;&lt;br /&gt;
  victim.polymorphDex = victim.dex;&lt;br /&gt;
&lt;br /&gt;
  attacker.minAttackValuePolymorph = 0;&lt;br /&gt;
  attacker.maxAttackValuePolymorph = 0;&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker) &amp;amp;&amp;amp; isPolymorph(attacker)) {&lt;br /&gt;
    var polymorphPowerPct =&lt;br /&gt;
      getPolymorphPower(attacker.polymorphPoint, polymorphPowerTable) / 100;&lt;br /&gt;
    var polymorphMonster = createMonster(attacker.polymorphMonster);&lt;br /&gt;
&lt;br /&gt;
    var polymorphStr = floorMultiplication(&lt;br /&gt;
      polymorphPowerPct,&lt;br /&gt;
      polymorphMonster.str&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    attacker.polymorphDex += floorMultiplication(&lt;br /&gt;
      polymorphPowerPct,&lt;br /&gt;
      polymorphMonster.dex&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    attacker.minAttackValuePolymorph = floorMultiplication(&lt;br /&gt;
      polymorphPowerPct,&lt;br /&gt;
      polymorphMonster.minAttackValue&lt;br /&gt;
    );&lt;br /&gt;
    attacker.maxAttackValuePolymorph = floorMultiplication(&lt;br /&gt;
      polymorphPowerPct,&lt;br /&gt;
      polymorphMonster.maxAttackValue&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    if (!attacker.weapon) {&lt;br /&gt;
      attacker.maxAttackValuePolymorph += 1;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    attacker.attackValue = 0;&lt;br /&gt;
&lt;br /&gt;
    if (isMagicClass(attacker)) {&lt;br /&gt;
      attacker.statAttackValue = 2 * (polymorphStr + attacker.int);&lt;br /&gt;
    } else {&lt;br /&gt;
      attacker.statAttackValue = 2 * (polymorphStr + attacker.str);&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    attacker.statAttackValue = calcStatAttackValue(attacker);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function computeHorse(attacker) {&lt;br /&gt;
  attacker.horseAttackValue = 0;&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker) &amp;amp;&amp;amp; isRiding(attacker)) {&lt;br /&gt;
    var horseConstant = 30;&lt;br /&gt;
&lt;br /&gt;
    if (attacker.class === &amp;quot;weaponary&amp;quot;) {&lt;br /&gt;
      horseConstant = 60;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    attacker.horseAttackValue = floorMultiplication(&lt;br /&gt;
      2 * attacker.level + attacker.statAttackValue,&lt;br /&gt;
      attacker.horsePoint / horseConstant&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getRankBonus(attacker) {&lt;br /&gt;
  if (!isChecked(attacker.lowRank)) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  switch (attacker.playerRank) {&lt;br /&gt;
    case &amp;quot;aggressive&amp;quot;:&lt;br /&gt;
      return 1;&lt;br /&gt;
    case &amp;quot;fraudulent&amp;quot;:&lt;br /&gt;
      return 2;&lt;br /&gt;
    case &amp;quot;malicious&amp;quot;:&lt;br /&gt;
      return 3;&lt;br /&gt;
    case &amp;quot;cruel&amp;quot;:&lt;br /&gt;
      return 5;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcElementCoeffPvP(elementBonus, mapping, attacker, victim) {&lt;br /&gt;
  var minElementMalus = 0;&lt;br /&gt;
  var maxDifference = 0;&lt;br /&gt;
  var savedElementDifferences = [];&lt;br /&gt;
  var elementBonusIndex = 0;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; elementBonus.length; index++) {&lt;br /&gt;
    if (!attacker[mapping.elementBonus[index]]) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var elementDifference =&lt;br /&gt;
      attacker[mapping.elementBonus[index]] -&lt;br /&gt;
      victim[mapping.elementResistance[index]];&lt;br /&gt;
&lt;br /&gt;
    if (elementDifference &amp;gt;= 0) {&lt;br /&gt;
      elementBonus[elementBonusIndex] = 10 * elementDifference;&lt;br /&gt;
      minElementMalus -= elementDifference;&lt;br /&gt;
      maxDifference = Math.max(maxDifference, elementDifference);&lt;br /&gt;
      elementBonusIndex++;&lt;br /&gt;
    } else {&lt;br /&gt;
      savedElementDifferences.push(elementDifference);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (!savedElementDifferences.length) {&lt;br /&gt;
    return;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  minElementMalus += maxDifference;&lt;br /&gt;
  savedElementDifferences.sort(compareNumbers);&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; savedElementDifferences.length; index++) {&lt;br /&gt;
    var elementDifference = savedElementDifferences[index];&lt;br /&gt;
&lt;br /&gt;
    elementBonus[elementBonusIndex + index] =&lt;br /&gt;
      10 * Math.max(minElementMalus, elementDifference);&lt;br /&gt;
&lt;br /&gt;
    minElementMalus = Math.min(&lt;br /&gt;
      0,&lt;br /&gt;
      Math.max(minElementMalus, minElementMalus - elementDifference)&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function skillChanceReduction(value) {&lt;br /&gt;
  if (value &amp;lt;= 9) {&lt;br /&gt;
    return Math.floor(value / 2);&lt;br /&gt;
  }&lt;br /&gt;
  return 5 + Math.floor((value - 10) / 4);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function magicResistanceToCoeff(magicResistance) {&lt;br /&gt;
  if (magicResistance) {&lt;br /&gt;
    return 2000 / (6 * magicResistance + 1000) - 1;&lt;br /&gt;
  }&lt;br /&gt;
  return 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createBattleValues(attacker, victim, battle, skillType) {&lt;br /&gt;
  var { mapping, constants } = battle;&lt;br /&gt;
  var calcAttackValues;&lt;br /&gt;
&lt;br /&gt;
  var missPercentage = 0;&lt;br /&gt;
  var attackValueMeleeMagic = 0;&lt;br /&gt;
  var attackValueMarriage = 0;&lt;br /&gt;
  var monsterResistanceMarriage = 0;&lt;br /&gt;
  var monsterResistance = 0;&lt;br /&gt;
  var typeBonus = 0;&lt;br /&gt;
  var raceBonus = 0;&lt;br /&gt;
  var raceResistance = 0;&lt;br /&gt;
  var stoneBonus = 0;&lt;br /&gt;
  var monsterBonus = 0;&lt;br /&gt;
  var elementBonus = [0, 0, 0, 0, 0, 0]; // fire, ice, lightning, earth, darkness, wind, order doesn't matter&lt;br /&gt;
  var defenseMarriage = 0;&lt;br /&gt;
  var damageMultiplier = 1;&lt;br /&gt;
  var useDamages = 1;&lt;br /&gt;
  var defense = victim.defense;&lt;br /&gt;
  var defenseBoost = defense;&lt;br /&gt;
  var magicResistance = 0;&lt;br /&gt;
  var weaponDefense = 0;&lt;br /&gt;
  var tigerStrength = 0;&lt;br /&gt;
  var blessingBonus = 0;&lt;br /&gt;
  var magicAttackValueMeleeMagic = 0;&lt;br /&gt;
  var criticalHitPercentage = attacker.criticalHit;&lt;br /&gt;
  var piercingHitPercentage = attacker.piercingHit;&lt;br /&gt;
  var extraPiercingHitPercentage = Math.max(0, piercingHitPercentage - 100);&lt;br /&gt;
  var averageDamage = 0;&lt;br /&gt;
  var averageDamageResistance = 0;&lt;br /&gt;
  var skillDamage = 0;&lt;br /&gt;
  var skillDamageResistance = 0;&lt;br /&gt;
  var rankBonus = 0;&lt;br /&gt;
  var defensePercent = 0;&lt;br /&gt;
  var damageBonus = 0;&lt;br /&gt;
  var empireMalus = 0;&lt;br /&gt;
  var sungMaStrBonus = 0;&lt;br /&gt;
  var sungmaStrMalus = 0;&lt;br /&gt;
  var whiteDragonElixir = 0;&lt;br /&gt;
  var steelDragonElixir = 0;&lt;br /&gt;
&lt;br /&gt;
  computePolymorphPoint(attacker, victim, constants.polymorphPowerTable);&lt;br /&gt;
  computeHorse(attacker);&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker)) {&lt;br /&gt;
    if (weaponData.hasOwnProperty(attacker.weapon)) {&lt;br /&gt;
      attacker.weapon = createWeapon(attacker.weapon);&lt;br /&gt;
    } else {&lt;br /&gt;
      attacker.weapon = createWeapon(0);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    attacker.weapon.getValues(attacker.weaponUpgrade);&lt;br /&gt;
&lt;br /&gt;
    attackValueMeleeMagic =&lt;br /&gt;
      attacker.attackValuePercent + Math.min(100, attacker.attackMeleeMagic);&lt;br /&gt;
&lt;br /&gt;
    var weaponType = attacker.weapon.type;&lt;br /&gt;
&lt;br /&gt;
    if (skillType &amp;amp;&amp;amp; attacker.class === &amp;quot;archery&amp;quot;) {&lt;br /&gt;
      if (weaponType !== 2) {&lt;br /&gt;
        useDamages = 0;&lt;br /&gt;
        weaponType = 2;&lt;br /&gt;
      }&lt;br /&gt;
      defense = 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var weaponDefenseName = mapping.defenseWeapon[weaponType];&lt;br /&gt;
    var weaponDefenseBreakName = mapping.breakWeapon[weaponType];&lt;br /&gt;
&lt;br /&gt;
    if (victim.hasOwnProperty(weaponDefenseName)) {&lt;br /&gt;
      weaponDefense = victim[weaponDefenseName];&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isChecked(attacker.whiteDragonElixir)) {&lt;br /&gt;
      whiteDragonElixir = 10;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isPC(victim)) {&lt;br /&gt;
      if (!skillType) {&lt;br /&gt;
        if (weaponType === 2 &amp;amp;&amp;amp; !isPolymorph(attacker)) {&lt;br /&gt;
          missPercentage = victim.arrowBlock;&lt;br /&gt;
        } else {&lt;br /&gt;
          missPercentage = victim.meleeBlock;&lt;br /&gt;
        }&lt;br /&gt;
        missPercentage +=&lt;br /&gt;
          victim.meleeArrowBlock -&lt;br /&gt;
          (missPercentage * victim.meleeArrowBlock) / 100;&lt;br /&gt;
&lt;br /&gt;
        blessingBonus = calcBlessingBonus(constants.skillPowerTable, victim);&lt;br /&gt;
        averageDamageResistance = victim.averageDamageResistance;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      typeBonus = Math.max(1, attacker.humanBonus - victim.humanResistance);&lt;br /&gt;
      raceBonus = attacker[mapping.raceBonus[victim.race]];&lt;br /&gt;
      raceResistance = victim[mapping.raceResistance[attacker.race]];&lt;br /&gt;
&lt;br /&gt;
      calcElementCoeffPvP(elementBonus, mapping, attacker, victim);&lt;br /&gt;
&lt;br /&gt;
      if (weaponType !== 2 &amp;amp;&amp;amp; attacker.hasOwnProperty(weaponDefenseBreakName)) {&lt;br /&gt;
        weaponDefense -= attacker[weaponDefenseBreakName];&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      criticalHitPercentage = 0;&lt;br /&gt;
    } else {&lt;br /&gt;
      if (isChecked(attacker.isMarried)) {&lt;br /&gt;
        if (isChecked(attacker.loveNecklace)) {&lt;br /&gt;
          attackValueMarriage = getMarriageBonusValue(&lt;br /&gt;
            attacker,&lt;br /&gt;
            constants.marriageTable,&lt;br /&gt;
            &amp;quot;loveNecklace&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isChecked(attacker.loveEarrings)) {&lt;br /&gt;
          criticalHitPercentage += getMarriageBonusValue(&lt;br /&gt;
            attacker,&lt;br /&gt;
            constants.marriageTable,&lt;br /&gt;
            &amp;quot;loveEarrings&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isChecked(attacker.harmonyEarrings)) {&lt;br /&gt;
          piercingHitPercentage += getMarriageBonusValue(&lt;br /&gt;
            attacker,&lt;br /&gt;
            constants.marriageTable,&lt;br /&gt;
            &amp;quot;harmonyEarrings&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (isChecked(attacker.tigerStrength)) {&lt;br /&gt;
        tigerStrength = 40;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      for (var index = 0; index &amp;lt; elementBonus.length; index++) {&lt;br /&gt;
        var elementBonusName = mapping.elementBonus[index];&lt;br /&gt;
        var elementResistanceName = mapping.elementResistance[index];&lt;br /&gt;
&lt;br /&gt;
        if (attacker[elementBonusName] &amp;amp;&amp;amp; victim[elementBonusName]) {&lt;br /&gt;
          elementBonus[index] =&lt;br /&gt;
            50 * (attacker[elementBonusName] - victim[elementResistanceName]);&lt;br /&gt;
        } else {&lt;br /&gt;
          elementBonus[index] = 5 * attacker[elementBonusName];&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      var victimType = victim.type;&lt;br /&gt;
&lt;br /&gt;
      if (victimType !== -1) {&lt;br /&gt;
        typeBonus = attacker[mapping.typeFlag[victimType]];&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      monsterBonus = attacker.monsterBonus;&lt;br /&gt;
&lt;br /&gt;
      if (isStone(victim)) {&lt;br /&gt;
        stoneBonus = attacker.stoneBonus;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (isBoss(victim)) {&lt;br /&gt;
        if (skillType) {&lt;br /&gt;
          skillDamage += attacker.skillBossDamage;&lt;br /&gt;
        } else {&lt;br /&gt;
          averageDamage += attacker.bossDamage;&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (isChecked(attacker.onYohara)) {&lt;br /&gt;
        var sungmaStrDifference = attacker.sungmaStr - attacker.sungmaStrMalus;&lt;br /&gt;
&lt;br /&gt;
        if (sungmaStrDifference &amp;gt;= 0) {&lt;br /&gt;
          sungMaStrBonus = sungmaStrDifference;&lt;br /&gt;
        } else {&lt;br /&gt;
          sungmaStrMalus = 0.5;&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (skillType) {&lt;br /&gt;
      skillDamage += attacker.skillDamage;&lt;br /&gt;
    } else {&lt;br /&gt;
      averageDamage += attacker.averageDamage;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    rankBonus = getRankBonus(attacker);&lt;br /&gt;
    damageBonus = attacker.damageBonus;&lt;br /&gt;
&lt;br /&gt;
    if (isChecked(attacker.empireMalus)) {&lt;br /&gt;
      empireMalus = 1;&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    if (isPC(victim)) {&lt;br /&gt;
      if (isChecked(victim.isMarried)) {&lt;br /&gt;
        if (isChecked(victim.harmonyBracelet)) {&lt;br /&gt;
          monsterResistanceMarriage = getMarriageBonusValue(&lt;br /&gt;
            victim,&lt;br /&gt;
            constants.marriageTable,&lt;br /&gt;
            &amp;quot;harmonyBracelet&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isChecked(victim.harmonyNecklace) &amp;amp;&amp;amp; !skillType) {&lt;br /&gt;
          defenseMarriage = getMarriageBonusValue(&lt;br /&gt;
            victim,&lt;br /&gt;
            constants.marriageTable,&lt;br /&gt;
            &amp;quot;harmonyNecklace&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      monsterResistance = victim.monsterResistance;&lt;br /&gt;
&lt;br /&gt;
      for (var index = 0; index &amp;lt; elementBonus.length; index++) {&lt;br /&gt;
        var elementBonusName = mapping.elementBonus[index];&lt;br /&gt;
        var elementResistanceName = mapping.elementResistance[index];&lt;br /&gt;
&lt;br /&gt;
        if (attacker[elementBonusName]) {&lt;br /&gt;
          elementBonus[index] =&lt;br /&gt;
            80 * (attacker[elementBonusName] - victim[elementResistanceName]);&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (!skillType) {&lt;br /&gt;
        if (isMeleeAttacker(attacker)) {&lt;br /&gt;
          missPercentage = victim.meleeBlock;&lt;br /&gt;
          averageDamageResistance = victim.averageDamageResistance;&lt;br /&gt;
          blessingBonus = calcBlessingBonus(constants.skillPowerTable, victim);&lt;br /&gt;
        } else if (isRangeAttacker(attacker)) {&lt;br /&gt;
          missPercentage = victim.arrowBlock;&lt;br /&gt;
          weaponDefense = victim.arrowDefense;&lt;br /&gt;
          averageDamageResistance = victim.averageDamageResistance;&lt;br /&gt;
          blessingBonus = calcBlessingBonus(constants.skillPowerTable, victim);&lt;br /&gt;
        } else if (isMagicAttacker(attacker)) {&lt;br /&gt;
          missPercentage = victim.arrowBlock;&lt;br /&gt;
          skillDamageResistance = victim.skillDamageResistance;&lt;br /&gt;
          magicResistance = victim.magicResistance;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        missPercentage +=&lt;br /&gt;
          victim.meleeArrowBlock -&lt;br /&gt;
          (missPercentage * victim.meleeArrowBlock) / 100;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    typeBonus = 1;&lt;br /&gt;
    damageMultiplier = attacker.damageMultiplier;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillType) {&lt;br /&gt;
    criticalHitPercentage = skillChanceReduction(criticalHitPercentage);&lt;br /&gt;
    piercingHitPercentage = skillChanceReduction(piercingHitPercentage);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (isPC(victim)) {&lt;br /&gt;
    if (!skillType &amp;amp;&amp;amp; isChecked(victim.biologist70)) {&lt;br /&gt;
      defenseBoost = Math.floor((defenseBoost * 110) / 100);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    criticalHitPercentage = Math.max(&lt;br /&gt;
      0,&lt;br /&gt;
      criticalHitPercentage - victim.criticalHitResistance&lt;br /&gt;
    );&lt;br /&gt;
    piercingHitPercentage = Math.max(&lt;br /&gt;
      0,&lt;br /&gt;
      piercingHitPercentage - victim.piercingHitResistance&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    if (skillType) {&lt;br /&gt;
      skillDamageResistance = victim.skillDamageResistance;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isMagicClass(victim)) {&lt;br /&gt;
      defensePercent = (-2 * victim.magicDefense * victim.defensePercent) / 100;&lt;br /&gt;
    } else {&lt;br /&gt;
      defensePercent = (-2 * defenseBoost * victim.defensePercent) / 100;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isChecked(victim.steelDragonElixir)) {&lt;br /&gt;
      steelDragonElixir = 10;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillType === &amp;quot;magic&amp;quot;) {&lt;br /&gt;
    attackValueMeleeMagic = 0;&lt;br /&gt;
    magicAttackValueMeleeMagic =&lt;br /&gt;
      attacker.attackMagic + Math.min(100, attacker.attackMeleeMagic);&lt;br /&gt;
    attackValueMarriage = 0;&lt;br /&gt;
    defense = 0;&lt;br /&gt;
    if (isDispell(attacker, 6)) {&lt;br /&gt;
      typeBonus = 0;&lt;br /&gt;
      raceBonus = 0;&lt;br /&gt;
      raceResistance = 0;&lt;br /&gt;
      stoneBonus = 0;&lt;br /&gt;
      monsterBonus = 0;&lt;br /&gt;
      for (var index = 0; index &amp;lt; elementBonus.length; index++) {&lt;br /&gt;
        elementBonus[index] = 0;&lt;br /&gt;
      }&lt;br /&gt;
    } else {&lt;br /&gt;
      magicResistance = victim.magicResistance;&lt;br /&gt;
    }&lt;br /&gt;
    weaponDefense = 0;&lt;br /&gt;
    calcAttackValues = calcMagicAttackValue;&lt;br /&gt;
  } else {&lt;br /&gt;
    calcAttackValues = calcSecondaryAttackValue;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  missPercentage = Math.min(100, missPercentage);&lt;br /&gt;
&lt;br /&gt;
  var bonusValues = {&lt;br /&gt;
    missPercentage: missPercentage,&lt;br /&gt;
    weaponBonusCoeff: 1,&lt;br /&gt;
    attackValueCoeff: 100 + attackValueMeleeMagic,&lt;br /&gt;
    attackValueMarriage: attackValueMarriage,&lt;br /&gt;
    monsterResistanceMarriageCoeff: 100 - monsterResistanceMarriage,&lt;br /&gt;
    monsterResistanceCoeff: 100 - monsterResistance,&lt;br /&gt;
    typeBonusCoeff: typeBonus,&lt;br /&gt;
    raceBonusCoeff: raceBonus,&lt;br /&gt;
    raceResistanceCoeff: raceResistance,&lt;br /&gt;
    stoneBonusCoeff: stoneBonus,&lt;br /&gt;
    monsterBonusCoeff: monsterBonus,&lt;br /&gt;
    elementBonusCoeff: elementBonus,&lt;br /&gt;
    damageMultiplier: damageMultiplier,&lt;br /&gt;
    useDamages: useDamages,&lt;br /&gt;
    defense: defense,&lt;br /&gt;
    defenseBoost: defenseBoost,&lt;br /&gt;
    defenseMarriage: defenseMarriage,&lt;br /&gt;
    tigerStrengthCoeff: 100 + tigerStrength,&lt;br /&gt;
    magicResistanceCoeff: magicResistanceToCoeff(magicResistance),&lt;br /&gt;
    weaponDefenseCoeff: 100 - weaponDefense,&lt;br /&gt;
    blessingBonusCoeff: 100 - blessingBonus,&lt;br /&gt;
    magicAttackValueCoeff: 100 + magicAttackValueMeleeMagic,&lt;br /&gt;
    extraPiercingHitCoeff: 5 * extraPiercingHitPercentage,&lt;br /&gt;
    averageDamageCoeff: 100 + averageDamage,&lt;br /&gt;
    averageDamageResistanceCoeff: 100 - Math.min(99, averageDamageResistance),&lt;br /&gt;
    skillDamageCoeff: 100 + skillDamage,&lt;br /&gt;
    skillDamageResistanceCoeff: 100 - Math.min(99, skillDamageResistance),&lt;br /&gt;
    rankBonusCoeff: 100 + rankBonus,&lt;br /&gt;
    defensePercent: Math.floor(defensePercent),&lt;br /&gt;
    damageBonusCoeff: damageBonus,&lt;br /&gt;
    empireMalusCoeff: 10 - empireMalus,&lt;br /&gt;
    sungMaStrBonusCoeff: 10000 + sungMaStrBonus,&lt;br /&gt;
    sungmaStrMalusCoeff: sungmaStrMalus,&lt;br /&gt;
    whiteDragonElixirCoeff: 100 + whiteDragonElixir,&lt;br /&gt;
    steelDragonElixirCoeff: 100 - steelDragonElixir,&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  criticalHitPercentage = Math.min(criticalHitPercentage, 100);&lt;br /&gt;
  piercingHitPercentage = Math.min(piercingHitPercentage, 100);&lt;br /&gt;
&lt;br /&gt;
  var damagesTypeCombinaison = [&lt;br /&gt;
    {&lt;br /&gt;
      criticalHit: false,&lt;br /&gt;
      piercingHit: false,&lt;br /&gt;
      weight:&lt;br /&gt;
        (100 - criticalHitPercentage) *&lt;br /&gt;
        (100 - piercingHitPercentage) *&lt;br /&gt;
        (100 - missPercentage),&lt;br /&gt;
      name: &amp;quot;normalHit&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      criticalHit: true,&lt;br /&gt;
      piercingHit: false,&lt;br /&gt;
      weight:&lt;br /&gt;
        criticalHitPercentage *&lt;br /&gt;
        (100 - piercingHitPercentage) *&lt;br /&gt;
        (100 - missPercentage),&lt;br /&gt;
      name: &amp;quot;criticalHit&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      criticalHit: false,&lt;br /&gt;
      piercingHit: true,&lt;br /&gt;
      weight:&lt;br /&gt;
        (100 - criticalHitPercentage) *&lt;br /&gt;
        piercingHitPercentage *&lt;br /&gt;
        (100 - missPercentage),&lt;br /&gt;
      name: &amp;quot;piercingHit&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      criticalHit: true,&lt;br /&gt;
      piercingHit: true,&lt;br /&gt;
      weight:&lt;br /&gt;
        criticalHitPercentage * piercingHitPercentage * (100 - missPercentage),&lt;br /&gt;
      name: &amp;quot;criticalPiercingHit&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
  ];&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    attacker: attacker,&lt;br /&gt;
    victim: victim,&lt;br /&gt;
    attackFactor: calcAttackFactor(attacker, victim),&lt;br /&gt;
    mainAttackValue: calcMainAttackValue(attacker),&lt;br /&gt;
    attackValues: calcAttackValues(attacker),&lt;br /&gt;
    bonusValues: bonusValues,&lt;br /&gt;
    damagesTypeCombinaison: damagesTypeCombinaison,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateBattleValues(battleValues, skillFormula, skillInfo) {&lt;br /&gt;
  var weaponBonus = 0;&lt;br /&gt;
  var skillWard = 0;&lt;br /&gt;
  var skillBonus = 0;&lt;br /&gt;
  var skillBonusByBonus = 0;&lt;br /&gt;
  var { attacker: attacker, bonusValues: bonusValues } = battleValues;&lt;br /&gt;
  var {&lt;br /&gt;
    range: [minVariation, maxVariation],&lt;br /&gt;
  } = skillInfo;&lt;br /&gt;
  var variationLength = maxVariation - minVariation + 1;&lt;br /&gt;
&lt;br /&gt;
  if (skillInfo.hasOwnProperty(&amp;quot;weaponBonus&amp;quot;)) {&lt;br /&gt;
    var [weaponType, weaponBonusValue] = skillInfo.weaponBonus;&lt;br /&gt;
&lt;br /&gt;
    if (weaponType === attacker.weapon.type) {&lt;br /&gt;
      weaponBonus = weaponBonusValue;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillInfo.skillBonus) {&lt;br /&gt;
    skillBonus = skillInfo.skillBonus;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillInfo.skillWard) {&lt;br /&gt;
    skillWard = skillInfo.skillWard;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillInfo.skillBonusByBonus) {&lt;br /&gt;
    skillBonusByBonus = skillInfo.skillBonusByBonus;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillInfo.removeWeaponReduction) {&lt;br /&gt;
    bonusValues.weaponDefenseCoeff = 100;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  bonusValues.weaponBonusCoeff = 100 + weaponBonus;&lt;br /&gt;
  bonusValues.skillWardCoeff = 1 - skillWard / 100;&lt;br /&gt;
  bonusValues.skillBonusCoeff = 1 + skillBonus / 100;&lt;br /&gt;
  bonusValues.skillBonusByBonusCoeff = 100 + skillBonusByBonus;&lt;br /&gt;
&lt;br /&gt;
  battleValues.skillFormula = skillFormula;&lt;br /&gt;
  battleValues.skillRange = skillInfo.range;&lt;br /&gt;
  battleValues.attackValues.totalCardinal *= variationLength;&lt;br /&gt;
  battleValues.attackValues.possibleDamagesCount *= variationLength;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcWeights(minValue, maxValue, minInterval) {&lt;br /&gt;
  var firstWeightLimit = minValue + minInterval - 1;&lt;br /&gt;
  var lastWeightsLimit = maxValue - minInterval + 1;&lt;br /&gt;
  var weights = [];&lt;br /&gt;
&lt;br /&gt;
  for (var value = minValue; value &amp;lt; firstWeightLimit; value++) {&lt;br /&gt;
    weights.push(value - minValue + 1);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (var value = firstWeightLimit; value &amp;lt;= lastWeightsLimit; value++) {&lt;br /&gt;
    weights.push(minInterval);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (var value = lastWeightsLimit + 1; value &amp;lt;= maxValue; value++) {&lt;br /&gt;
    weights.push(maxValue - value + 1);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return weights;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcBlessingBonus(skillPowerTable, victim) {&lt;br /&gt;
  if (!isChecked(victim.isBlessed)) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var int = victim.intBlessing;&lt;br /&gt;
  var dex = victim.dexBlessing;&lt;br /&gt;
  var skillPower = getSkillPower(victim[&amp;quot;skillBlessing&amp;quot;], skillPowerTable);&lt;br /&gt;
&lt;br /&gt;
  if (!skillPower) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var blessingBonus = floorMultiplication(&lt;br /&gt;
    ((int * 0.3 + 5) * (2 * skillPower + 0.5) + 0.3 * dex) / (skillPower + 2.3),&lt;br /&gt;
    1&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  if (victim.class === &amp;quot;dragon&amp;quot; &amp;amp;&amp;amp; isChecked(ictim.blessingOnself)) {&lt;br /&gt;
    blessingBonus = floorMultiplication(blessingBonus, 1.1);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return blessingBonus;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSkillFormula(battle, skillId, battleValues, removeSkillVariation) {&lt;br /&gt;
  var { attacker, victim, attackFactor } = battleValues;&lt;br /&gt;
  var skillPowerTable = battle.constants.skillPowerTable;&lt;br /&gt;
&lt;br /&gt;
  var skillFormula;&lt;br /&gt;
  var skillInfo = { range: [0, 0] };&lt;br /&gt;
&lt;br /&gt;
  var { class: attackerClass, level: lv, vit, str, int, dex } = attacker;&lt;br /&gt;
&lt;br /&gt;
  if (skillId &amp;lt;= 9) {&lt;br /&gt;
    var skillPower = getSkillPower(&lt;br /&gt;
      attacker[&amp;quot;attackSkill&amp;quot; + skillId],&lt;br /&gt;
      skillPowerTable&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    var improvedBySkillBonus = false;&lt;br /&gt;
    var improvedByBonus = false;&lt;br /&gt;
&lt;br /&gt;
    if (attackerClass === &amp;quot;body&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Triple lacération&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.1 * atk + (0.5 * atk + 1.5 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Moulinet à l'épée&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              3 * atk + (0.8 * atk + 5 * str + 3 * dex + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Accélération&lt;br /&gt;
        case 5:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * atk + (atk + dex * 3 + str * 7 + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Volonté de vivre&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              (3 * atk + (atk + 1.5 * str) * skillPower) * 1.07,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          break;&lt;br /&gt;
        // Tremblement de terre&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              3 * atk +&lt;br /&gt;
              (0.9 * atk + variation + 5 * str + 3 * dex + lv) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;mental&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Attaque de l'esprit&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2.3 * atk + (4 * atk + 4 * str + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Attaque de la paume&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2.3 * atk + (3 * atk + 4 * str + 3 * vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Charge&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * atk + (2 * atk + 2 * dex + 2 * vit + 4 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          break;&lt;br /&gt;
        // Coup d'épée&lt;br /&gt;
        case 5:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * atk + (atk + 3 * dex + 5 * str + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Orbe de l'épée&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              (2 * atk + (2 * atk + 2 * dex + 2 * vit + 4 * str) * skillPower) *&lt;br /&gt;
              1.1,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          break;&lt;br /&gt;
        // Tremblement de terre&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              3 * atk +&lt;br /&gt;
              (0.9 * atk + variation + 5 * str + 3 * dex + lv) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;blade_fight&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Embuscade&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk + (1.2 * atk + variation + 4 * dex + 4 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [1, 50];&lt;br /&gt;
          skillInfo.range = [500, 700];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Attaque rapide&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk + (1.6 * atk + variation + 7 * dex + 7 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [1, 35];&lt;br /&gt;
          skillInfo.range = [200, 300];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Dague filante&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * atk + (0.5 * atk + 9 * dex + 7 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Brume empoisonnée&lt;br /&gt;
        case 5:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * lv + (atk + 3 * str + 18 * dex) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Poison insidieux&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              (2 * lv + (atk + 3 * str + 18 * dex) * skillPower) * 1.1,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          break;&lt;br /&gt;
        // Étoiles brillantes&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk + (1.7 * atk + variation + 6 * dex + 5 * lv) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;archery&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Tir à répétition&lt;br /&gt;
        // case 1:&lt;br /&gt;
        //   skillFormula = function (atk) {&lt;br /&gt;
        //     return floorMultiplication(&lt;br /&gt;
        //       atk + 0.2 * atk * Math.floor(2 + 6 * skillPower) + (0.8 * atk + 8 * dex * attackFactor + 2 * int) * skillPower,&lt;br /&gt;
        //       1&lt;br /&gt;
        //     );&lt;br /&gt;
        //   };&lt;br /&gt;
        //   improvedByBonus = true;&lt;br /&gt;
        //   break;&lt;br /&gt;
        // Pluie de flèches&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk + (1.7 * atk + 5 * dex + str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Flèche de feu&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.5 * atk + (2.6 * atk + 0.9 * int + variation) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [100, 300];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Foulée de plume&lt;br /&gt;
        case 4:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              (3 * dex + 200 + 2 * str + 2 * int) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.removeWeaponReduction = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Flèche empoisonnée&lt;br /&gt;
        case 5:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk +&lt;br /&gt;
              (1.4 * atk + variation + 7 * dex + 4 * str + 4 * int) *&lt;br /&gt;
              skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [100, 200];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Coup étincelant&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              (atk +&lt;br /&gt;
                (1.2 * atk + variation + 6 * dex + 3 * str + 3 * int) *&lt;br /&gt;
                skillPower) *&lt;br /&gt;
              1.2,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [100, 200];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Tir tempête&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.9 * atk + (2.6 * atk + variation) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;weaponary&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Toucher brûlant&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk +&lt;br /&gt;
              2 * lv +&lt;br /&gt;
              2 * int +&lt;br /&gt;
              (2 * atk + 4 * str + 14 * int) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Tourbillon du dragon&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.1 * atk +&lt;br /&gt;
              2 * lv +&lt;br /&gt;
              2 * int +&lt;br /&gt;
              (1.5 * atk + str + 12 * int) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Contre-sort&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              40 +&lt;br /&gt;
              5 * lv +&lt;br /&gt;
              2 * int +&lt;br /&gt;
              (10 * int + 7 * mav + variation) * attackFactor * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [50, 100];&lt;br /&gt;
          break;&lt;br /&gt;
        // Coup démoniaque&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.9 * atk + (2.6 * atk + variation) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;black_magic&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Attaque des ténèbres&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              40 +&lt;br /&gt;
              5 * lv +&lt;br /&gt;
              2 * int +&lt;br /&gt;
              (13 * int + 6 * mav + variation) * attackFactor * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [50, 100];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Attaque de flammes&lt;br /&gt;
        // case 2:&lt;br /&gt;
        //   skillFormula = function (mav, variation) {&lt;br /&gt;
        //     return floorMultiplication(&lt;br /&gt;
        //       5 * lv + 2 * int + (7 * int + 8 * mav + 4 * str + 2 * vit + variation) * skillPower,&lt;br /&gt;
        //       1&lt;br /&gt;
        //     );&lt;br /&gt;
        //   };&lt;br /&gt;
        //   skillInfo.range = [180, 100];&lt;br /&gt;
        //   improvedByBonus = true;&lt;br /&gt;
        //   break;&lt;br /&gt;
        // Esprit de flammes&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              30 +&lt;br /&gt;
              2 * lv +&lt;br /&gt;
              2 * int +&lt;br /&gt;
              (7 * int + 6 * mav + variation) * attackFactor * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [200, 500];&lt;br /&gt;
          break;&lt;br /&gt;
        // Frappe de l'esprit&lt;br /&gt;
        // case 5:&lt;br /&gt;
        //   skillFormula = function (mav, variation) {&lt;br /&gt;
        //     return floorMultiplication(&lt;br /&gt;
        //       40 + 2 * lv + 2 * int + (2 * vit + 2 * dex + 13 * int + 6 * mav + variation) * attackFactor * skillPower,&lt;br /&gt;
        //       1&lt;br /&gt;
        //     );&lt;br /&gt;
        //   };&lt;br /&gt;
        //   skillInfo.range = [180, 200];&lt;br /&gt;
        //   break;&lt;br /&gt;
        // Orbe des ténèbres&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (mav) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              120 +&lt;br /&gt;
              6 * lv +&lt;br /&gt;
              (5 * vit + 5 * dex + 29 * int + 9 * mav) *&lt;br /&gt;
              attackFactor *&lt;br /&gt;
              skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Vague mortelle&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              120 +&lt;br /&gt;
              6 * lv +&lt;br /&gt;
              (5 * vit + 5 * dex + 30 * int + variation + 9 * mav) *&lt;br /&gt;
              attackFactor *&lt;br /&gt;
              skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;dragon&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Talisman volant&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (mav) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              70 +&lt;br /&gt;
              5 * lv +&lt;br /&gt;
              (18 * int + 7 * str + 5 * mav + 50) * attackFactor * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [4, 10];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Dragon chassant&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (mav) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              60 +&lt;br /&gt;
              5 * lv +&lt;br /&gt;
              (16 * int + 6 * dex + 6 * mav + 120) *&lt;br /&gt;
              attackFactor *&lt;br /&gt;
              skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [4, 10];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Rugissement du dragon&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (mav) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              70 +&lt;br /&gt;
              3 * lv +&lt;br /&gt;
              (20 * int + 3 * str + 10 * mav + 100) *&lt;br /&gt;
              attackFactor *&lt;br /&gt;
              skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [4, 10];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Météore&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              120 +&lt;br /&gt;
              6 * lv +&lt;br /&gt;
              (5 * vit + 5 * dex + 30 * int + variation + 9 * mav) *&lt;br /&gt;
              attackFactor *&lt;br /&gt;
              skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;heal&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Jet de foudre&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              60 +&lt;br /&gt;
              5 * lv +&lt;br /&gt;
              (8 * int + 2 * dex + 8 * mav + variation) *&lt;br /&gt;
              attackFactor *&lt;br /&gt;
              skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [6, 10];&lt;br /&gt;
          skillInfo.range = [5 * int, 15 * int];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Invocation de foudre&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              40 +&lt;br /&gt;
              4 * lv +&lt;br /&gt;
              (13 * int + 2 * str + 10 * mav + variation) *&lt;br /&gt;
              attackFactor *&lt;br /&gt;
              skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [6, 10];&lt;br /&gt;
          skillInfo.range = [5 * int, 16 * int];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Griffe de foudre&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              50 +&lt;br /&gt;
              5 * lv +&lt;br /&gt;
              (8 * int + 2 * str + 8 * mav + variation) *&lt;br /&gt;
              attackFactor *&lt;br /&gt;
              skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 800];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;lycan&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Déchiqueter&lt;br /&gt;
        // case 1:&lt;br /&gt;
        //   skillFormula = function (atk) {&lt;br /&gt;
        //     return floorMultiplication(&lt;br /&gt;
        //       1.1 * atk + (0.3 * atk + 1.5 * str) * skillPower,&lt;br /&gt;
        //       1&lt;br /&gt;
        //     );&lt;br /&gt;
        //   };&lt;br /&gt;
        //   skillInfo.weaponBonus = [5, 54];&lt;br /&gt;
        //   improvedByBonus = true;&lt;br /&gt;
        //   break;&lt;br /&gt;
        // Souffle de loup&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * atk + (atk + 3 * dex + 5 * str + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [5, 35];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Bond de loup&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk + (1.6 * atk + 200 + 7 * dex + 7 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [5, 35];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Griffe de loup&lt;br /&gt;
        case 4:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              3 * atk + (0.8 * atk + 6 * str + 2 * dex + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Tempête cinglante&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.8 * atk +&lt;br /&gt;
              (atk + 6 * dex + variation + 3 * str + lv) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
    if (improvedBySkillBonus) {&lt;br /&gt;
      skillInfo.skillBonus =&lt;br /&gt;
        16 * getSkillPower(attacker.skillBonus, skillPowerTable);&lt;br /&gt;
&lt;br /&gt;
      var skillWardChoice = victim.skillWardChoice;&lt;br /&gt;
&lt;br /&gt;
      if (skillWardChoice &amp;amp;&amp;amp; skillWardChoice === attackerClass) {&lt;br /&gt;
        skillInfo.skillWard =&lt;br /&gt;
          24 * getSkillPower(victim.skillWard, skillPowerTable);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (improvedByBonus) {&lt;br /&gt;
      skillInfo.skillBonusByBonus = attacker[&amp;quot;skillBonus&amp;quot; + skillId];&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (removeSkillVariation) {&lt;br /&gt;
      var averageVariation = (skillInfo.range[0] + skillInfo.range[0]) / 2;&lt;br /&gt;
      skillInfo.range = [averageVariation, averageVariation];&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    var skillPower = getSkillPower(&lt;br /&gt;
      attacker[&amp;quot;horseSkill&amp;quot; + skillId],&lt;br /&gt;
      skillPowerTable&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    switch (skillId) {&lt;br /&gt;
      // Combat équestre&lt;br /&gt;
      case 137:&lt;br /&gt;
        skillFormula = function (atk) {&lt;br /&gt;
          return floorMultiplication(atk + 2 * atk * skillPower, 1);&lt;br /&gt;
        };&lt;br /&gt;
        break;&lt;br /&gt;
      // Charge à cheval&lt;br /&gt;
      case 138:&lt;br /&gt;
        skillFormula = function (atk) {&lt;br /&gt;
          return floorMultiplication(&lt;br /&gt;
            2.4 * (200 + 1.5 * lv) + 600 * skillPower,&lt;br /&gt;
            1&lt;br /&gt;
          );&lt;br /&gt;
        };&lt;br /&gt;
        break;&lt;br /&gt;
      // Vague de Pouvoir&lt;br /&gt;
      case 139:&lt;br /&gt;
        skillFormula = function (atk) {&lt;br /&gt;
          return floorMultiplication(&lt;br /&gt;
            2 * (200 + 1.5 * lv) + 600 * skillPower,&lt;br /&gt;
            1&lt;br /&gt;
          );&lt;br /&gt;
        };&lt;br /&gt;
        break;&lt;br /&gt;
      // Grêle de flèches&lt;br /&gt;
      case 140:&lt;br /&gt;
        skillFormula = function (atk) {&lt;br /&gt;
          return floorMultiplication(atk + 2 * atk * skillPower, 1);&lt;br /&gt;
        };&lt;br /&gt;
        break;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  updateBattleValues(battleValues, skillFormula, skillInfo);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcMagicAttackValueAugmentation(&lt;br /&gt;
  magicAttackValueWeapon,&lt;br /&gt;
  magicAttackValueBonus&lt;br /&gt;
) {&lt;br /&gt;
  if (magicAttackValueBonus) {&lt;br /&gt;
    return Math.max(&lt;br /&gt;
      1,&lt;br /&gt;
      0.0025056 *&lt;br /&gt;
      magicAttackValueBonus ** 0.602338 *&lt;br /&gt;
      magicAttackValueWeapon ** 1.20476&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
  return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getMagicAttackValueAugmentation(&lt;br /&gt;
  minMagicAttackValue,&lt;br /&gt;
  maxMagicAttackValue,&lt;br /&gt;
  magicAttackValueBonus&lt;br /&gt;
) {&lt;br /&gt;
  var magicAttackValueAugmentation = [];&lt;br /&gt;
&lt;br /&gt;
  for (&lt;br /&gt;
    var magicAttackValue = minMagicAttackValue;&lt;br /&gt;
    magicAttackValue &amp;lt;= maxMagicAttackValue;&lt;br /&gt;
    magicAttackValue++&lt;br /&gt;
  ) {&lt;br /&gt;
    magicAttackValueAugmentation.push(&lt;br /&gt;
      calcMagicAttackValueAugmentation(magicAttackValue, magicAttackValueBonus)&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return magicAttackValueAugmentation;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcPhysicalDamages(battleValues) {&lt;br /&gt;
  var {&lt;br /&gt;
    attackFactor,&lt;br /&gt;
    mainAttackValue,&lt;br /&gt;
    attackValues: { minAttackValue, maxAttackValue, attackValueOther, weights },&lt;br /&gt;
    bonusValues,&lt;br /&gt;
    damagesTypeCombinaison,&lt;br /&gt;
  } = battleValues;&lt;br /&gt;
&lt;br /&gt;
  var damagesWeightedByType = {};&lt;br /&gt;
&lt;br /&gt;
  if (bonusValues.missPercentage) {&lt;br /&gt;
    damagesWeightedByType.miss = bonusValues.missPercentage / 100;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (var damagesType of damagesTypeCombinaison) {&lt;br /&gt;
    if (!damagesType.weight) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var damagesWeighted = {};&lt;br /&gt;
    damagesWeightedByType[damagesType.name] = damagesWeighted;&lt;br /&gt;
&lt;br /&gt;
    for (&lt;br /&gt;
      var attackValue = minAttackValue;&lt;br /&gt;
      attackValue &amp;lt;= maxAttackValue;&lt;br /&gt;
      attackValue++&lt;br /&gt;
    ) {&lt;br /&gt;
      var weight = weights[attackValue - minAttackValue] * damagesType.weight;&lt;br /&gt;
&lt;br /&gt;
      var secondaryAttackValue = 2 * attackValue + attackValueOther;&lt;br /&gt;
      var rawDamages =&lt;br /&gt;
        mainAttackValue +&lt;br /&gt;
        floorMultiplication(attackFactor, secondaryAttackValue);&lt;br /&gt;
&lt;br /&gt;
      var damagesWithPrimaryBonuses = calcDamageWithPrimaryBonuses(&lt;br /&gt;
        rawDamages,&lt;br /&gt;
        bonusValues&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      var minPiercingDamages =&lt;br /&gt;
        damagesWithPrimaryBonuses -&lt;br /&gt;
        bonusValues.defenseBoost +&lt;br /&gt;
        bonusValues.defenseMarriage;&lt;br /&gt;
&lt;br /&gt;
      if (minPiercingDamages &amp;lt;= 2) {&lt;br /&gt;
        for (var damages = 1; damages &amp;lt;= 5; damages++) {&lt;br /&gt;
          var finalDamages = calcDamageWithSecondaryBonuses(&lt;br /&gt;
            damages,&lt;br /&gt;
            bonusValues,&lt;br /&gt;
            damagesType,&lt;br /&gt;
            minPiercingDamages,&lt;br /&gt;
            damagesWithPrimaryBonuses&lt;br /&gt;
          );&lt;br /&gt;
&lt;br /&gt;
          addKeyValue(damagesWeighted, finalDamages, weight / 5);&lt;br /&gt;
        }&lt;br /&gt;
      } else {&lt;br /&gt;
        var finalDamages = calcDamageWithSecondaryBonuses(&lt;br /&gt;
          minPiercingDamages,&lt;br /&gt;
          bonusValues,&lt;br /&gt;
          damagesType,&lt;br /&gt;
          minPiercingDamages,&lt;br /&gt;
          damagesWithPrimaryBonuses&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        addKeyValue(damagesWeighted, finalDamages, weight);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return damagesWeightedByType;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcPhysicalSkillDamages(battleValues) {&lt;br /&gt;
  var {&lt;br /&gt;
    attackFactor,&lt;br /&gt;
    mainAttackValue,&lt;br /&gt;
    attackValues: { minAttackValue, maxAttackValue, attackValueOther, weights },&lt;br /&gt;
    bonusValues,&lt;br /&gt;
    damagesTypeCombinaison,&lt;br /&gt;
    skillFormula,&lt;br /&gt;
    skillRange: [minVariation, maxVariation],&lt;br /&gt;
  } = battleValues;&lt;br /&gt;
&lt;br /&gt;
  var damagesWeightedByType = {};&lt;br /&gt;
&lt;br /&gt;
  for (var damagesType of damagesTypeCombinaison) {&lt;br /&gt;
    if (!damagesType.weight) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var damagesWeighted = {};&lt;br /&gt;
    var savedDamages = {};&lt;br /&gt;
&lt;br /&gt;
    damagesWeightedByType[damagesType.name] = damagesWeighted;&lt;br /&gt;
&lt;br /&gt;
    for (&lt;br /&gt;
      var attackValue = minAttackValue;&lt;br /&gt;
      attackValue &amp;lt;= maxAttackValue;&lt;br /&gt;
      attackValue++&lt;br /&gt;
    ) {&lt;br /&gt;
      var weight = weights[attackValue - minAttackValue] * damagesType.weight;&lt;br /&gt;
&lt;br /&gt;
      var secondaryAttackValue = 2 * attackValue + attackValueOther;&lt;br /&gt;
      var rawDamages =&lt;br /&gt;
        mainAttackValue +&lt;br /&gt;
        floorMultiplication(attackFactor, secondaryAttackValue);&lt;br /&gt;
&lt;br /&gt;
      var damagesWithPrimaryBonuses = calcDamageWithPrimaryBonuses(&lt;br /&gt;
        rawDamages,&lt;br /&gt;
        bonusValues&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      for (&lt;br /&gt;
        var variation = minVariation;&lt;br /&gt;
        variation &amp;lt;= maxVariation;&lt;br /&gt;
        variation++&lt;br /&gt;
      ) {&lt;br /&gt;
        if (damagesWithPrimaryBonuses &amp;lt;= 2) {&lt;br /&gt;
          for (var damages = 1; damages &amp;lt;= 5; damages++) {&lt;br /&gt;
            damages *= bonusValues.useDamages;&lt;br /&gt;
&lt;br /&gt;
            var damagesWithFormula = skillFormula(damages, variation);&lt;br /&gt;
&lt;br /&gt;
            damagesWithFormula = Math.floor(&lt;br /&gt;
              (damagesWithFormula * bonusValues.weaponBonusCoeff) / 100&lt;br /&gt;
            );&lt;br /&gt;
&lt;br /&gt;
            var finalDamages = calcSkillDamageWithSecondaryBonuses(&lt;br /&gt;
              damagesWithFormula,&lt;br /&gt;
              bonusValues,&lt;br /&gt;
              damagesType,&lt;br /&gt;
              damagesWithPrimaryBonuses&lt;br /&gt;
            );&lt;br /&gt;
&lt;br /&gt;
            addKeyValue(damagesWeighted, finalDamages, weight / 5);&lt;br /&gt;
          }&lt;br /&gt;
        } else {&lt;br /&gt;
          damagesWithPrimaryBonuses *= bonusValues.useDamages;&lt;br /&gt;
&lt;br /&gt;
          var damagesWithFormula = skillFormula(&lt;br /&gt;
            damagesWithPrimaryBonuses,&lt;br /&gt;
            variation&lt;br /&gt;
          );&lt;br /&gt;
&lt;br /&gt;
          if (savedDamages.hasOwnProperty(damagesWithFormula)) {&lt;br /&gt;
            var finalDamages = savedDamages[damagesWithFormula];&lt;br /&gt;
            damagesWeighted[finalDamages] += weight;&lt;br /&gt;
            continue;&lt;br /&gt;
          }&lt;br /&gt;
&lt;br /&gt;
          var finalDamages = Math.floor(&lt;br /&gt;
            (damagesWithFormula * bonusValues.weaponBonusCoeff) / 100&lt;br /&gt;
          );&lt;br /&gt;
&lt;br /&gt;
          finalDamages = calcSkillDamageWithSecondaryBonuses(&lt;br /&gt;
            finalDamages,&lt;br /&gt;
            bonusValues,&lt;br /&gt;
            damagesType,&lt;br /&gt;
            damagesWithPrimaryBonuses&lt;br /&gt;
          );&lt;br /&gt;
&lt;br /&gt;
          savedDamages[damagesWithFormula] = finalDamages;&lt;br /&gt;
          addKeyValue(damagesWeighted, finalDamages, weight);&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return damagesWeightedByType;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcMagicSkillDamages(battleValues) {&lt;br /&gt;
  var {&lt;br /&gt;
    attackValues: {&lt;br /&gt;
      minMagicAttackValue,&lt;br /&gt;
      maxMagicAttackValue,&lt;br /&gt;
      magicAttackValueAugmentation,&lt;br /&gt;
      weights,&lt;br /&gt;
    },&lt;br /&gt;
    bonusValues,&lt;br /&gt;
    damagesTypeCombinaison,&lt;br /&gt;
    skillFormula,&lt;br /&gt;
    skillRange: [minVariation, maxVariation],&lt;br /&gt;
  } = battleValues;&lt;br /&gt;
&lt;br /&gt;
  var damagesWeightedByType = {};&lt;br /&gt;
&lt;br /&gt;
  for (var damagesType of damagesTypeCombinaison) {&lt;br /&gt;
    if (!damagesType.weight) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var damagesWeighted = {};&lt;br /&gt;
    var savedDamages = {};&lt;br /&gt;
&lt;br /&gt;
    damagesWeightedByType[damagesType.name] = damagesWeighted;&lt;br /&gt;
&lt;br /&gt;
    for (&lt;br /&gt;
      var magicAttackValue = minMagicAttackValue;&lt;br /&gt;
      magicAttackValue &amp;lt;= maxMagicAttackValue;&lt;br /&gt;
      magicAttackValue++&lt;br /&gt;
    ) {&lt;br /&gt;
      var index = magicAttackValue - minMagicAttackValue;&lt;br /&gt;
      var weight = weights[index] * damagesType.weight;&lt;br /&gt;
&lt;br /&gt;
      for (&lt;br /&gt;
        var variation = minVariation;&lt;br /&gt;
        variation &amp;lt;= maxVariation;&lt;br /&gt;
        variation++&lt;br /&gt;
      ) {&lt;br /&gt;
        var rawDamages = skillFormula(&lt;br /&gt;
          magicAttackValue + magicAttackValueAugmentation[index],&lt;br /&gt;
          variation&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        if (savedDamages.hasOwnProperty(rawDamages)) {&lt;br /&gt;
          var finalDamages = savedDamages[rawDamages];&lt;br /&gt;
          damagesWeighted[finalDamages] += weight;&lt;br /&gt;
          continue;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var damagesWithPrimaryBonuses = Math.floor(&lt;br /&gt;
          (rawDamages * bonusValues.weaponBonusCoeff) / 100&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        damagesWithPrimaryBonuses = calcDamageWithPrimaryBonuses(&lt;br /&gt;
          damagesWithPrimaryBonuses,&lt;br /&gt;
          bonusValues&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        if (damagesWithPrimaryBonuses &amp;lt;= 2) {&lt;br /&gt;
          for (var damages = 1; damages &amp;lt;= 5; damages++) {&lt;br /&gt;
            var finalDamages = calcSkillDamageWithSecondaryBonuses(&lt;br /&gt;
              damages,&lt;br /&gt;
              bonusValues,&lt;br /&gt;
              damagesType,&lt;br /&gt;
              damagesWithPrimaryBonuses&lt;br /&gt;
            );&lt;br /&gt;
            addKeyValue(damagesWeighted, finalDamages, weight / 5);&lt;br /&gt;
          }&lt;br /&gt;
        } else {&lt;br /&gt;
          var finalDamages = calcSkillDamageWithSecondaryBonuses(&lt;br /&gt;
            damagesWithPrimaryBonuses,&lt;br /&gt;
            bonusValues,&lt;br /&gt;
            damagesType,&lt;br /&gt;
            damagesWithPrimaryBonuses&lt;br /&gt;
          );&lt;br /&gt;
&lt;br /&gt;
          savedDamages[rawDamages] = finalDamages;&lt;br /&gt;
          addKeyValue(damagesWeighted, finalDamages, weight);&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return damagesWeightedByType;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcDamages(&lt;br /&gt;
  attacker,&lt;br /&gt;
  victim,&lt;br /&gt;
  attackType,&lt;br /&gt;
  battle,&lt;br /&gt;
  removeSkillVariation&lt;br /&gt;
) {&lt;br /&gt;
  var damagesCalculator, skillId, skillType;&lt;br /&gt;
&lt;br /&gt;
  if (attackType === &amp;quot;physical&amp;quot;) {&lt;br /&gt;
    damagesCalculator = calcPhysicalDamages;&lt;br /&gt;
  } else if (attackType.startsWith(&amp;quot;attackSkill&amp;quot;)) {&lt;br /&gt;
    skillId = Number(attackType.split(&amp;quot;attackSkill&amp;quot;)[1]);&lt;br /&gt;
&lt;br /&gt;
    if (isMagicClass(attacker) || isDispell(attacker, skillId)) {&lt;br /&gt;
      skillType = &amp;quot;magic&amp;quot;;&lt;br /&gt;
      damagesCalculator = calcMagicSkillDamages;&lt;br /&gt;
    } else {&lt;br /&gt;
      skillType = &amp;quot;physical&amp;quot;;&lt;br /&gt;
      damagesCalculator = calcPhysicalSkillDamages;&lt;br /&gt;
    }&lt;br /&gt;
  } else if (attackType.startsWith(&amp;quot;horseSkill&amp;quot;)) {&lt;br /&gt;
    skillType = &amp;quot;physical&amp;quot;;&lt;br /&gt;
    skillId = Number(attackType.split(&amp;quot;horseSkill&amp;quot;)[1]);&lt;br /&gt;
    damagesCalculator = calcPhysicalSkillDamages;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var battleValues = createBattleValues(attacker, victim, battle, skillType);&lt;br /&gt;
&lt;br /&gt;
  if (skillId) {&lt;br /&gt;
    getSkillFormula(battle, skillId, battleValues, removeSkillVariation);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var {&lt;br /&gt;
    attackValues: { totalCardinal, possibleDamagesCount },&lt;br /&gt;
  } = battleValues;&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    damagesWeightedByType: damagesCalculator(battleValues),&lt;br /&gt;
    totalCardinal: totalCardinal,&lt;br /&gt;
    possibleDamagesCount: possibleDamagesCount,&lt;br /&gt;
    skillType: skillType,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function damagesWithoutVariation(&lt;br /&gt;
  attacker,&lt;br /&gt;
  victim,&lt;br /&gt;
  attackType,&lt;br /&gt;
  battle,&lt;br /&gt;
  characters&lt;br /&gt;
) {&lt;br /&gt;
  startDamagesTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
  var {&lt;br /&gt;
    damagesWeightedByType,&lt;br /&gt;
    totalCardinal,&lt;br /&gt;
    possibleDamagesCount,&lt;br /&gt;
    skillType,&lt;br /&gt;
  } = calcDamages(attacker, victim, attackType, battle);&lt;br /&gt;
&lt;br /&gt;
  endDamagesTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
  possibleDamagesCount = displayResults(&lt;br /&gt;
    possibleDamagesCount,&lt;br /&gt;
    totalCardinal,&lt;br /&gt;
    damagesWeightedByType,&lt;br /&gt;
    battle,&lt;br /&gt;
    attacker.name,&lt;br /&gt;
    victim.name&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  endDisplayTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
  displayFightInfo(&lt;br /&gt;
    possibleDamagesCount,&lt;br /&gt;
    endDamagesTime - startDamagesTime,&lt;br /&gt;
    endDisplayTime - endDamagesTime,&lt;br /&gt;
    battle&lt;br /&gt;
  );&lt;br /&gt;
  addPotentialErrorInformation(&lt;br /&gt;
    battle.errorInformation,&lt;br /&gt;
    attacker,&lt;br /&gt;
    victim,&lt;br /&gt;
    skillType,&lt;br /&gt;
    characters&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  hideElement(battle.bonusVariationResultContainer);&lt;br /&gt;
  showElement(battle.fightResultContainer);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function damagesWithVariation(&lt;br /&gt;
  attacker,&lt;br /&gt;
  victim,&lt;br /&gt;
  attackType,&lt;br /&gt;
  battle,&lt;br /&gt;
  entity,&lt;br /&gt;
  entityVariation&lt;br /&gt;
) {&lt;br /&gt;
  startTime = performance.now();&lt;br /&gt;
  var damagesByBonus = [];&lt;br /&gt;
  var augmentationByBonus = [];&lt;br /&gt;
  var {&lt;br /&gt;
    bonusVariationMinValue: minVariation,&lt;br /&gt;
    bonusVariationMaxValue: maxVariation,&lt;br /&gt;
  } = entity;&lt;br /&gt;
  var step = Math.ceil((maxVariation - minVariation + 1) / 500);&lt;br /&gt;
  var simulationCount = 0;&lt;br /&gt;
  var simulationTime;&lt;br /&gt;
&lt;br /&gt;
  for (&lt;br /&gt;
    var bonusValue = minVariation;&lt;br /&gt;
    bonusValue &amp;lt;= maxVariation;&lt;br /&gt;
    bonusValue += step&lt;br /&gt;
  ) {&lt;br /&gt;
    entity[entityVariation] = bonusValue;&lt;br /&gt;
&lt;br /&gt;
    var { damagesWeightedByType, totalCardinal } = calcDamages(&lt;br /&gt;
      copyObject(attacker),&lt;br /&gt;
      copyObject(victim),&lt;br /&gt;
      attackType,&lt;br /&gt;
      battle,&lt;br /&gt;
      true&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    var meanDamages = calcMeanDamages(damagesWeightedByType, totalCardinal);&lt;br /&gt;
&lt;br /&gt;
    if (bonusValue === minVariation) {&lt;br /&gt;
      var firstDamages = Math.max(meanDamages, 1e-3);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    damagesByBonus.push({ x: bonusValue, y: meanDamages });&lt;br /&gt;
    augmentationByBonus.push({&lt;br /&gt;
      x: bonusValue,&lt;br /&gt;
      y: meanDamages / firstDamages - 1,&lt;br /&gt;
    });&lt;br /&gt;
    simulationCount++;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  endTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
  battle.damagesByBonus = damagesByBonus.concat(entityVariation);&lt;br /&gt;
&lt;br /&gt;
  addToBonusVariationChart(&lt;br /&gt;
    damagesByBonus,&lt;br /&gt;
    augmentationByBonus,&lt;br /&gt;
    entity.bonusVariationDisplay,&lt;br /&gt;
    battle.bonusVariationChart&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  simulationCount = battle.numberFormats.default.format(simulationCount);&lt;br /&gt;
  simulationTime = battle.numberFormats.second.format(&lt;br /&gt;
    (endTime - startTime) / 1000&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  battle.simulationCounter.textContent = simulationCount;&lt;br /&gt;
  battle.simulationTime.textContent = simulationTime;&lt;br /&gt;
&lt;br /&gt;
  hideElement(battle.fightResultContainer);&lt;br /&gt;
  showElement(battle.bonusVariationResultContainer);&lt;br /&gt;
&lt;br /&gt;
  if (&lt;br /&gt;
    isChecked(attacker.bonusVariationActivation) &amp;amp;&amp;amp;&lt;br /&gt;
    isChecked(victim.bonusVariationActivation)&lt;br /&gt;
  ) {&lt;br /&gt;
    showElement(battle.errorInformation[&amp;quot;attacker-victim-variation&amp;quot;]);&lt;br /&gt;
  } else {&lt;br /&gt;
    hideElement(battle.errorInformation[&amp;quot;attacker-victim-variation&amp;quot;]);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function changeMonsterValues(monster, instance, attacker) {&lt;br /&gt;
  switch (instance) {&lt;br /&gt;
    case &amp;quot;SungMahiTower&amp;quot;:&lt;br /&gt;
      var sungMahiFloor = 1;&lt;br /&gt;
      var sungMahiStep = 1;&lt;br /&gt;
      var rawDefense = 120;&lt;br /&gt;
&lt;br /&gt;
      if (isPC(attacker)) {&lt;br /&gt;
        sungMahiFloor = attacker.sungMahiFloor;&lt;br /&gt;
        sungMahiStep = attacker.sungMahiStep;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (monster.rank === 5) {&lt;br /&gt;
        monster.level = 121;&lt;br /&gt;
        monster.dex = 75;&lt;br /&gt;
        rawDefense += 1;&lt;br /&gt;
      } else if (monster.rank === 6) {&lt;br /&gt;
        monster.level = 123;&lt;br /&gt;
        monster.dex = 75;&lt;br /&gt;
        rawDefense += 1;&lt;br /&gt;
      } else {&lt;br /&gt;
        monster.level = 120;&lt;br /&gt;
        monster.dex = 68;&lt;br /&gt;
      }&lt;br /&gt;
      monster.vit = 100;&lt;br /&gt;
      monster.rawDefense = rawDefense + (sungMahiStep - 1) * 6;&lt;br /&gt;
      monster.fistDefense = 0;&lt;br /&gt;
      monster.swordDefense = 0;&lt;br /&gt;
      monster.twoHandedSwordDefense = 0;&lt;br /&gt;
      monster.daggerDefense = 0;&lt;br /&gt;
      monster.bellDefense = 0;&lt;br /&gt;
      monster.fanDefense = 0;&lt;br /&gt;
      monster.arrowDefense = 0;&lt;br /&gt;
      monster.clawDefense = 0;&lt;br /&gt;
      monster.magicResistance = 0;&lt;br /&gt;
      monster.fireResistance = -20;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  // Alastor&lt;br /&gt;
  if (monster.vnum === 6790) {&lt;br /&gt;
    monster.iceResistance = 0;&lt;br /&gt;
    monster.iceBonus = 0;&lt;br /&gt;
    monster.lightningResistance = -10;&lt;br /&gt;
    monster.lightningBonus = 65;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createWeapon(vnum) {&lt;br /&gt;
  var weapon = copyObject(weaponData[vnum]);&lt;br /&gt;
  var serpentVnums = [360, 380, 1210, 2230, 3250, 5200, 6150, 7330];&lt;br /&gt;
  var weaponValues = weapon[1];&lt;br /&gt;
  var isSerpent = isValueInArray(Number(vnum), serpentVnums);&lt;br /&gt;
  var isSpecial = Array.isArray(weaponValues[0]);&lt;br /&gt;
  var isMagic;&lt;br /&gt;
&lt;br /&gt;
  if (isSpecial) {&lt;br /&gt;
    isMagic = weaponValues[0][1] &amp;gt; 0;&lt;br /&gt;
  } else {&lt;br /&gt;
    isMagic = weaponValues[1] &amp;gt; 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    type: weapon[0],&lt;br /&gt;
    maxUpgrade: weapon[2].length - 1,&lt;br /&gt;
    isSerpent: isSerpent,&lt;br /&gt;
    isMagic: isMagic,&lt;br /&gt;
    getValues: function (upgrade) {&lt;br /&gt;
      var currentWeaponValues = weaponValues;&lt;br /&gt;
&lt;br /&gt;
      if (upgrade === undefined) {&lt;br /&gt;
        // rare bug when weaponUpgrade is deleted&lt;br /&gt;
        console.warn(&amp;quot;WeaponUpgrade is missing.&amp;quot;);&lt;br /&gt;
        upgrade = this.maxUpgrade;&lt;br /&gt;
      }&lt;br /&gt;
      upgrade = Math.min(upgrade, this.maxUpgrade);&lt;br /&gt;
&lt;br /&gt;
      if (isSpecial) {&lt;br /&gt;
        currentWeaponValues = weaponValues[upgrade];&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      this.minAttackValue = currentWeaponValues[2];&lt;br /&gt;
      this.maxAttackValue = currentWeaponValues[3];&lt;br /&gt;
      this.minMagicAttackValue = currentWeaponValues[0];&lt;br /&gt;
      this.maxMagicAttackValue = currentWeaponValues[1];&lt;br /&gt;
      this.growth = weapon[2][upgrade];&lt;br /&gt;
    },&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createMonster(monsterVnum, attacker) {&lt;br /&gt;
  var monsterAttributes = monsterData[monsterVnum];&lt;br /&gt;
&lt;br /&gt;
  var monster = {&lt;br /&gt;
    vnum: Number(monsterVnum),&lt;br /&gt;
    name: monsterAttributes[36],&lt;br /&gt;
    rank: monsterAttributes[0],&lt;br /&gt;
    race: monsterAttributes[1],&lt;br /&gt;
    attack: monsterAttributes[2],&lt;br /&gt;
    level: monsterAttributes[3],&lt;br /&gt;
    type: monsterAttributes[4],&lt;br /&gt;
    str: monsterAttributes[5],&lt;br /&gt;
    dex: monsterAttributes[6],&lt;br /&gt;
    vit: monsterAttributes[7],&lt;br /&gt;
    int: monsterAttributes[8],&lt;br /&gt;
    minAttackValue: monsterAttributes[9],&lt;br /&gt;
    maxAttackValue: monsterAttributes[10],&lt;br /&gt;
    rawDefense: monsterAttributes[11],&lt;br /&gt;
    criticalHit: monsterAttributes[12],&lt;br /&gt;
    piercingHit: monsterAttributes[13],&lt;br /&gt;
    fistDefense: monsterAttributes[14],&lt;br /&gt;
    swordDefense: monsterAttributes[15],&lt;br /&gt;
    twoHandedSwordDefense: monsterAttributes[16],&lt;br /&gt;
    daggerDefense: monsterAttributes[17],&lt;br /&gt;
    bellDefense: monsterAttributes[18],&lt;br /&gt;
    fanDefense: monsterAttributes[19],&lt;br /&gt;
    arrowDefense: monsterAttributes[20],&lt;br /&gt;
    clawDefense: monsterAttributes[21],&lt;br /&gt;
    fireResistance: monsterAttributes[22],&lt;br /&gt;
    lightningResistance: monsterAttributes[23],&lt;br /&gt;
    magicResistance: monsterAttributes[24],&lt;br /&gt;
    windResistance: monsterAttributes[25],&lt;br /&gt;
    lightningBonus: monsterAttributes[26],&lt;br /&gt;
    fireBonus: monsterAttributes[27],&lt;br /&gt;
    iceBonus: monsterAttributes[28],&lt;br /&gt;
    windBonus: monsterAttributes[29],&lt;br /&gt;
    earthBonus: monsterAttributes[30],&lt;br /&gt;
    darknessBonus: monsterAttributes[31],&lt;br /&gt;
    darknessResistance: monsterAttributes[32],&lt;br /&gt;
    iceResistance: monsterAttributes[33],&lt;br /&gt;
    earthResistance: monsterAttributes[34],&lt;br /&gt;
    damageMultiplier: monsterAttributes[35],&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  // monster.instance = 0;&lt;br /&gt;
&lt;br /&gt;
  // if (attacker &amp;amp;&amp;amp; monster.instance === 0) {&lt;br /&gt;
  //   changeMonsterValues(monster, &amp;quot;SungMahiTower&amp;quot;, attacker);&lt;br /&gt;
  // }&lt;br /&gt;
&lt;br /&gt;
  changeMonsterValues(monster);&lt;br /&gt;
&lt;br /&gt;
  monster.defense = monster.rawDefense + monster.level + monster.vit;&lt;br /&gt;
&lt;br /&gt;
  return monster;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addPotentialErrorInformation(&lt;br /&gt;
  errorInformation,&lt;br /&gt;
  attacker,&lt;br /&gt;
  victim,&lt;br /&gt;
  skillType,&lt;br /&gt;
  characters&lt;br /&gt;
) {&lt;br /&gt;
  for (var error of Object.values(errorInformation)) {&lt;br /&gt;
    hideElement(error);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker)) {&lt;br /&gt;
    if (isRiding(attacker)) {&lt;br /&gt;
      if (attacker.horsePoint === 0) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;horse-level&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
      showElement(errorInformation[&amp;quot;horse-stat&amp;quot;]);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isPolymorph(attacker)) {&lt;br /&gt;
      if (attacker.polymorphPoint === 0) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;polymorph-level&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (&lt;br /&gt;
        (attacker.polymorphPoint &amp;lt;= 39 &amp;amp;&amp;amp; attacker.attackValuePercent &amp;lt;= 199) ||&lt;br /&gt;
        (attacker.polymorphPoint === 40 &amp;amp;&amp;amp; attacker.attackValuePercent &amp;lt;= 299)&lt;br /&gt;
      ) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;polymorph-bonus&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
    if (skillType === &amp;quot;magic&amp;quot;) {&lt;br /&gt;
      if (attacker.magicAttackValue) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;magic-attack-value-bonus&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
      if (victim.magicResistance) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;magic-resistance&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    showElement(errorInformation[&amp;quot;monster-attacker&amp;quot;]);&lt;br /&gt;
    if (isMagicAttacker(attacker) &amp;amp;&amp;amp; victim.magicResistance) {&lt;br /&gt;
      showElement(errorInformation[&amp;quot;magic-resistance&amp;quot;]);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (isPC(victim)) {&lt;br /&gt;
    if (isRiding(victim)) {&lt;br /&gt;
      showElement(errorInformation[&amp;quot;horse-stat&amp;quot;]);&lt;br /&gt;
    }&lt;br /&gt;
    if (isPolymorph(victim)) {&lt;br /&gt;
      if (attacker.polymorphPoint === 0) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;polymorph-level&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
      showElement(errorInformation[&amp;quot;polymorph-defense&amp;quot;]);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (characters.unsavedChanges) {&lt;br /&gt;
    showElement(errorInformation[&amp;quot;save&amp;quot;]);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function reduceChartPointsListener(battle) {&lt;br /&gt;
  var {&lt;br /&gt;
    reduceChartPointsContainer,&lt;br /&gt;
    reduceChartPoints,&lt;br /&gt;
    numberFormats: { second: numberFormat },&lt;br /&gt;
    displayTime,&lt;br /&gt;
  } = battle;&lt;br /&gt;
&lt;br /&gt;
  reduceChartPoints.addEventListener(&amp;quot;change&amp;quot;, function () {&lt;br /&gt;
    var startDisplayTime = performance.now();&lt;br /&gt;
    var scatterDataByType = battle.scatterDataByType;&lt;br /&gt;
    var {&lt;br /&gt;
      chart,&lt;br /&gt;
      maxPoints,&lt;br /&gt;
      chart: {&lt;br /&gt;
        data: { datasets },&lt;br /&gt;
      },&lt;br /&gt;
    } = battle.damagesChart;&lt;br /&gt;
    var addAnimations = false;&lt;br /&gt;
&lt;br /&gt;
    for (var index = 0; index &amp;lt; datasets.length; index++) {&lt;br /&gt;
      var dataset = datasets[index];&lt;br /&gt;
      var scatterData = scatterDataByType[dataset.name];&lt;br /&gt;
&lt;br /&gt;
      if (dataset.canBeReduced &amp;amp;&amp;amp; reduceChartPoints.checked) {&lt;br /&gt;
        dataset.data = aggregateDamages(scatterData, maxPoints);&lt;br /&gt;
        addAnimations = true;&lt;br /&gt;
      } else {&lt;br /&gt;
        dataset.data = scatterData;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    handleChartAnimations(chart, addAnimations);&lt;br /&gt;
    chart.update();&lt;br /&gt;
&lt;br /&gt;
    displayTime.textContent = numberFormat.format(&lt;br /&gt;
      (performance.now() - startDisplayTime) / 1000&lt;br /&gt;
    );&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  reduceChartPointsContainer.addEventListener(&amp;quot;pointerup&amp;quot;, function (event) {&lt;br /&gt;
    if (event.pointerType === &amp;quot;mouse&amp;quot;) {&lt;br /&gt;
      reduceChartPoints.click();&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function downloadRawDataListener(battle) {&lt;br /&gt;
  var { downLoadRawData, downLoadRawDataVariation } = battle;&lt;br /&gt;
  var fileType = &amp;quot;text/csv;charset=utf-8;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  downLoadRawData.addEventListener(&amp;quot;click&amp;quot;, function () {&lt;br /&gt;
    var damagesWeightedByType = battle.damagesWeightedByType;&lt;br /&gt;
    var filename = &amp;quot;raw_damages.csv&amp;quot;;&lt;br /&gt;
    var csvContent = &amp;quot;damage,probabilities,damageType\n&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    for (var damagesType in damagesWeightedByType) {&lt;br /&gt;
      var damagesWeighted = damagesWeightedByType[damagesType];&lt;br /&gt;
&lt;br /&gt;
      for (var damages in damagesWeighted) {&lt;br /&gt;
        csvContent +=&lt;br /&gt;
          damages + &amp;quot;,&amp;quot; + damagesWeighted[damages] + &amp;quot;,&amp;quot; + damagesType + &amp;quot;\n&amp;quot;;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    downloadData(csvContent, fileType, filename);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  downLoadRawDataVariation.addEventListener(&amp;quot;click&amp;quot;, function () {&lt;br /&gt;
    var damagesByBonus = battle.damagesByBonus;&lt;br /&gt;
    var damagesByBonusLength = damagesByBonus.length;&lt;br /&gt;
    var filename = &amp;quot;damages_variation.csv&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    if (!damagesByBonusLength) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var csvContent =&lt;br /&gt;
      damagesByBonus[damagesByBonusLength - 1] + &amp;quot;,averageDamage\n&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    for (var index = 0; index &amp;lt; damagesByBonusLength - 1; index++) {&lt;br /&gt;
      var row = damagesByBonus[index];&lt;br /&gt;
&lt;br /&gt;
      csvContent += row.x + &amp;quot;,&amp;quot; + row.y + &amp;quot;\n&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    downloadData(csvContent, fileType, filename);&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function displayResults(&lt;br /&gt;
  possibleDamagesCount,&lt;br /&gt;
  totalCardinal,&lt;br /&gt;
  damagesWeightedByType,&lt;br /&gt;
  battle,&lt;br /&gt;
  attackerName,&lt;br /&gt;
  victimName&lt;br /&gt;
) {&lt;br /&gt;
  var [&lt;br /&gt;
    meanDamages,&lt;br /&gt;
    minDamages,&lt;br /&gt;
    maxDamages,&lt;br /&gt;
    scatterDataByType,&lt;br /&gt;
    possibleDamagesCount,&lt;br /&gt;
    uniqueDamagesCount,&lt;br /&gt;
  ] = prepareDamagesData(&lt;br /&gt;
    damagesWeightedByType,&lt;br /&gt;
    possibleDamagesCount,&lt;br /&gt;
    totalCardinal&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  addToDamagesChart(&lt;br /&gt;
    scatterDataByType,&lt;br /&gt;
    battle.damagesChart,&lt;br /&gt;
    battle.reduceChartPoints.checked&lt;br /&gt;
  );&lt;br /&gt;
  updateDamagesChartDescription(&lt;br /&gt;
    battle.uniqueDamagesCounters,&lt;br /&gt;
    uniqueDamagesCount,&lt;br /&gt;
    battle.numberFormats.default&lt;br /&gt;
  );&lt;br /&gt;
  displayFightResults(&lt;br /&gt;
    battle,&lt;br /&gt;
    attackerName,&lt;br /&gt;
    victimName,&lt;br /&gt;
    meanDamages,&lt;br /&gt;
    minDamages,&lt;br /&gt;
    maxDamages&lt;br /&gt;
  );&lt;br /&gt;
  battle.damagesWeightedByType = damagesWeightedByType;&lt;br /&gt;
  battle.scatterDataByType = scatterDataByType;&lt;br /&gt;
&lt;br /&gt;
  return possibleDamagesCount;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function displayFightResults(&lt;br /&gt;
  battle,&lt;br /&gt;
  attackerName,&lt;br /&gt;
  victimName,&lt;br /&gt;
  meanDamages,&lt;br /&gt;
  minDamages,&lt;br /&gt;
  maxDamages&lt;br /&gt;
) {&lt;br /&gt;
  var {&lt;br /&gt;
    tableResultFight,&lt;br /&gt;
    tableResultHistory,&lt;br /&gt;
    attackTypeSelection,&lt;br /&gt;
    savedFights,&lt;br /&gt;
    numberFormats: { default: numberFormat },&lt;br /&gt;
    deleteFightTemplate,&lt;br /&gt;
  } = battle;&lt;br /&gt;
&lt;br /&gt;
  hideElement(tableResultHistory.rows[1]);&lt;br /&gt;
&lt;br /&gt;
  var valuesToDisplay = [&lt;br /&gt;
    attackerName,&lt;br /&gt;
    victimName,&lt;br /&gt;
    attackTypeSelection.options[attackTypeSelection.selectedIndex].textContent,&lt;br /&gt;
    meanDamages,&lt;br /&gt;
    minDamages,&lt;br /&gt;
    maxDamages,&lt;br /&gt;
  ];&lt;br /&gt;
&lt;br /&gt;
  savedFights.push(valuesToDisplay);&lt;br /&gt;
  updateSavedFights(savedFights);&lt;br /&gt;
&lt;br /&gt;
  editTableResultRow(tableResultFight.rows[1], valuesToDisplay, numberFormat);&lt;br /&gt;
  addRowToTableResultHistory(&lt;br /&gt;
    tableResultHistory,&lt;br /&gt;
    valuesToDisplay,&lt;br /&gt;
    deleteFightTemplate,&lt;br /&gt;
    numberFormat&lt;br /&gt;
  );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function displayFightInfo(&lt;br /&gt;
  possibleDamagesCount,&lt;br /&gt;
  damagesTime,&lt;br /&gt;
  displayTime,&lt;br /&gt;
  battle&lt;br /&gt;
) {&lt;br /&gt;
  var container = battle.possibleDamagesCounter.parentElement;&lt;br /&gt;
&lt;br /&gt;
  if (possibleDamagesCount &amp;lt;= 1) {&lt;br /&gt;
    hideElement(container);&lt;br /&gt;
    return;&lt;br /&gt;
  } else {&lt;br /&gt;
    showElement(container);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  possibleDamagesCount =&lt;br /&gt;
    battle.numberFormats.default.format(possibleDamagesCount);&lt;br /&gt;
  damagesTime = battle.numberFormats.second.format(damagesTime / 1000);&lt;br /&gt;
  displayTime = battle.numberFormats.second.format(displayTime / 1000);&lt;br /&gt;
&lt;br /&gt;
  battle.possibleDamagesCounter.textContent = possibleDamagesCount;&lt;br /&gt;
  battle.damagesTime.textContent = damagesTime;&lt;br /&gt;
  battle.displayTime.textContent = displayTime;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isPseudoSaved(characters, pseudo) {&lt;br /&gt;
  return characters.savedCharacters.hasOwnProperty(pseudo);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createBattle(characters, battle) {&lt;br /&gt;
  battle.battleForm.addEventListener(&amp;quot;submit&amp;quot;, function (event) {&lt;br /&gt;
    event.preventDefault();&lt;br /&gt;
&lt;br /&gt;
    // auto save&lt;br /&gt;
    if (characters.unsavedChanges) {&lt;br /&gt;
      characters.saveButton.click();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var battleInfo = new FormData(event.target);&lt;br /&gt;
    var attackerName = battleInfo.get(&amp;quot;attacker&amp;quot;);&lt;br /&gt;
    var attackType = battleInfo.get(&amp;quot;attackTypeSelection&amp;quot;);&lt;br /&gt;
    var victimName = battleInfo.get(&amp;quot;victim&amp;quot;);&lt;br /&gt;
    var attackerVariation;&lt;br /&gt;
    var victimVariation;&lt;br /&gt;
&lt;br /&gt;
    if (!attackerName &amp;amp;&amp;amp; !attackType &amp;amp;&amp;amp; !victimName) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isPseudoSaved(characters, attackerName)) {&lt;br /&gt;
      var attacker = copyObject(characters.savedCharacters[attackerName]);&lt;br /&gt;
      attackerVariation = attacker.bonusVariation;&lt;br /&gt;
    } else {&lt;br /&gt;
      var attacker = createMonster(attackerName);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isPseudoSaved(characters, victimName)) {&lt;br /&gt;
      var victim = copyObject(characters.savedCharacters[victimName]);&lt;br /&gt;
      victimVariation = victim.bonusVariation;&lt;br /&gt;
    } else {&lt;br /&gt;
      var victim = createMonster(victimName, attacker);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      isChecked(attacker.bonusVariationActivation) &amp;amp;&amp;amp;&lt;br /&gt;
      attacker.hasOwnProperty(attackerVariation) &amp;amp;&amp;amp;&lt;br /&gt;
      attacker.bonusVariationMinValue &amp;lt; attacker.bonusVariationMaxValue&lt;br /&gt;
    ) {&lt;br /&gt;
      damagesWithVariation(&lt;br /&gt;
        attacker,&lt;br /&gt;
        victim,&lt;br /&gt;
        attackType,&lt;br /&gt;
        battle,&lt;br /&gt;
        attacker,&lt;br /&gt;
        attackerVariation&lt;br /&gt;
      );&lt;br /&gt;
    } else if (&lt;br /&gt;
      isChecked(victim.bonusVariationActivation) &amp;amp;&amp;amp;&lt;br /&gt;
      victim.hasOwnProperty(victimVariation) &amp;amp;&amp;amp;&lt;br /&gt;
      victim.bonusVariationMinValue &amp;lt; victim.bonusVariationMaxValue&lt;br /&gt;
    ) {&lt;br /&gt;
      damagesWithVariation(&lt;br /&gt;
        attacker,&lt;br /&gt;
        victim,&lt;br /&gt;
        attackType,&lt;br /&gt;
        battle,&lt;br /&gt;
        victim,&lt;br /&gt;
        victimVariation&lt;br /&gt;
      );&lt;br /&gt;
    } else {&lt;br /&gt;
      damagesWithoutVariation(attacker, victim, attackType, battle, characters);&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createMapping() {&lt;br /&gt;
  mapping = {&lt;br /&gt;
    typeFlag: [&lt;br /&gt;
      &amp;quot;animalBonus&amp;quot;, // 0&lt;br /&gt;
      &amp;quot;humanBonus&amp;quot;, // 1&lt;br /&gt;
      &amp;quot;orcBonus&amp;quot;, // 2&lt;br /&gt;
      &amp;quot;mysticBonus&amp;quot;, // 3&lt;br /&gt;
      &amp;quot;undeadBonus&amp;quot;, // 4&lt;br /&gt;
      &amp;quot;insectBonus&amp;quot;, // 5&lt;br /&gt;
      &amp;quot;desertBonus&amp;quot;, // 6&lt;br /&gt;
      &amp;quot;devilBonus&amp;quot;, // 7&lt;br /&gt;
    ],&lt;br /&gt;
    raceBonus: {&lt;br /&gt;
      warrior: &amp;quot;warriorBonus&amp;quot;,&lt;br /&gt;
      sura: &amp;quot;suraBonus&amp;quot;,&lt;br /&gt;
      ninja: &amp;quot;ninjaBonus&amp;quot;,&lt;br /&gt;
      shaman: &amp;quot;shamanBonus&amp;quot;,&lt;br /&gt;
      lycan: &amp;quot;lycanBonus&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    raceResistance: {&lt;br /&gt;
      warrior: &amp;quot;warriorResistance&amp;quot;,&lt;br /&gt;
      sura: &amp;quot;suraResistance&amp;quot;,&lt;br /&gt;
      ninja: &amp;quot;ninjaResistance&amp;quot;,&lt;br /&gt;
      shaman: &amp;quot;shamanResistance&amp;quot;,&lt;br /&gt;
      lycan: &amp;quot;lycanResistance&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    defenseWeapon: [&lt;br /&gt;
      &amp;quot;swordDefense&amp;quot;, // 0&lt;br /&gt;
      &amp;quot;daggerDefense&amp;quot;, // 1&lt;br /&gt;
      &amp;quot;arrowDefense&amp;quot;, // 2&lt;br /&gt;
      &amp;quot;twoHandedSwordDefense&amp;quot;, // 3&lt;br /&gt;
      &amp;quot;bellDefense&amp;quot;, // 4&lt;br /&gt;
      &amp;quot;clawDefense&amp;quot;, // 5&lt;br /&gt;
      &amp;quot;fanDefense&amp;quot;, // 6&lt;br /&gt;
      &amp;quot;swordDefense&amp;quot;, // 7&lt;br /&gt;
      &amp;quot;fistDefense&amp;quot;, // 8&lt;br /&gt;
    ],&lt;br /&gt;
    breakWeapon: [&lt;br /&gt;
      &amp;quot;breakSwordDefense&amp;quot;, // 0&lt;br /&gt;
      &amp;quot;breakDaggerDefense&amp;quot;, // 1&lt;br /&gt;
      &amp;quot;breakArrowDefense&amp;quot;, // 2&lt;br /&gt;
      &amp;quot;breakTwoHandedSwordDefense&amp;quot;, // 3&lt;br /&gt;
      &amp;quot;breakBellDefense&amp;quot;, // 4&lt;br /&gt;
      &amp;quot;breakClawDefense&amp;quot;, // 5&lt;br /&gt;
      &amp;quot;breakFanDefense&amp;quot;, // 6&lt;br /&gt;
      &amp;quot;breakSwordDefense&amp;quot;, // 7&lt;br /&gt;
    ],&lt;br /&gt;
    elementBonus: [&lt;br /&gt;
      &amp;quot;fireBonus&amp;quot;, // 0&lt;br /&gt;
      &amp;quot;iceBonus&amp;quot;, // 1&lt;br /&gt;
      &amp;quot;windBonus&amp;quot;, // 2&lt;br /&gt;
      &amp;quot;lightningBonus&amp;quot;, // 3&lt;br /&gt;
      &amp;quot;earthBonus&amp;quot;, // 4&lt;br /&gt;
      &amp;quot;darknessBonus&amp;quot;, // 5&lt;br /&gt;
    ],&lt;br /&gt;
    elementResistance: [&lt;br /&gt;
      &amp;quot;fireResistance&amp;quot;, // 0&lt;br /&gt;
      &amp;quot;iceResistance&amp;quot;, // 1&lt;br /&gt;
      &amp;quot;windResistance&amp;quot;, // 2&lt;br /&gt;
      &amp;quot;lightningResistance&amp;quot;, // 3&lt;br /&gt;
      &amp;quot;earthResistance&amp;quot;, // 4&lt;br /&gt;
      &amp;quot;darknessResistance&amp;quot;, // 5&lt;br /&gt;
    ],&lt;br /&gt;
  };&lt;br /&gt;
  return mapping;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createConstants() {&lt;br /&gt;
  var constants = {&lt;br /&gt;
    polymorphPowerTable: [&lt;br /&gt;
      10, 11, 11, 12, 13, 13, 14, 15, 16, 17, 18, 19, 20, 22, 23, 24, 26, 27,&lt;br /&gt;
      29, 31, 33, 35, 37, 39, 41, 44, 46, 49, 52, 55, 59, 62, 66, 70, 74, 79,&lt;br /&gt;
      84, 89, 94, 100, 0,&lt;br /&gt;
    ],&lt;br /&gt;
    skillPowerTable: [&lt;br /&gt;
      0, 0.05, 0.06, 0.08, 0.1, 0.12, 0.14, 0.16, 0.18, 0.2, 0.22, 0.24, 0.26,&lt;br /&gt;
      0.28, 0.3, 0.32, 0.34, 0.36, 0.38, 0.4, 0.5, 0.52, 0.54, 0.56, 0.58, 0.6,&lt;br /&gt;
      0.63, 0.66, 0.69, 0.72, 0.82, 0.85, 0.88, 0.91, 0.94, 0.98, 1.02, 1.06,&lt;br /&gt;
      1.1, 1.15, 1.25,&lt;br /&gt;
    ],&lt;br /&gt;
    marriageTable: {&lt;br /&gt;
      harmonyEarrings: [4, 5, 6, 8],&lt;br /&gt;
      loveEarrings: [4, 5, 6, 8],&lt;br /&gt;
      harmonyBracelet: [4, 5, 6, 8],&lt;br /&gt;
      loveNecklace: [20, 25, 30, 40],&lt;br /&gt;
      harmonyNecklace: [12, 16, 20, 30],&lt;br /&gt;
    },&lt;br /&gt;
    allowedWeaponsPerRace: {&lt;br /&gt;
      warrior: [0, 3, 8],&lt;br /&gt;
      ninja: [0, 1, 2, 8],&lt;br /&gt;
      sura: [0, 7, 8],&lt;br /&gt;
      shaman: [4, 6, 8],&lt;br /&gt;
      lycan: [5, 8],&lt;br /&gt;
    },&lt;br /&gt;
    translation: {&lt;br /&gt;
      fr: {&lt;br /&gt;
        damages: &amp;quot;Dégâts&amp;quot;,&lt;br /&gt;
        percentage: &amp;quot;Pourcentage&amp;quot;,&lt;br /&gt;
        miss: &amp;quot;Miss&amp;quot;,&lt;br /&gt;
        normalHit: &amp;quot;Coup classique&amp;quot;,&lt;br /&gt;
        criticalHit: &amp;quot;Coup critique&amp;quot;,&lt;br /&gt;
        piercingHit: &amp;quot;Coup perçant&amp;quot;,&lt;br /&gt;
        criticalPiercingHit: &amp;quot;Coup critique perçant&amp;quot;,&lt;br /&gt;
        damagesRepartition: &amp;quot;Distribution des dégâts&amp;quot;,&lt;br /&gt;
        averageDamages: &amp;quot;Dégâts moyens&amp;quot;,&lt;br /&gt;
        damagesAugmentation: &amp;quot;Augmentation des dégâts&amp;quot;,&lt;br /&gt;
        bonusVariationTitle: [&lt;br /&gt;
          &amp;quot;Évolution des dégâts moyens&amp;quot;,&lt;br /&gt;
          &amp;quot;par rapport à la valeur d'un bonus&amp;quot;,&lt;br /&gt;
        ],&lt;br /&gt;
      },&lt;br /&gt;
      en: {&lt;br /&gt;
        damages: &amp;quot;Damage&amp;quot;,&lt;br /&gt;
        percentage: &amp;quot;Percentage&amp;quot;,&lt;br /&gt;
        miss: &amp;quot;Miss&amp;quot;,&lt;br /&gt;
        normalHit: &amp;quot;Normal Hit&amp;quot;,&lt;br /&gt;
        criticalHit: &amp;quot;Critical Hit&amp;quot;,&lt;br /&gt;
        piercingHit: &amp;quot;Piercing Hit&amp;quot;,&lt;br /&gt;
        criticalPiercingHit: &amp;quot;Critical Piercing Hit&amp;quot;,&lt;br /&gt;
        damagesRepartition: &amp;quot;Damage Repartition&amp;quot;,&lt;br /&gt;
        averageDamages: &amp;quot;Average Damage&amp;quot;,&lt;br /&gt;
        damagesAugmentation: &amp;quot;Damage Augmentation&amp;quot;,&lt;br /&gt;
        bonusVariationTitle: [&lt;br /&gt;
          &amp;quot;Evolution of Average Damage&amp;quot;,&lt;br /&gt;
          &amp;quot;Relative to a Bonus Value&amp;quot;,&lt;br /&gt;
        ],&lt;br /&gt;
      },&lt;br /&gt;
      tr: {&lt;br /&gt;
        damages: &amp;quot;Hasar&amp;quot;,&lt;br /&gt;
        percentage: &amp;quot;Yüzde&amp;quot;,&lt;br /&gt;
        miss: &amp;quot;Miss Vuruş&amp;quot;,&lt;br /&gt;
        normalHit: &amp;quot;Düz Vuruş&amp;quot;,&lt;br /&gt;
        criticalHit: &amp;quot;Kritik Vuruş&amp;quot;,&lt;br /&gt;
        piercingHit: &amp;quot;Delici Vuruş&amp;quot;,&lt;br /&gt;
        criticalPiercingHit: &amp;quot;Kritikli Delici Vuruş&amp;quot;,&lt;br /&gt;
        damagesRepartition: &amp;quot;Hasar Dağılımı&amp;quot;,&lt;br /&gt;
        averageDamages: &amp;quot;Ortalama Hasar&amp;quot;,&lt;br /&gt;
        damagesAugmentation: &amp;quot;Ortalama Hasar Artışı&amp;quot;,&lt;br /&gt;
        bonusVariationTitle: [&lt;br /&gt;
          &amp;quot;Bir bonusun değerine kıyasla&amp;quot;,&lt;br /&gt;
          &amp;quot;Ortalama Hasar Çizelgesi&amp;quot;,&lt;br /&gt;
        ],&lt;br /&gt;
      },&lt;br /&gt;
      ro: {&lt;br /&gt;
        damages: &amp;quot;Daune&amp;quot;,&lt;br /&gt;
        percentage: &amp;quot;Procent&amp;quot;,&lt;br /&gt;
        miss: &amp;quot;Miss&amp;quot;,&lt;br /&gt;
        normalHit: &amp;quot;Lovitura normala&amp;quot;,&lt;br /&gt;
        criticalHit: &amp;quot;Lovitura critica&amp;quot;,&lt;br /&gt;
        piercingHit: &amp;quot;Lovitura patrunzatoare&amp;quot;,&lt;br /&gt;
        criticalPiercingHit: &amp;quot;Lovitura critica si patrunzatoare&amp;quot;,&lt;br /&gt;
        damagesRepartition: &amp;quot;Distribuția daunelor&amp;quot;,&lt;br /&gt;
        averageDamages: &amp;quot;Media damageului&amp;quot;,&lt;br /&gt;
        damagesAugmentation: &amp;quot;Damage imbunatatit&amp;quot;,&lt;br /&gt;
        bonusVariationTitle: [&lt;br /&gt;
          &amp;quot;Evolutia mediei damageului&amp;quot;,&lt;br /&gt;
          &amp;quot;relativ la o valoare bonus&amp;quot;,&lt;br /&gt;
        ],&lt;br /&gt;
      },&lt;br /&gt;
      de: {&lt;br /&gt;
        damages: &amp;quot;Schäden&amp;quot;,&lt;br /&gt;
        percentage: &amp;quot;Prozentsatz&amp;quot;,&lt;br /&gt;
        miss: &amp;quot;Verfehlen&amp;quot;,&lt;br /&gt;
        normalHit: &amp;quot;Normaler Treffer&amp;quot;,&lt;br /&gt;
        criticalHit: &amp;quot;Kritischer Treffer&amp;quot;,&lt;br /&gt;
        piercingHit: &amp;quot;Durchdringender Treffer&amp;quot;,&lt;br /&gt;
        criticalPiercingHit: &amp;quot;Kritischer durchdringender Treffer&amp;quot;,&lt;br /&gt;
        damagesRepartition: &amp;quot;Schadensverteilung&amp;quot;,&lt;br /&gt;
        averageDamages: &amp;quot;Durchschnittlicher Schaden&amp;quot;,&lt;br /&gt;
        damagesAugmentation: &amp;quot;Schadenserhöhung&amp;quot;,&lt;br /&gt;
        bonusVariationTitle: [&lt;br /&gt;
          &amp;quot;Entwicklung des durchschnittlichen Schadens&amp;quot;,&lt;br /&gt;
          &amp;quot;im Verhältnis zu einem Bonus&amp;quot;,&lt;br /&gt;
        ],&lt;br /&gt;
      },&lt;br /&gt;
      pt: {&lt;br /&gt;
        damages: &amp;quot;Dano&amp;quot;,&lt;br /&gt;
        percentage: &amp;quot;Percentagem&amp;quot;,&lt;br /&gt;
        miss: &amp;quot;Miss&amp;quot;,&lt;br /&gt;
        normalHit: &amp;quot;Dano normal&amp;quot;,&lt;br /&gt;
        criticalHit: &amp;quot;Dano crítico&amp;quot;,&lt;br /&gt;
        piercingHit: &amp;quot;Dano perfurante&amp;quot;,&lt;br /&gt;
        criticalPiercingHit: &amp;quot;Dano crítico perfurante&amp;quot;,&lt;br /&gt;
        damagesRepartition: &amp;quot;Repartição de dano&amp;quot;,&lt;br /&gt;
        averageDamages: &amp;quot;Dano médio&amp;quot;,&lt;br /&gt;
        damagesAugmentation: &amp;quot;Aumento de dano&amp;quot;,&lt;br /&gt;
        bonusVariationTitle: [&amp;quot;Evolução do dano médio&amp;quot;, &amp;quot;relativo a um bónus&amp;quot;],&lt;br /&gt;
      },&lt;br /&gt;
      // es: {&lt;br /&gt;
      //   damages: &amp;quot;Daño&amp;quot;,&lt;br /&gt;
      //   percentage: &amp;quot;Porcentaje&amp;quot;,&lt;br /&gt;
      //   miss: &amp;quot;Miss&amp;quot;,&lt;br /&gt;
      //   normalHit: &amp;quot;Daño normal&amp;quot;,&lt;br /&gt;
      //   criticalHit: &amp;quot;Daño crítico&amp;quot;,&lt;br /&gt;
      //   piercingHit: &amp;quot;Daño perforante&amp;quot;,&lt;br /&gt;
      //   criticalPiercingHit: &amp;quot;Daño crítico perforante&amp;quot;,&lt;br /&gt;
      //   damagesRepartition: &amp;quot;Repartición de daños&amp;quot;,&lt;br /&gt;
      //   averageDamages: &amp;quot;Daño medio&amp;quot;,&lt;br /&gt;
      //   damagesAugmentation: &amp;quot;Aumento de daño&amp;quot;,&lt;br /&gt;
      //   bonusVariationTitle: [&amp;quot;Evolución del daño medio&amp;quot;, &amp;quot;Relativo a una bonificación&amp;quot;]&lt;br /&gt;
      // },&lt;br /&gt;
    },&lt;br /&gt;
  };&lt;br /&gt;
  return constants;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initResultTableHistory(battle) {&lt;br /&gt;
  var {&lt;br /&gt;
    tableResultHistory,&lt;br /&gt;
    savedFights,&lt;br /&gt;
    deleteFightTemplate,&lt;br /&gt;
    numberFormats: { default: numberFormat },&lt;br /&gt;
  } = battle;&lt;br /&gt;
  var startIndex = 3;&lt;br /&gt;
&lt;br /&gt;
  if (savedFights.length) {&lt;br /&gt;
    hideElement(tableResultHistory.rows[1]);&lt;br /&gt;
&lt;br /&gt;
    for (var savedFight of savedFights) {&lt;br /&gt;
      addRowToTableResultHistory(&lt;br /&gt;
        tableResultHistory,&lt;br /&gt;
        savedFight,&lt;br /&gt;
        deleteFightTemplate,&lt;br /&gt;
        numberFormat&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  tableResultHistory.addEventListener(&amp;quot;click&amp;quot;, function (event) {&lt;br /&gt;
    var deleteButton = event.target.closest(&amp;quot;.svg-icon-delete&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (deleteButton) {&lt;br /&gt;
      var row = deleteButton.closest(&amp;quot;tr&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
      if (row) {&lt;br /&gt;
        savedFights.splice(row.rowIndex - startIndex, 1);&lt;br /&gt;
        updateSavedFights(savedFights);&lt;br /&gt;
&lt;br /&gt;
        row.remove();&lt;br /&gt;
&lt;br /&gt;
        if (tableResultHistory.rows.length === startIndex) {&lt;br /&gt;
          showElement(tableResultHistory.rows[1]);&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initDamagesChart(battle) {&lt;br /&gt;
  var { translation, reduceChartPointsContainer, reduceChartPoints } = battle;&lt;br /&gt;
  var percentFormat = battle.numberFormats.percent;&lt;br /&gt;
  var customPlugins = {&lt;br /&gt;
    id: &amp;quot;customPlugins&amp;quot;,&lt;br /&gt;
    afterDraw(chart) {&lt;br /&gt;
      var missPercentage = chart.data.missPercentage;&lt;br /&gt;
&lt;br /&gt;
      if (!missPercentage) {&lt;br /&gt;
        return;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      var {&lt;br /&gt;
        ctx,&lt;br /&gt;
        chartArea: { top, right },&lt;br /&gt;
      } = chart;&lt;br /&gt;
      ctx.save();&lt;br /&gt;
      var text =&lt;br /&gt;
        translation.miss + &amp;quot; : &amp;quot; + percentFormat.format(missPercentage);&lt;br /&gt;
      var padding = 4;&lt;br /&gt;
      var fontSize = 14;&lt;br /&gt;
&lt;br /&gt;
      ctx.font = fontSize + &amp;quot;px Helvetica Neue&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
      var textWidth = ctx.measureText(text).width;&lt;br /&gt;
      var xPosition = right - textWidth - 5;&lt;br /&gt;
      var yPosition = top + 5;&lt;br /&gt;
&lt;br /&gt;
      ctx.fillStyle = &amp;quot;rgba(255, 0, 0, 0.2)&amp;quot;;&lt;br /&gt;
      ctx.fillRect(&lt;br /&gt;
        xPosition - padding,&lt;br /&gt;
        yPosition - padding,&lt;br /&gt;
        textWidth + 2 * padding,&lt;br /&gt;
        fontSize + 2 * padding&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      ctx.strokeStyle = &amp;quot;red&amp;quot;;&lt;br /&gt;
      ctx.strokeRect(&lt;br /&gt;
        xPosition - padding,&lt;br /&gt;
        yPosition - padding,&lt;br /&gt;
        textWidth + 2 * padding,&lt;br /&gt;
        fontSize + 2 * padding&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      ctx.fillStyle = &amp;quot;#666&amp;quot;;&lt;br /&gt;
      ctx.textBaseline = &amp;quot;top&amp;quot;;&lt;br /&gt;
      ctx.fillText(text, xPosition, yPosition + 1);&lt;br /&gt;
&lt;br /&gt;
      ctx.restore();&lt;br /&gt;
    },&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  Chart.register(customPlugins);&lt;br /&gt;
&lt;br /&gt;
  var ctx = battle.plotDamages.getContext(&amp;quot;2d&amp;quot;);&lt;br /&gt;
  var maxLabelsInTooltip = 10;&lt;br /&gt;
  var nullLabelText = &amp;quot; ...&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  var chart = new Chart(ctx, {&lt;br /&gt;
    type: &amp;quot;scatter&amp;quot;,&lt;br /&gt;
    data: {&lt;br /&gt;
      missPercentage: 0,&lt;br /&gt;
      datasets: [],&lt;br /&gt;
    },&lt;br /&gt;
    options: {&lt;br /&gt;
      responsive: true,&lt;br /&gt;
      maintainAspectRatio: false,&lt;br /&gt;
      plugins: {&lt;br /&gt;
        legend: {&lt;br /&gt;
          display: true,&lt;br /&gt;
          onHover: function (e) {&lt;br /&gt;
            e.native.target.style.cursor = &amp;quot;pointer&amp;quot;;&lt;br /&gt;
          },&lt;br /&gt;
          onLeave: function (e) {&lt;br /&gt;
            e.native.target.style.cursor = &amp;quot;default&amp;quot;;&lt;br /&gt;
          },&lt;br /&gt;
          onClick: function (e, legendItem, legend) {&lt;br /&gt;
            var currentIndex = legendItem.datasetIndex;&lt;br /&gt;
            var ci = legend.chart;&lt;br /&gt;
            var isCurrentDatasetVisible = ci.isDatasetVisible(currentIndex);&lt;br /&gt;
            var datasets = ci.data.datasets;&lt;br /&gt;
            var hideReducePoints = true;&lt;br /&gt;
            var isReducePointsChecked = reduceChartPoints.checked;&lt;br /&gt;
&lt;br /&gt;
            datasets[currentIndex].hidden = isCurrentDatasetVisible;&lt;br /&gt;
            legendItem.hidden = isCurrentDatasetVisible;&lt;br /&gt;
&lt;br /&gt;
            for (var index in datasets) {&lt;br /&gt;
              if (ci.isDatasetVisible(index) &amp;amp;&amp;amp; datasets[index].canBeReduced) {&lt;br /&gt;
                showElement(reduceChartPointsContainer);&lt;br /&gt;
                hideReducePoints = false;&lt;br /&gt;
                break;&lt;br /&gt;
              }&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            if (hideReducePoints) {&lt;br /&gt;
              hideElement(reduceChartPointsContainer);&lt;br /&gt;
              handleChartAnimations(ci, true);&lt;br /&gt;
            } else {&lt;br /&gt;
              handleChartAnimations(ci, isReducePointsChecked);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            ci.update();&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        title: {&lt;br /&gt;
          display: true,&lt;br /&gt;
          text: translation.damagesRepartition,&lt;br /&gt;
          font: {&lt;br /&gt;
            size: 20,&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        tooltip: {&lt;br /&gt;
          callbacks: {&lt;br /&gt;
            label: function (context) {&lt;br /&gt;
              if (context.label === null) {&lt;br /&gt;
                return nullLabelText;&lt;br /&gt;
              }&lt;br /&gt;
&lt;br /&gt;
              var xValue = battle.numberFormats.default.format(&lt;br /&gt;
                context.parsed.x&lt;br /&gt;
              );&lt;br /&gt;
              var yValue = battle.numberFormats.percent.format(&lt;br /&gt;
                context.parsed.y&lt;br /&gt;
              );&lt;br /&gt;
&lt;br /&gt;
              label =&lt;br /&gt;
                &amp;quot; &amp;quot; +&lt;br /&gt;
                context.dataset.label +&lt;br /&gt;
                &amp;quot; : (&amp;quot; +&lt;br /&gt;
                xValue +&lt;br /&gt;
                &amp;quot;, &amp;quot; +&lt;br /&gt;
                yValue +&lt;br /&gt;
                &amp;quot;)&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
              return label;&lt;br /&gt;
            },&lt;br /&gt;
            beforeBody: function (tooltipItems) {&lt;br /&gt;
              if (tooltipItems.length &amp;gt; maxLabelsInTooltip + 1) {&lt;br /&gt;
                tooltipItems.splice(maxLabelsInTooltip + 1);&lt;br /&gt;
                tooltipItems[maxLabelsInTooltip].label = null;&lt;br /&gt;
              }&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          caretPadding: 10,&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
      scales: {&lt;br /&gt;
        x: {&lt;br /&gt;
          type: &amp;quot;linear&amp;quot;,&lt;br /&gt;
          position: &amp;quot;bottom&amp;quot;,&lt;br /&gt;
          title: {&lt;br /&gt;
            display: true,&lt;br /&gt;
            text: translation.damages,&lt;br /&gt;
            font: {&lt;br /&gt;
              size: 16,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        y: {&lt;br /&gt;
          title: {&lt;br /&gt;
            display: true,&lt;br /&gt;
            text: translation.percentage,&lt;br /&gt;
            font: {&lt;br /&gt;
              size: 16,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          ticks: {&lt;br /&gt;
            format: {&lt;br /&gt;
              style: &amp;quot;percent&amp;quot;,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
      elements: {&lt;br /&gt;
        point: {&lt;br /&gt;
          borderWidth: 1,&lt;br /&gt;
          radius: 3,&lt;br /&gt;
          hitRadius: 3,&lt;br /&gt;
          hoverRadius: 6,&lt;br /&gt;
          hoverBorderWidth: 2,&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
    },&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  var datasetsStyle = [&lt;br /&gt;
    {&lt;br /&gt;
      name: &amp;quot;normalHit&amp;quot;,&lt;br /&gt;
      canBeReduced: false,&lt;br /&gt;
      label: translation.normalHit,&lt;br /&gt;
      backgroundColor: &amp;quot;rgba(75, 192, 192, 0.2)&amp;quot;,&lt;br /&gt;
      borderColor: &amp;quot;rgba(75, 192, 192, 1)&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      name: &amp;quot;piercingHit&amp;quot;,&lt;br /&gt;
      canBeReduced: false,&lt;br /&gt;
      label: translation.piercingHit,&lt;br /&gt;
      backgroundColor: &amp;quot;rgba(192, 192, 75, 0.2)&amp;quot;,&lt;br /&gt;
      borderColor: &amp;quot;rgba(192, 192, 75, 1)&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      name: &amp;quot;criticalHit&amp;quot;,&lt;br /&gt;
      canBeReduced: false,&lt;br /&gt;
      label: translation.criticalHit,&lt;br /&gt;
      backgroundColor: &amp;quot;rgba(192, 75, 192, 0.2)&amp;quot;,&lt;br /&gt;
      borderColor: &amp;quot;rgba(192, 75, 192, 1)&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      name: &amp;quot;criticalPiercingHit&amp;quot;,&lt;br /&gt;
      canBeReduced: false,&lt;br /&gt;
      label: translation.criticalPiercingHit,&lt;br /&gt;
      backgroundColor: &amp;quot;rgba(75, 75, 192, 0.2)&amp;quot;,&lt;br /&gt;
      borderColor: &amp;quot;rgba(75, 75, 192, 1)&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
  ];&lt;br /&gt;
  battle.damagesChart = {&lt;br /&gt;
    chart: chart,&lt;br /&gt;
    datasetsStyle: datasetsStyle,&lt;br /&gt;
    maxPoints: 500,&lt;br /&gt;
    reduceChartPointsContainer: reduceChartPointsContainer,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initBonusVariationChart(battle) {&lt;br /&gt;
  var translation = battle.translation;&lt;br /&gt;
&lt;br /&gt;
  var ctx = battle.plotBonusVariation.getContext(&amp;quot;2d&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  var chart = new Chart(ctx, {&lt;br /&gt;
    type: &amp;quot;line&amp;quot;,&lt;br /&gt;
    data: {&lt;br /&gt;
      datasets: [&lt;br /&gt;
        {&lt;br /&gt;
          label: translation.averageDamages,&lt;br /&gt;
          backgroundColor: &amp;quot;rgba(75, 192, 192, 0.2)&amp;quot;,&lt;br /&gt;
          borderColor: &amp;quot;rgba(75, 192, 192, 1)&amp;quot;,&lt;br /&gt;
          fill: true,&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          label: translation.damagesAugmentation,&lt;br /&gt;
          backgroundColor: &amp;quot;rgba(192, 192, 75, 0.2)&amp;quot;,&lt;br /&gt;
          borderColor: &amp;quot;rgba(192, 192, 75, 1)&amp;quot;,&lt;br /&gt;
          hidden: true,&lt;br /&gt;
          yTicksFormat: { style: &amp;quot;percent&amp;quot; },&lt;br /&gt;
          fill: true,&lt;br /&gt;
        },&lt;br /&gt;
      ],&lt;br /&gt;
    },&lt;br /&gt;
    options: {&lt;br /&gt;
      responsive: true,&lt;br /&gt;
      maintainAspectRatio: false,&lt;br /&gt;
      plugins: {&lt;br /&gt;
        legend: {&lt;br /&gt;
          display: true,&lt;br /&gt;
          onHover: function (e) {&lt;br /&gt;
            e.native.target.style.cursor = &amp;quot;pointer&amp;quot;;&lt;br /&gt;
          },&lt;br /&gt;
          onLeave: function (e) {&lt;br /&gt;
            e.native.target.style.cursor = &amp;quot;default&amp;quot;;&lt;br /&gt;
          },&lt;br /&gt;
          onClick: function (e, legendItem, legend) {&lt;br /&gt;
            var currentIndex = legendItem.datasetIndex;&lt;br /&gt;
            var ci = legend.chart;&lt;br /&gt;
            var datasets = ci.data.datasets;&lt;br /&gt;
            var isCurrentDatasetVisible = ci.isDatasetVisible(currentIndex);&lt;br /&gt;
            var yAxis = ci.options.scales.y;&lt;br /&gt;
&lt;br /&gt;
            var otherIndex = currentIndex === 0 ? 1 : 0;&lt;br /&gt;
            var visibleDataset = isCurrentDatasetVisible&lt;br /&gt;
              ? datasets[otherIndex]&lt;br /&gt;
              : datasets[currentIndex];&lt;br /&gt;
&lt;br /&gt;
            datasets[currentIndex].hidden = isCurrentDatasetVisible;&lt;br /&gt;
            datasets[otherIndex].hidden = !isCurrentDatasetVisible;&lt;br /&gt;
&lt;br /&gt;
            yAxis.title.text = visibleDataset.label;&lt;br /&gt;
            yAxis.ticks.format = visibleDataset.yTicksFormat;&lt;br /&gt;
&lt;br /&gt;
            ci.update();&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        title: {&lt;br /&gt;
          display: true,&lt;br /&gt;
          text: translation.bonusVariationTitle,&lt;br /&gt;
          font: {&lt;br /&gt;
            size: 18,&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        tooltip: {&lt;br /&gt;
          caretPadding: 10,&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
      scales: {&lt;br /&gt;
        x: {&lt;br /&gt;
          type: &amp;quot;linear&amp;quot;,&lt;br /&gt;
          position: &amp;quot;bottom&amp;quot;,&lt;br /&gt;
          title: {&lt;br /&gt;
            display: true,&lt;br /&gt;
            text: &amp;quot;Bonus&amp;quot;,&lt;br /&gt;
            font: {&lt;br /&gt;
              size: 16,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          ticks: {&lt;br /&gt;
            callback: function (value) {&lt;br /&gt;
              if (Number.isInteger(value)) {&lt;br /&gt;
                return Number(value);&lt;br /&gt;
              }&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        y: {&lt;br /&gt;
          title: {&lt;br /&gt;
            display: true,&lt;br /&gt;
            text: translation.averageDamages,&lt;br /&gt;
            font: {&lt;br /&gt;
              size: 16,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
      elements: {&lt;br /&gt;
        point: {&lt;br /&gt;
          borderWidth: 1,&lt;br /&gt;
          radius: 3,&lt;br /&gt;
          hitRadius: 3,&lt;br /&gt;
          hoverRadius: 6,&lt;br /&gt;
          hoverBorderWidth: 2,&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
    },&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  battle.bonusVariationChart = chart;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function attackSelectonListener(&lt;br /&gt;
  characters,&lt;br /&gt;
  attackerSelection,&lt;br /&gt;
  attackTypeSelection&lt;br /&gt;
) {&lt;br /&gt;
  attackerSelection.addEventListener(&amp;quot;change&amp;quot;, function (event) {&lt;br /&gt;
    var attackerName = event.target.value;&lt;br /&gt;
&lt;br /&gt;
    if (isPseudoSaved(characters, attackerName)) {&lt;br /&gt;
      var attacker = characters.savedCharacters[attackerName];&lt;br /&gt;
      filterAttackTypeSelection(attacker, attackTypeSelection);&lt;br /&gt;
    } else {&lt;br /&gt;
      filterAttackTypeSelectionMonster(attackTypeSelection);&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getTranslation(translation) {&lt;br /&gt;
  var userLanguage = navigator.language;&lt;br /&gt;
  var langToUse = &amp;quot;en&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  for (var lang in translation) {&lt;br /&gt;
    if (userLanguage.startsWith(lang)) {&lt;br /&gt;
      langToUse = lang;&lt;br /&gt;
      break;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return translation[langToUse];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createDamageCalculatorInformation(chartSource) {&lt;br /&gt;
  var characters = {&lt;br /&gt;
    unsavedChanges: false,&lt;br /&gt;
    savedCharacters: {},&lt;br /&gt;
    currentCharacter: null,&lt;br /&gt;
    savedMonsters: getSavedMonsters(),&lt;br /&gt;
    characterCreation: document.getElementById(&amp;quot;character-creation&amp;quot;),&lt;br /&gt;
    addNewCharacterButton: document.getElementById(&amp;quot;add-new-character&amp;quot;),&lt;br /&gt;
    dropZone: document.getElementById(&amp;quot;character-drop-zone&amp;quot;),&lt;br /&gt;
    characterInput: document.getElementById(&amp;quot;character-input&amp;quot;),&lt;br /&gt;
    newCharacterTemplate: document.getElementById(&amp;quot;new-character-template&amp;quot;)&lt;br /&gt;
      .children[0],&lt;br /&gt;
    charactersContainer: document.getElementById(&amp;quot;characters-container&amp;quot;),&lt;br /&gt;
    monsterButtonTemplates: document.getElementById(&amp;quot;monster-button-templates&amp;quot;),&lt;br /&gt;
    monsterTemplate: document.getElementById(&amp;quot;new-monster-template&amp;quot;)&lt;br /&gt;
      .children[0],&lt;br /&gt;
    monstersContainer: document.getElementById(&amp;quot;monsters-container&amp;quot;),&lt;br /&gt;
    monsteriFrame: document.getElementById(&amp;quot;monster-iframe&amp;quot;),&lt;br /&gt;
    stoneiFrame: document.getElementById(&amp;quot;stone-iframe&amp;quot;),&lt;br /&gt;
    saveButton: document.getElementById(&amp;quot;save-character&amp;quot;),&lt;br /&gt;
    weaponCategory: document.getElementById(&amp;quot;weapon-category&amp;quot;),&lt;br /&gt;
    weaponDisplay: document.getElementById(&amp;quot;weapon-display&amp;quot;),&lt;br /&gt;
    randomAttackValue: document.getElementById(&amp;quot;random-attack-value&amp;quot;),&lt;br /&gt;
    randomMagicAttackValue: document.getElementById(&lt;br /&gt;
      &amp;quot;random-magic-attack-value&amp;quot;&lt;br /&gt;
    ),&lt;br /&gt;
    yoharaCreation: document.getElementById(&amp;quot;yohara-creation&amp;quot;),&lt;br /&gt;
    blessingCreation: document.getElementById(&amp;quot;blessing-creation&amp;quot;),&lt;br /&gt;
    marriageCreation: document.getElementById(&amp;quot;marriage-creation&amp;quot;),&lt;br /&gt;
    bonusVariation: {&lt;br /&gt;
      tab: document.getElementById(&amp;quot;Variation&amp;quot;),&lt;br /&gt;
      activation: document.getElementById(&amp;quot;bonus-variation-activation&amp;quot;),&lt;br /&gt;
      input: document.getElementById(&amp;quot;bonus-variation&amp;quot;),&lt;br /&gt;
      inputDisplay: document.getElementById(&amp;quot;bonus-variation-display&amp;quot;),&lt;br /&gt;
      container: document.getElementById(&amp;quot;bonus-variation-range&amp;quot;),&lt;br /&gt;
      minValue: document.getElementById(&amp;quot;bonus-variation-min-value&amp;quot;),&lt;br /&gt;
      maxValue: document.getElementById(&amp;quot;bonus-variation-max-value&amp;quot;),&lt;br /&gt;
    },&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  characters.bonusVariation.inputDisplay.setAttribute(&amp;quot;readonly&amp;quot;, &amp;quot;&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  for (var [pseudo, character] of Object.entries(getSavedCharacters())) {&lt;br /&gt;
    characters.savedCharacters[pseudo] = character;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var skillContainer = document.getElementById(&amp;quot;skill-container&amp;quot;);&lt;br /&gt;
  characters.skillElementsToFilter =&lt;br /&gt;
    skillContainer.querySelectorAll(&amp;quot;[data-class]&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  var mapping = createMapping();&lt;br /&gt;
  var constants = createConstants();&lt;br /&gt;
&lt;br /&gt;
  var battle = {&lt;br /&gt;
    resetAttackType: false,&lt;br /&gt;
    savedFights: getSavedFights(),&lt;br /&gt;
    battleForm: document.getElementById(&amp;quot;create-battle&amp;quot;),&lt;br /&gt;
    attackerSelection: document.getElementById(&amp;quot;attacker-selection&amp;quot;),&lt;br /&gt;
    attackTypeSelection: document.getElementById(&amp;quot;attack-type-selection&amp;quot;),&lt;br /&gt;
    victimSelection: document.getElementById(&amp;quot;victim-selection&amp;quot;),&lt;br /&gt;
    damagesWeightedByType: {},&lt;br /&gt;
    scatterDataByType: {},&lt;br /&gt;
    damagesByBonus: [],&lt;br /&gt;
    tableResultFight: document.getElementById(&amp;quot;result-table-fight&amp;quot;),&lt;br /&gt;
    tableResultHistory: document.getElementById(&amp;quot;result-table-history&amp;quot;),&lt;br /&gt;
    deleteFightTemplate: document.getElementById(&amp;quot;delete-fight-template&amp;quot;)&lt;br /&gt;
      .children[0],&lt;br /&gt;
    errorInformation: {},&lt;br /&gt;
    fightResultContainer: document.getElementById(&amp;quot;fight-result-container&amp;quot;),&lt;br /&gt;
    downLoadRawData: document.getElementById(&amp;quot;download-raw-data&amp;quot;),&lt;br /&gt;
    downLoadRawDataVariation: document.getElementById(&lt;br /&gt;
      &amp;quot;download-raw-data-variation&amp;quot;&lt;br /&gt;
    ),&lt;br /&gt;
    bonusVariationResultContainer: document.getElementById(&lt;br /&gt;
      &amp;quot;bonus-variation-result-container&amp;quot;&lt;br /&gt;
    ),&lt;br /&gt;
    reduceChartPointsContainer: document.getElementById(&lt;br /&gt;
      &amp;quot;reduce-chart-points-container&amp;quot;&lt;br /&gt;
    ),&lt;br /&gt;
    reduceChartPoints: document.getElementById(&amp;quot;reduce-chart-points&amp;quot;),&lt;br /&gt;
    plotDamages: document.getElementById(&amp;quot;plot-damages&amp;quot;),&lt;br /&gt;
    plotBonusVariation: document.getElementById(&amp;quot;plot-bonus-variation&amp;quot;),&lt;br /&gt;
    uniqueDamagesCounters: document.querySelectorAll(&amp;quot;.unique-damages-counter&amp;quot;),&lt;br /&gt;
    possibleDamagesCounter: document.getElementById(&amp;quot;possible-damages-counter&amp;quot;),&lt;br /&gt;
    damagesTime: document.getElementById(&amp;quot;damages-time&amp;quot;),&lt;br /&gt;
    displayTime: document.getElementById(&amp;quot;display-time&amp;quot;),&lt;br /&gt;
    simulationCounter: document.getElementById(&amp;quot;simulation-counter&amp;quot;),&lt;br /&gt;
    simulationTime: document.getElementById(&amp;quot;simulation-time&amp;quot;),&lt;br /&gt;
    numberFormats: {&lt;br /&gt;
      default: new Intl.NumberFormat(undefined, {&lt;br /&gt;
        minimumFractionDigits: 0,&lt;br /&gt;
        maximumFractionDigits: 1,&lt;br /&gt;
      }),&lt;br /&gt;
      percent: new Intl.NumberFormat(undefined, {&lt;br /&gt;
        style: &amp;quot;percent&amp;quot;,&lt;br /&gt;
        maximumFractionDigits: 3,&lt;br /&gt;
      }),&lt;br /&gt;
      second: new Intl.NumberFormat(undefined, {&lt;br /&gt;
        style: &amp;quot;unit&amp;quot;,&lt;br /&gt;
        unit: &amp;quot;second&amp;quot;,&lt;br /&gt;
        unitDisplay: &amp;quot;long&amp;quot;,&lt;br /&gt;
        maximumFractionDigits: 3,&lt;br /&gt;
      }),&lt;br /&gt;
    },&lt;br /&gt;
    mapping: mapping,&lt;br /&gt;
    constants: constants,&lt;br /&gt;
    translation: getTranslation(constants.translation),&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  attackSelectonListener(&lt;br /&gt;
    characters,&lt;br /&gt;
    battle.attackerSelection,&lt;br /&gt;
    battle.attackTypeSelection&lt;br /&gt;
  );&lt;br /&gt;
  initResultTableHistory(battle);&lt;br /&gt;
  addScript(chartSource, function () {&lt;br /&gt;
    initDamagesChart(battle);&lt;br /&gt;
    initBonusVariationChart(battle);&lt;br /&gt;
  });&lt;br /&gt;
  reduceChartPointsListener(battle);&lt;br /&gt;
  downloadRawDataListener(battle);&lt;br /&gt;
&lt;br /&gt;
  var errorElements = document.querySelectorAll(&amp;quot;[data-error]&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; errorElements.length; index++) {&lt;br /&gt;
    var errorElement = errorElements[index];&lt;br /&gt;
    battle.errorInformation[errorElement.dataset.error] = errorElement;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return [characters, battle];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadStyle(src) {&lt;br /&gt;
  var link = document.createElement(&amp;quot;link&amp;quot;);&lt;br /&gt;
  link.href = src;&lt;br /&gt;
  link.rel = &amp;quot;stylesheet&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  document.head.appendChild(link);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
(function () {&lt;br /&gt;
  var javascriptSource =&lt;br /&gt;
    &amp;quot;/index.php?title=Utilisateur:Ankhseram/Calculator.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&amp;quot;;&lt;br /&gt;
  var cssSource =&lt;br /&gt;
    &amp;quot;/index.php?title=Utilisateur:Ankhseram/Style.css&amp;amp;action=raw&amp;amp;ctype=text/css&amp;quot;;&lt;br /&gt;
  var chartSource = &amp;quot;https://cdn.jsdelivr.net/npm/chart.js&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  loadStyle(cssSource);&lt;br /&gt;
&lt;br /&gt;
  function main() {&lt;br /&gt;
    var [characters, battle] = createDamageCalculatorInformation(chartSource);&lt;br /&gt;
&lt;br /&gt;
    characterManagement(characters, battle);&lt;br /&gt;
    monsterManagement(characters, battle);&lt;br /&gt;
&lt;br /&gt;
    updateBattleChoice(characters, battle);&lt;br /&gt;
    createBattle(characters, battle);&lt;br /&gt;
  }&lt;br /&gt;
  addScript(javascriptSource, main);&lt;br /&gt;
})();&lt;/div&gt;</summary>
		<author><name>Dexter</name></author>
		
	</entry>
	<entry>
		<id>https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Script/Calculator.js&amp;diff=105760</id>
		<title>MediaWiki:Script/Calculator.js</title>
		<link rel="alternate" type="text/html" href="https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Script/Calculator.js&amp;diff=105760"/>
		<updated>2024-12-11T20:20:45Z</updated>

		<summary type="html">&lt;p&gt;Dexter : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;function removeAccent(str) {&lt;br /&gt;
  return str.normalize(&amp;quot;NFD&amp;quot;).replace(/[\u0300-\u036f]/g, &amp;quot;&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function pseudoFormat(str) {&lt;br /&gt;
  return removeAccent(str).replace(/[^A-Za-z0-9 \(\)\+_-]+/g, &amp;quot;&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isValueInArray(value, array) {&lt;br /&gt;
  return array.indexOf(value) !== -1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function copyObject(object) {&lt;br /&gt;
  var copy = {};&lt;br /&gt;
  for (var key in object) {&lt;br /&gt;
    copy[key] = object[key];&lt;br /&gt;
  }&lt;br /&gt;
  return copy;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function compareNumbers(a, b) {&lt;br /&gt;
  return b - a;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isChecked(attribute) {&lt;br /&gt;
  return attribute === &amp;quot;on&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function floorMultiplication(firstFactor, secondFactor) {&lt;br /&gt;
  return Math.floor((firstFactor * secondFactor).toFixed(8));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function truncateNumber(number, precision) {&lt;br /&gt;
  return Math.floor(number * 10 ** precision) / 10 ** precision;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addKeyValue(object, key, value) {&lt;br /&gt;
  if (object.hasOwnProperty(key)) {&lt;br /&gt;
    object[key] += value;&lt;br /&gt;
  } else {&lt;br /&gt;
    object[key] = value;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function editTableResultRow(row, valuesToDisplay, numberFormat) {&lt;br /&gt;
  row.innerHTML = &amp;quot;&amp;quot;;&lt;br /&gt;
  for (var index = 0; index &amp;lt; valuesToDisplay.length; index++) {&lt;br /&gt;
    var cell = row.insertCell();&lt;br /&gt;
    var textContent;&lt;br /&gt;
&lt;br /&gt;
    if (index &amp;gt;= 3) {&lt;br /&gt;
      textContent = numberFormat.format(valuesToDisplay[index]);&lt;br /&gt;
    } else {&lt;br /&gt;
      textContent = valuesToDisplay[index];&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    cell.textContent = textContent;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return row;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addRowToTableResultHistory(&lt;br /&gt;
  tableResultHistory,&lt;br /&gt;
  valuesToDisplay,&lt;br /&gt;
  deleteFightTemplate,&lt;br /&gt;
  numberFormat&lt;br /&gt;
) {&lt;br /&gt;
  var row = tableResultHistory.insertRow();&lt;br /&gt;
  editTableResultRow(row, valuesToDisplay, numberFormat);&lt;br /&gt;
  var cell = row.insertCell();&lt;br /&gt;
  cell.appendChild(deleteFightTemplate.cloneNode(true));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcMeanDamages(damagesWeightedByType, totalCardinal) {&lt;br /&gt;
  var sumDamages = 0;&lt;br /&gt;
&lt;br /&gt;
  for (var damagesTypeName in damagesWeightedByType) {&lt;br /&gt;
    if (damagesTypeName === &amp;quot;miss&amp;quot;) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var damagesWeighted = damagesWeightedByType[damagesTypeName];&lt;br /&gt;
&lt;br /&gt;
    for (var damages in damagesWeighted) {&lt;br /&gt;
      sumDamages += damages * damagesWeighted[damages];&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return sumDamages / totalCardinal;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function prepareDamagesData(&lt;br /&gt;
  damagesWeightedByType,&lt;br /&gt;
  possibleDamagesCountTemp,&lt;br /&gt;
  totalCardinal&lt;br /&gt;
) {&lt;br /&gt;
  var minDamages = Infinity;&lt;br /&gt;
  var maxDamages = 0;&lt;br /&gt;
  var scatterDataByType = {};&lt;br /&gt;
  var sumDamages = 0;&lt;br /&gt;
  var possibleDamagesCount = 0;&lt;br /&gt;
  var uniqueDamagesCount = 0;&lt;br /&gt;
&lt;br /&gt;
  for (var damagesTypeName in damagesWeightedByType) {&lt;br /&gt;
    if (damagesTypeName === &amp;quot;miss&amp;quot;) {&lt;br /&gt;
      scatterDataByType.miss = damagesWeightedByType.miss;&lt;br /&gt;
      possibleDamagesCount++;&lt;br /&gt;
      uniqueDamagesCount++;&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var firstIteration = true;&lt;br /&gt;
    var damagesWeighted = damagesWeightedByType[damagesTypeName];&lt;br /&gt;
    var scatterData = [];&lt;br /&gt;
    scatterDataByType[damagesTypeName] = scatterData;&lt;br /&gt;
&lt;br /&gt;
    for (var damages in damagesWeighted) {&lt;br /&gt;
      damages = +damages;&lt;br /&gt;
&lt;br /&gt;
      if (firstIteration) {&lt;br /&gt;
        if (damages &amp;lt; minDamages) {&lt;br /&gt;
          minDamages = damages;&lt;br /&gt;
        }&lt;br /&gt;
        firstIteration = false;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      var weight = damagesWeighted[damages];&lt;br /&gt;
      var probability = weight / totalCardinal;&lt;br /&gt;
&lt;br /&gt;
      sumDamages += damages * weight;&lt;br /&gt;
      damagesWeighted[damages] = probability;&lt;br /&gt;
      scatterData.push({ x: damages, y: probability });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var scatterDataLength = scatterData.length;&lt;br /&gt;
&lt;br /&gt;
    possibleDamagesCount += possibleDamagesCountTemp;&lt;br /&gt;
    uniqueDamagesCount += scatterDataLength;&lt;br /&gt;
&lt;br /&gt;
    if (damages &amp;gt; maxDamages) {&lt;br /&gt;
      maxDamages = damages;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (minDamages === Infinity) {&lt;br /&gt;
    minDamages = 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return [&lt;br /&gt;
    sumDamages / totalCardinal,&lt;br /&gt;
    minDamages,&lt;br /&gt;
    maxDamages,&lt;br /&gt;
    scatterDataByType,&lt;br /&gt;
    possibleDamagesCount,&lt;br /&gt;
    uniqueDamagesCount,&lt;br /&gt;
  ];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function aggregateDamages(scatterData, maxPoints) {&lt;br /&gt;
  var dataLength = scatterData.length;&lt;br /&gt;
  var remainingData = dataLength;&lt;br /&gt;
  var aggregateScatterData = [];&lt;br /&gt;
&lt;br /&gt;
  for (var groupIndex = 0; groupIndex &amp;lt; maxPoints; groupIndex++) {&lt;br /&gt;
    var groupLength = Math.floor(remainingData / (maxPoints - groupIndex));&lt;br /&gt;
    var startIndex = dataLength - remainingData;&lt;br /&gt;
    var aggregateDamages = 0;&lt;br /&gt;
    var aggregateProbability = 0;&lt;br /&gt;
&lt;br /&gt;
    for (var index = startIndex; index &amp;lt; startIndex + groupLength; index++) {&lt;br /&gt;
      var { x: damages, y: probability } = scatterData[index];&lt;br /&gt;
      aggregateDamages += damages * probability;&lt;br /&gt;
      aggregateProbability += probability;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    aggregateScatterData.push({&lt;br /&gt;
      x: aggregateDamages / aggregateProbability,&lt;br /&gt;
      y: aggregateProbability,&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    remainingData -= groupLength;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return aggregateScatterData;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addToDamagesChart(&lt;br /&gt;
  scatterDataByType,&lt;br /&gt;
  damagesChart,&lt;br /&gt;
  isReducePointsChecked&lt;br /&gt;
) {&lt;br /&gt;
  var { chart, datasetsStyle, maxPoints, reduceChartPointsContainer } =&lt;br /&gt;
    damagesChart;&lt;br /&gt;
  var isFirstDataset = true;&lt;br /&gt;
  var datasets = chart.data.datasets;&lt;br /&gt;
&lt;br /&gt;
  datasets.length = 0;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; datasetsStyle.length; index++) {&lt;br /&gt;
    var dataset = copyObject(datasetsStyle[index]);&lt;br /&gt;
&lt;br /&gt;
    if (!scatterDataByType.hasOwnProperty(dataset.name)) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var scatterData = scatterDataByType[dataset.name];&lt;br /&gt;
    var canBeReduced = scatterData.length &amp;gt; 2 * maxPoints;&lt;br /&gt;
&lt;br /&gt;
    dataset.hidden = !isFirstDataset;&lt;br /&gt;
    dataset.canBeReduced = canBeReduced;&lt;br /&gt;
&lt;br /&gt;
    if (canBeReduced &amp;amp;&amp;amp; isReducePointsChecked) {&lt;br /&gt;
      dataset.data = aggregateDamages(scatterData, maxPoints);&lt;br /&gt;
    } else {&lt;br /&gt;
      dataset.data = scatterData;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isFirstDataset) {&lt;br /&gt;
      isFirstDataset = false;&lt;br /&gt;
&lt;br /&gt;
      if (canBeReduced) {&lt;br /&gt;
        showElement(reduceChartPointsContainer);&lt;br /&gt;
&lt;br /&gt;
        if (!isReducePointsChecked) {&lt;br /&gt;
          handleChartAnimations(chart, false);&lt;br /&gt;
        }&lt;br /&gt;
      } else {&lt;br /&gt;
        hideElement(reduceChartPointsContainer);&lt;br /&gt;
        handleChartAnimations(chart, true);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    datasets.push(dataset);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  chart.data.missPercentage = scatterDataByType.miss;&lt;br /&gt;
  chart.update();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addToBonusVariationChart(&lt;br /&gt;
  damagesByBonus,&lt;br /&gt;
  augmentationByBonus,&lt;br /&gt;
  xLabel,&lt;br /&gt;
  chart&lt;br /&gt;
) {&lt;br /&gt;
  chart.data.datasets[0].data = damagesByBonus;&lt;br /&gt;
  chart.data.datasets[1].data = augmentationByBonus;&lt;br /&gt;
  chart.options.scales.x.title.text = xLabel;&lt;br /&gt;
  chart.update();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleChartAnimations(chart, addAnimations) {&lt;br /&gt;
  chart.options.animation = addAnimations;&lt;br /&gt;
  chart.options.animations.colors = addAnimations;&lt;br /&gt;
  chart.options.animations.x = addAnimations;&lt;br /&gt;
  chart.options.transitions.active.animation.duration = addAnimations * 1000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateDamagesChartDescription(&lt;br /&gt;
  uniqueDamagesCounters,&lt;br /&gt;
  uniqueDamagesCount,&lt;br /&gt;
  formatNumber&lt;br /&gt;
) {&lt;br /&gt;
  uniqueDamagesCounters.forEach(function (element) {&lt;br /&gt;
    if (uniqueDamagesCount &amp;lt;= 1) {&lt;br /&gt;
      hideElement(element.parentElement);&lt;br /&gt;
    } else {&lt;br /&gt;
      showElement(element.parentElement);&lt;br /&gt;
      element.textContent = formatNumber.format(uniqueDamagesCount);&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getMonsterName(monsterVnum) {&lt;br /&gt;
  var monsterAttributes = monsterData[monsterVnum];&lt;br /&gt;
  return monsterAttributes[monsterAttributes.length - 1];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterClass(selectedRace, classChoice, selectValueIsChanged = false) {&lt;br /&gt;
  showElement(classChoice.parentElement);&lt;br /&gt;
&lt;br /&gt;
  for (var option of classChoice.options) {&lt;br /&gt;
    if (option.getAttribute(&amp;quot;data-race&amp;quot;) === selectedRace) {&lt;br /&gt;
      if (!selectValueIsChanged) {&lt;br /&gt;
        classChoice.value = option.value;&lt;br /&gt;
        selectValueIsChanged = true;&lt;br /&gt;
      }&lt;br /&gt;
      showElement(option);&lt;br /&gt;
    } else {&lt;br /&gt;
      hideElement(option);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  if (selectedRace == &amp;quot;lycan&amp;quot;) {&lt;br /&gt;
    hideElement(classChoice.parentElement);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterWeapon(&lt;br /&gt;
  selectedRace,&lt;br /&gt;
  weaponElement,&lt;br /&gt;
  weaponCategory,&lt;br /&gt;
  allowedWeaponsPerRace,&lt;br /&gt;
  selectValueIsChanged = false&lt;br /&gt;
) {&lt;br /&gt;
  var allowedWeapons = allowedWeaponsPerRace[selectedRace];&lt;br /&gt;
&lt;br /&gt;
  if (!selectValueIsChanged) {&lt;br /&gt;
    var weaponType = weaponData[weaponElement.value][1];&lt;br /&gt;
&lt;br /&gt;
    if (!isValueInArray(weaponType, allowedWeapons)) {&lt;br /&gt;
      weaponElement.value = 0;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var children = weaponCategory.children;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; children.length; index++) {&lt;br /&gt;
    var child = children[index];&lt;br /&gt;
&lt;br /&gt;
    if (isValueInArray(index, allowedWeapons)) {&lt;br /&gt;
      showElement(child);&lt;br /&gt;
    } else {&lt;br /&gt;
      hideElement(child);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSelectedWeapon(weaponCategory) {&lt;br /&gt;
  return weaponCategory.querySelector(&amp;quot;input[type='radio']:checked&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleWeaponDisplay(weaponDisplay, newWeapon, weaponVnum) {&lt;br /&gt;
  var newImage = newWeapon.nextElementSibling.cloneNode();&lt;br /&gt;
  var newText = document.createElement(&amp;quot;span&amp;quot;);&lt;br /&gt;
  var oldImage = weaponDisplay.firstChild;&lt;br /&gt;
  var oldText = oldImage.nextElementSibling;&lt;br /&gt;
  var weaponName = createWeapon(weaponVnum).name;&lt;br /&gt;
&lt;br /&gt;
  if (weaponVnum == 0) {&lt;br /&gt;
    newText.textContent = &amp;quot; &amp;quot; + weaponName + &amp;quot; &amp;quot;;&lt;br /&gt;
  } else {&lt;br /&gt;
    var weaponLink = document.createElement(&amp;quot;a&amp;quot;);&lt;br /&gt;
    weaponLink.href = mw.util.getUrl(weaponName);&lt;br /&gt;
    weaponLink.title = weaponName;&lt;br /&gt;
    weaponLink.textContent = weaponName;&lt;br /&gt;
&lt;br /&gt;
    newText.appendChild(document.createTextNode(&amp;quot; &amp;quot;));&lt;br /&gt;
    newText.appendChild(weaponLink);&lt;br /&gt;
    newText.appendChild(document.createTextNode(&amp;quot; &amp;quot;));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  weaponDisplay.replaceChild(newImage, oldImage);&lt;br /&gt;
  weaponDisplay.replaceChild(newText, oldText);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterUpgrade(&lt;br /&gt;
  weaponUpgrade,&lt;br /&gt;
  weaponVnum,&lt;br /&gt;
  randomAttackValue,&lt;br /&gt;
  randomMagicAttackValue,&lt;br /&gt;
  currentUpgrade&lt;br /&gt;
) {&lt;br /&gt;
  var weapon = createWeapon(weaponVnum);&lt;br /&gt;
&lt;br /&gt;
  if (weapon.isSerpent) {&lt;br /&gt;
    showElement(randomAttackValue);&lt;br /&gt;
&lt;br /&gt;
    if (weapon.maxMagicAttackValue) {&lt;br /&gt;
      showElement(randomMagicAttackValue);&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    hideElement(randomAttackValue);&lt;br /&gt;
    hideElement(randomMagicAttackValue);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var upgradeNumber = weapon.upgrades.length;&lt;br /&gt;
&lt;br /&gt;
  if (upgradeNumber &amp;lt;= 1) {&lt;br /&gt;
    hideElement(weaponUpgrade.parentElement);&lt;br /&gt;
  } else {&lt;br /&gt;
    showElement(weaponUpgrade.parentElement);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  weaponUpgrade.innerHTML = &amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  for (var upgrade = 0; upgrade &amp;lt; upgradeNumber; upgrade++) {&lt;br /&gt;
    var option = document.createElement(&amp;quot;option&amp;quot;);&lt;br /&gt;
    option.value = upgrade;&lt;br /&gt;
    option.textContent = &amp;quot;+&amp;quot; + upgrade;&lt;br /&gt;
    weaponUpgrade.appendChild(option);&lt;br /&gt;
  }&lt;br /&gt;
  if (currentUpgrade === undefined) {&lt;br /&gt;
    option.selected = true;&lt;br /&gt;
  } else {&lt;br /&gt;
    weaponUpgrade.value = currentUpgrade;&lt;br /&gt;
    currentUpgrade = undefined;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterCheckbox(checkbox, element) {&lt;br /&gt;
  if (checkbox.checked) {&lt;br /&gt;
    showElement(element);&lt;br /&gt;
  } else {&lt;br /&gt;
    hideElement(element);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterSkills(selectedClass, skillElementsToFilter) {&lt;br /&gt;
  for (var element of skillElementsToFilter) {&lt;br /&gt;
    if (isValueInArray(selectedClass, element.dataset.class)) {&lt;br /&gt;
      showElement(element);&lt;br /&gt;
    } else {&lt;br /&gt;
      hideElement(element);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterAttackTypeSelection(attacker, attackTypeSelection) {&lt;br /&gt;
  var attackerClass = attacker.class;&lt;br /&gt;
  var selectedOption =&lt;br /&gt;
    attackTypeSelection.options[attackTypeSelection.selectedIndex];&lt;br /&gt;
  var attackerIsNotPolymorph = !isPolymorph(attacker);&lt;br /&gt;
&lt;br /&gt;
  for (var index = 2; index &amp;lt; attackTypeSelection.options.length; index++) {&lt;br /&gt;
    var option = attackTypeSelection.options[index];&lt;br /&gt;
    var optionClass = option.dataset.class;&lt;br /&gt;
    var optionValue = option.value;&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      attackerIsNotPolymorph &amp;amp;&amp;amp;&lt;br /&gt;
      attacker[optionValue] &amp;amp;&amp;amp;&lt;br /&gt;
      (attackerClass === optionClass ||&lt;br /&gt;
        (optionValue.startsWith(&amp;quot;horseSkill&amp;quot;) &amp;amp;&amp;amp;&lt;br /&gt;
          isRiding(attacker) &amp;amp;&amp;amp;&lt;br /&gt;
          (!optionClass || isValueInArray(attackerClass, optionClass))))&lt;br /&gt;
    ) {&lt;br /&gt;
      showElement(option);&lt;br /&gt;
    } else {&lt;br /&gt;
      hideElement(option);&lt;br /&gt;
&lt;br /&gt;
      if (selectedOption === option) {&lt;br /&gt;
        attackTypeSelection.selectedIndex = 0;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterAttackTypeSelectionMonster(attackTypeSelection) {&lt;br /&gt;
  for (var index = 2; index &amp;lt; attackTypeSelection.options.length; index++) {&lt;br /&gt;
    hideElement(attackTypeSelection.options[index]);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (attackTypeSelection.selectedIndex !== 1) {&lt;br /&gt;
    attackTypeSelection.selectedIndex = 0;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterForm(characters, battle) {&lt;br /&gt;
  var characterCreation = characters.characterCreation;&lt;br /&gt;
  var allowedWeaponsPerRace = battle.constants.allowedWeaponsPerRace;&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;change&amp;quot;, function (event) {&lt;br /&gt;
    var target = event.target;&lt;br /&gt;
    var targetName = target.name;&lt;br /&gt;
&lt;br /&gt;
    switch (targetName) {&lt;br /&gt;
      case &amp;quot;race&amp;quot;:&lt;br /&gt;
        var selectedRace = target.value;&lt;br /&gt;
        var classChoice = characterCreation.class;&lt;br /&gt;
        var weaponElement = characterCreation.weapon;&lt;br /&gt;
&lt;br /&gt;
        filterClass(selectedRace, classChoice);&lt;br /&gt;
        filterWeapon(&lt;br /&gt;
          selectedRace,&lt;br /&gt;
          weaponElement,&lt;br /&gt;
          characters.weaponCategory,&lt;br /&gt;
          allowedWeaponsPerRace&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        var newWeapon = getSelectedWeapon(characters.weaponCategory);&lt;br /&gt;
        handleWeaponDisplay(&lt;br /&gt;
          characters.weaponDisplay,&lt;br /&gt;
          newWeapon,&lt;br /&gt;
          weaponElement.value&lt;br /&gt;
        );&lt;br /&gt;
        filterUpgrade(&lt;br /&gt;
          characterCreation.weaponUpgrade,&lt;br /&gt;
          weaponElement.value,&lt;br /&gt;
          characters.randomAttackValue,&lt;br /&gt;
          characters.randomMagicAttackValue&lt;br /&gt;
        );&lt;br /&gt;
        filterSkills(classChoice.value, characters.skillElementsToFilter);&lt;br /&gt;
&lt;br /&gt;
        if (characterCreation.name.value === battle.attackerSelection.value) {&lt;br /&gt;
          battle.resetAttackType = true;&lt;br /&gt;
        }&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;class&amp;quot;:&lt;br /&gt;
        filterSkills(target.value, characters.skillElementsToFilter);&lt;br /&gt;
&lt;br /&gt;
        if (characterCreation.name.value === battle.attackerSelection.value) {&lt;br /&gt;
          battle.resetAttackType = true;&lt;br /&gt;
        }&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;weapon&amp;quot;:&lt;br /&gt;
        handleWeaponDisplay(&lt;br /&gt;
          characters.weaponDisplay,&lt;br /&gt;
          target,&lt;br /&gt;
          characterCreation.weapon.value&lt;br /&gt;
        );&lt;br /&gt;
        filterUpgrade(&lt;br /&gt;
          characterCreation.weaponUpgrade,&lt;br /&gt;
          target.value,&lt;br /&gt;
          characters.randomAttackValue,&lt;br /&gt;
          characters.randomMagicAttackValue&lt;br /&gt;
        );&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;isPolymorph&amp;quot;:&lt;br /&gt;
        filterCheckbox(&lt;br /&gt;
          target,&lt;br /&gt;
          characterCreation.polymorphMonster.parentElement&lt;br /&gt;
        );&lt;br /&gt;
        if (characterCreation.name.value === battle.attackerSelection.value) {&lt;br /&gt;
          battle.resetAttackType = true;&lt;br /&gt;
        }&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;lowRank&amp;quot;:&lt;br /&gt;
        filterCheckbox(target, characterCreation.playerRank.parentElement);&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;isBlessed&amp;quot;:&lt;br /&gt;
        filterCheckbox(target, characters.blessingCreation);&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;onYohara&amp;quot;:&lt;br /&gt;
        filterCheckbox(target, characters.yoharaCreation);&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;isMarried&amp;quot;:&lt;br /&gt;
        filterCheckbox(target, characters.marriageCreation);&lt;br /&gt;
        break;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      targetName.startsWith(&amp;quot;attackSkill&amp;quot;) ||&lt;br /&gt;
      targetName.startsWith(&amp;quot;horseSkill&amp;quot;)&lt;br /&gt;
    ) {&lt;br /&gt;
      battle.resetAttackType = true;&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addUniquePseudo(characterDataObject, savedCharactersPseudo) {&lt;br /&gt;
  var characterPseudo = String(characterDataObject.name);&lt;br /&gt;
  var originalPseudo = characterPseudo;&lt;br /&gt;
  var count = 0;&lt;br /&gt;
&lt;br /&gt;
  var regex = /(.*)(\d)$/;&lt;br /&gt;
  var match = characterPseudo.match(regex);&lt;br /&gt;
&lt;br /&gt;
  if (match) {&lt;br /&gt;
    originalPseudo = match[1];&lt;br /&gt;
    count = match[2];&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  while (isValueInArray(characterPseudo, savedCharactersPseudo)) {&lt;br /&gt;
    characterPseudo = originalPseudo + count;&lt;br /&gt;
    count++;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  characterDataObject.name = characterPseudo;&lt;br /&gt;
  return [characterDataObject, characterPseudo];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function convertToNumber(value) {&lt;br /&gt;
  var valueNumber = Number(value);&lt;br /&gt;
  return isNaN(valueNumber) ? value : valueNumber;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getLocalStorageValue(key, defaultValue) {&lt;br /&gt;
  var storedValue = localStorage.getItem(key);&lt;br /&gt;
&lt;br /&gt;
  if (storedValue) {&lt;br /&gt;
    return JSON.parse(storedValue);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return defaultValue;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSavedCharacters() {&lt;br /&gt;
  return getLocalStorageValue(&amp;quot;savedCharactersCalculator&amp;quot;, {});&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSavedMonsters() {&lt;br /&gt;
  var savedMonsters = getLocalStorageValue(&amp;quot;savedMonstersCalculator&amp;quot;, {});&lt;br /&gt;
&lt;br /&gt;
  if (Array.isArray(savedMonsters)) {&lt;br /&gt;
    return {};&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var filteredMonsters = {};&lt;br /&gt;
&lt;br /&gt;
  for (var vnum in savedMonsters) {&lt;br /&gt;
    if (String(Number(vnum)) === vnum) {&lt;br /&gt;
      filteredMonsters[vnum] = savedMonsters[vnum];&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return filteredMonsters;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSavedFights() {&lt;br /&gt;
  return getLocalStorageValue(&amp;quot;savedFightsCalculator&amp;quot;, []);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveToLocalStorage(key, value) {&lt;br /&gt;
  localStorage.setItem(key, JSON.stringify(value));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateSavedCharacters(savedCharacters) {&lt;br /&gt;
  saveToLocalStorage(&amp;quot;savedCharactersCalculator&amp;quot;, savedCharacters);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateSavedMonsters(savedMonsters) {&lt;br /&gt;
  saveToLocalStorage(&amp;quot;savedMonstersCalculator&amp;quot;, savedMonsters);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateSavedFights(savedFights) {&lt;br /&gt;
  saveToLocalStorage(&amp;quot;savedFightsCalculator&amp;quot;, savedFights);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveCharacter(&lt;br /&gt;
  savedCharacters,&lt;br /&gt;
  characterCreation,&lt;br /&gt;
  battle,&lt;br /&gt;
  newCharacter,&lt;br /&gt;
  characterDataObject&lt;br /&gt;
) {&lt;br /&gt;
  if (!characterDataObject) {&lt;br /&gt;
    var characterData = new FormData(characterCreation);&lt;br /&gt;
    var characterDataObject = {};&lt;br /&gt;
&lt;br /&gt;
    characterData.forEach(function (value, key) {&lt;br /&gt;
      characterDataObject[key] = convertToNumber(value);&lt;br /&gt;
    });&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  savedCharacters[characterDataObject.name] = characterDataObject;&lt;br /&gt;
  updateSavedCharacters(savedCharacters);&lt;br /&gt;
&lt;br /&gt;
  if (newCharacter) {&lt;br /&gt;
    addBattleChoice(battle, characterDataObject.name);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (battle.resetAttackType) {&lt;br /&gt;
    filterAttackTypeSelection(characterDataObject, battle.attackTypeSelection);&lt;br /&gt;
    battle.resetAttackType = false;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveButtonGreen(saveButton) {&lt;br /&gt;
  saveButton.classList.remove(&amp;quot;unsaved-character&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveButtonOrange(saveButton) {&lt;br /&gt;
  saveButton.classList.add(&amp;quot;unsaved-character&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function characterCreationListener(characters, battle) {&lt;br /&gt;
  var { characterCreation, saveButton, weaponCategory } = characters;&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;submit&amp;quot;, function (event) {&lt;br /&gt;
    event.preventDefault();&lt;br /&gt;
&lt;br /&gt;
    if (characters.unsavedChanges) {&lt;br /&gt;
      saveCharacter(characters.savedCharacters, characterCreation, battle);&lt;br /&gt;
      saveButtonGreen(saveButton);&lt;br /&gt;
      characters.unsavedChanges = false;&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  document.addEventListener(&amp;quot;keydown&amp;quot;, function (event) {&lt;br /&gt;
    if (event.ctrlKey &amp;amp;&amp;amp; event.key === &amp;quot;s&amp;quot;) {&lt;br /&gt;
      event.preventDefault();&lt;br /&gt;
      saveButton.click();&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  weaponCategory.addEventListener(&amp;quot;mouseover&amp;quot;, function (event) {&lt;br /&gt;
    label = event.target.closest(&amp;quot;label&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (label) {&lt;br /&gt;
      var tooltip = label.lastChild;&lt;br /&gt;
&lt;br /&gt;
      if (tooltip.classList.contains(&amp;quot;popContenu&amp;quot;)) {&lt;br /&gt;
        var tooltipRect = tooltip.getBoundingClientRect();&lt;br /&gt;
        var modalRect = weaponCategory.getBoundingClientRect();&lt;br /&gt;
&lt;br /&gt;
        if (tooltipRect.right &amp;gt; modalRect.right) {&lt;br /&gt;
          tooltip.style.left = &amp;quot;-100%&amp;quot;;&lt;br /&gt;
        } else if (tooltipRect.left &amp;lt; modalRect.left) {&lt;br /&gt;
          tooltip.style.left = &amp;quot;200%&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function downloadData(content, type, filename) {&lt;br /&gt;
  var link = document.createElement(&amp;quot;a&amp;quot;);&lt;br /&gt;
  var blob = new Blob([content], { type: type });&lt;br /&gt;
  var blobURL = URL.createObjectURL(blob);&lt;br /&gt;
&lt;br /&gt;
  link.href = blobURL;&lt;br /&gt;
  link.download = filename;&lt;br /&gt;
  document.body.appendChild(link);&lt;br /&gt;
&lt;br /&gt;
  link.click();&lt;br /&gt;
  document.body.removeChild(link);&lt;br /&gt;
  URL.revokeObjectURL(blobURL);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function uploadCharacter(&lt;br /&gt;
  selectedFiles,&lt;br /&gt;
  characters,&lt;br /&gt;
  characterTemplate,&lt;br /&gt;
  charactersContainer,&lt;br /&gt;
  battle&lt;br /&gt;
) {&lt;br /&gt;
  var selectFilesLength = selectedFiles.length;&lt;br /&gt;
&lt;br /&gt;
  for (var fileIndex = 0; fileIndex &amp;lt; selectFilesLength; fileIndex++) {&lt;br /&gt;
    var selectedFile = selectedFiles[fileIndex];&lt;br /&gt;
&lt;br /&gt;
    if (selectedFile.type === &amp;quot;text/plain&amp;quot;) {&lt;br /&gt;
      var reader = new FileReader();&lt;br /&gt;
      reader.onload = function (e) {&lt;br /&gt;
        var fileContent = e.target.result;&lt;br /&gt;
        try {&lt;br /&gt;
          var characterDataObject = JSON.parse(fileContent);&lt;br /&gt;
&lt;br /&gt;
          if (characterDataObject.hasOwnProperty(&amp;quot;name&amp;quot;)) {&lt;br /&gt;
            var characterPseudo = String(characterDataObject.name);&lt;br /&gt;
&lt;br /&gt;
            hideElement(characters.characterCreation);&lt;br /&gt;
            characterPseudo = validPseudo(characterPseudo);&lt;br /&gt;
&lt;br /&gt;
            [characterDataObject, characterPseudo] = addUniquePseudo(&lt;br /&gt;
              characterDataObject,&lt;br /&gt;
              Object.keys(characters.savedCharacters)&lt;br /&gt;
            );&lt;br /&gt;
            var selectedCharacter = handleNewCharacter(&lt;br /&gt;
              characters,&lt;br /&gt;
              characterTemplate,&lt;br /&gt;
              charactersContainer,&lt;br /&gt;
              battle,&lt;br /&gt;
              characterPseudo&lt;br /&gt;
            )[0];&lt;br /&gt;
&lt;br /&gt;
            if (selectFilesLength === 1) {&lt;br /&gt;
              updateForm(&lt;br /&gt;
                characterDataObject,&lt;br /&gt;
                characters.characterCreation,&lt;br /&gt;
                characters,&lt;br /&gt;
                selectedCharacter,&lt;br /&gt;
                battle&lt;br /&gt;
              );&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            saveCharacter(&lt;br /&gt;
              characters.savedCharacters,&lt;br /&gt;
              characters.characterCreation,&lt;br /&gt;
              battle,&lt;br /&gt;
              true,&lt;br /&gt;
              characterDataObject&lt;br /&gt;
            );&lt;br /&gt;
          }&lt;br /&gt;
        } catch (error) {&lt;br /&gt;
          console.log(error);&lt;br /&gt;
          if (error.name === &amp;quot;TypeError&amp;quot;) {&lt;br /&gt;
            // delete the character&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
      };&lt;br /&gt;
      reader.readAsText(selectedFile);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleUploadCharacter(&lt;br /&gt;
  characters,&lt;br /&gt;
  characterTemplate,&lt;br /&gt;
  charactersContainer,&lt;br /&gt;
  battle&lt;br /&gt;
) {&lt;br /&gt;
  var characterInput = characters.characterInput;&lt;br /&gt;
  var dropZone = characters.dropZone;&lt;br /&gt;
&lt;br /&gt;
  characterInput.accept = &amp;quot;.txt&amp;quot;;&lt;br /&gt;
  characterInput.multiple = true;&lt;br /&gt;
  dropZone.setAttribute(&amp;quot;tabindex&amp;quot;, &amp;quot;0&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  dropZone.addEventListener(&amp;quot;click&amp;quot;, function () {&lt;br /&gt;
    characterInput.click();&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  dropZone.addEventListener(&amp;quot;dragover&amp;quot;, function (event) {&lt;br /&gt;
    event.preventDefault();&lt;br /&gt;
    dropZone.classList.add(&amp;quot;drop-zone--dragover&amp;quot;);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  [&amp;quot;dragleave&amp;quot;, &amp;quot;dragend&amp;quot;].forEach(function (type) {&lt;br /&gt;
    dropZone.addEventListener(type, function () {&lt;br /&gt;
      dropZone.classList.remove(&amp;quot;drop-zone--dragover&amp;quot;);&lt;br /&gt;
    });&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  dropZone.addEventListener(&amp;quot;drop&amp;quot;, function (event) {&lt;br /&gt;
    event.preventDefault();&lt;br /&gt;
    uploadCharacter(&lt;br /&gt;
      event.dataTransfer.files,&lt;br /&gt;
      characters,&lt;br /&gt;
      characterTemplate,&lt;br /&gt;
      charactersContainer,&lt;br /&gt;
      battle&lt;br /&gt;
    );&lt;br /&gt;
    dropZone.classList.remove(&amp;quot;drop-zone--dragover&amp;quot;);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  characterInput.addEventListener(&amp;quot;change&amp;quot;, function (event) {&lt;br /&gt;
    uploadCharacter(&lt;br /&gt;
      event.target.files,&lt;br /&gt;
      characters,&lt;br /&gt;
      characterTemplate,&lt;br /&gt;
      charactersContainer,&lt;br /&gt;
      battle&lt;br /&gt;
    );&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function deleteCharacter(characters, pseudo, element, battle) {&lt;br /&gt;
  battle.battleForm.reset();&lt;br /&gt;
  delete characters.savedCharacters[pseudo];&lt;br /&gt;
  element.remove();&lt;br /&gt;
&lt;br /&gt;
  updateSavedCharacters(characters.savedCharacters);&lt;br /&gt;
  removeBattleChoice(battle, pseudo);&lt;br /&gt;
&lt;br /&gt;
  if (&lt;br /&gt;
    !Object.keys(characters.savedCharacters).length ||&lt;br /&gt;
    characters.characterCreation.name.value === pseudo&lt;br /&gt;
  ) {&lt;br /&gt;
    saveButtonGreen(characters.saveButton);&lt;br /&gt;
    characters.unsavedChanges = false;&lt;br /&gt;
    hideElement(characters.characterCreation);&lt;br /&gt;
    showElement(characters.characterCreation.previousElementSibling);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function deleteMonster(characters, battle, monsterVnum, monsterElement) {&lt;br /&gt;
  var monsterElement =&lt;br /&gt;
    monsterElement ||&lt;br /&gt;
    characters.monstersContainer.querySelector(&lt;br /&gt;
      &amp;quot;[data-monster-id='&amp;quot; + monsterVnum + &amp;quot;']&amp;quot;&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
  if (monsterElement) {&lt;br /&gt;
    monsterElement.remove();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  battle.battleForm.reset();&lt;br /&gt;
  delete characters.savedMonsters[monsterVnum];&lt;br /&gt;
&lt;br /&gt;
  updateSavedMonsters(characters.savedMonsters);&lt;br /&gt;
  removeBattleChoice(battle, monsterVnum);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleStyle(characters, selectedElement) {&lt;br /&gt;
  var currentCharacter = characters.currentCharacter;&lt;br /&gt;
&lt;br /&gt;
  if (currentCharacter) {&lt;br /&gt;
    currentCharacter.classList.remove(&amp;quot;selected-character&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  selectedElement.classList.add(&amp;quot;selected-character&amp;quot;);&lt;br /&gt;
  characters.currentCharacter = selectedElement;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateForm(&lt;br /&gt;
  formData,&lt;br /&gt;
  characterCreation,&lt;br /&gt;
  characters,&lt;br /&gt;
  selectedElement,&lt;br /&gt;
  battle&lt;br /&gt;
) {&lt;br /&gt;
  saveButtonGreen(characters.saveButton);&lt;br /&gt;
  hideElement(characterCreation.previousElementSibling);&lt;br /&gt;
  showElement(characterCreation);&lt;br /&gt;
  handleStyle(characters, selectedElement);&lt;br /&gt;
&lt;br /&gt;
  characterCreation.reset();&lt;br /&gt;
&lt;br /&gt;
  for (var [name, value] of Object.entries(formData)) {&lt;br /&gt;
    var formElement = characterCreation[name];&lt;br /&gt;
&lt;br /&gt;
    if (!formElement) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (formElement.type === &amp;quot;checkbox&amp;quot;) {&lt;br /&gt;
      if (isChecked(value)) {&lt;br /&gt;
        formElement.checked = true;&lt;br /&gt;
      }&lt;br /&gt;
    } else {&lt;br /&gt;
      formElement.value = value;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  var selectedRace = characterCreation.race.value;&lt;br /&gt;
  var classChoice = characterCreation.class;&lt;br /&gt;
  var weaponElement = characterCreation.weapon;&lt;br /&gt;
&lt;br /&gt;
  filterClass(selectedRace, classChoice, true);&lt;br /&gt;
  filterWeapon(&lt;br /&gt;
    selectedRace,&lt;br /&gt;
    weaponElement,&lt;br /&gt;
    characters.weaponCategory,&lt;br /&gt;
    battle.constants.allowedWeaponsPerRace,&lt;br /&gt;
    true&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  var newWeapon = getSelectedWeapon(characters.weaponCategory);&lt;br /&gt;
&lt;br /&gt;
  handleWeaponDisplay(characters.weaponDisplay, newWeapon, weaponElement.value);&lt;br /&gt;
  filterUpgrade(&lt;br /&gt;
    characterCreation.weaponUpgrade,&lt;br /&gt;
    weaponElement.value,&lt;br /&gt;
    characters.randomAttackValue,&lt;br /&gt;
    characters.randomMagicAttackValue,&lt;br /&gt;
    formData.weaponUpgrade&lt;br /&gt;
  );&lt;br /&gt;
  filterCheckbox(&lt;br /&gt;
    characterCreation.isPolymorph,&lt;br /&gt;
    characterCreation.polymorphMonster.parentElement&lt;br /&gt;
  );&lt;br /&gt;
  filterCheckbox(&lt;br /&gt;
    characterCreation.lowRank,&lt;br /&gt;
    characterCreation.playerRank.parentElement&lt;br /&gt;
  );&lt;br /&gt;
  filterCheckbox(characterCreation.onYohara, characters.yoharaCreation);&lt;br /&gt;
  filterCheckbox(characterCreation.isBlessed, characters.blessingCreation);&lt;br /&gt;
  filterCheckbox(characterCreation.isMarried, characters.marriageCreation);&lt;br /&gt;
  filterSkills(classChoice.value, characters.skillElementsToFilter);&lt;br /&gt;
  handleBonusVariationUpdate(characterCreation, characters.bonusVariation);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleClickOnCharacter(&lt;br /&gt;
  spanInput,&lt;br /&gt;
  target,&lt;br /&gt;
  characters,&lt;br /&gt;
  characterElement,&lt;br /&gt;
  battle,&lt;br /&gt;
  edition&lt;br /&gt;
) {&lt;br /&gt;
  var displayedPseudo = characters.characterCreation.name.value;&lt;br /&gt;
  var pseudo = spanInput.dataset.name;&lt;br /&gt;
&lt;br /&gt;
  if (edition) {&lt;br /&gt;
    if (!characters.unsavedChanges) {&lt;br /&gt;
      updateForm(&lt;br /&gt;
        characters.savedCharacters[pseudo],&lt;br /&gt;
        characters.characterCreation,&lt;br /&gt;
        characters,&lt;br /&gt;
        characterElement,&lt;br /&gt;
        battle&lt;br /&gt;
      );&lt;br /&gt;
    } else if (displayedPseudo === pseudo) {&lt;br /&gt;
      // pass&lt;br /&gt;
    } else {&lt;br /&gt;
      var result = confirm(&lt;br /&gt;
        &amp;quot;Voulez-vous continuer ? Les dernières modifications ne seront pas sauvegardées.&amp;quot;&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      if (result) {&lt;br /&gt;
        updateForm(&lt;br /&gt;
          characters.savedCharacters[pseudo],&lt;br /&gt;
          characters.characterCreation,&lt;br /&gt;
          characters,&lt;br /&gt;
          characterElement,&lt;br /&gt;
          battle&lt;br /&gt;
        );&lt;br /&gt;
        characters.unsavedChanges = false;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    if (target.tagName === &amp;quot;path&amp;quot;) {&lt;br /&gt;
      target = target.parentElement;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    switch (target.dataset.icon) {&lt;br /&gt;
      case &amp;quot;duplicate&amp;quot;:&lt;br /&gt;
        if (!characters.unsavedChanges) {&lt;br /&gt;
          addNewCharacter(&lt;br /&gt;
            characters,&lt;br /&gt;
            characters.newCharacterTemplate,&lt;br /&gt;
            characters.charactersContainer,&lt;br /&gt;
            battle,&lt;br /&gt;
            pseudo&lt;br /&gt;
          );&lt;br /&gt;
        } else {&lt;br /&gt;
          var result = confirm(&lt;br /&gt;
            &amp;quot;Voulez-vous continuer ? Les dernières modifications ne seront pas sauvegardées.&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
&lt;br /&gt;
          if (result) {&lt;br /&gt;
            addNewCharacter(&lt;br /&gt;
              characters,&lt;br /&gt;
              characters.newCharacterTemplate,&lt;br /&gt;
              characters.charactersContainer,&lt;br /&gt;
              battle,&lt;br /&gt;
              pseudo&lt;br /&gt;
            );&lt;br /&gt;
            saveButtonGreen(characters.saveButton);&lt;br /&gt;
            characters.unsavedChanges = false;&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
        break;&lt;br /&gt;
&lt;br /&gt;
      case &amp;quot;download&amp;quot;:&lt;br /&gt;
        var character = characters.savedCharacters[pseudo];&lt;br /&gt;
        downloadData(&lt;br /&gt;
          JSON.stringify(character),&lt;br /&gt;
          &amp;quot;text/plain&amp;quot;,&lt;br /&gt;
          character.name + &amp;quot;.txt&amp;quot;&lt;br /&gt;
        );&lt;br /&gt;
        break;&lt;br /&gt;
&lt;br /&gt;
      case &amp;quot;delete&amp;quot;:&lt;br /&gt;
        var result = confirm(&lt;br /&gt;
          &amp;quot;Voulez-vous vraiment supprimer définitivement le personnage &amp;quot; +&lt;br /&gt;
            pseudo +&lt;br /&gt;
            &amp;quot; ?&amp;quot;&lt;br /&gt;
        );&lt;br /&gt;
        if (result) {&lt;br /&gt;
          deleteCharacter(characters, pseudo, characterElement, battle);&lt;br /&gt;
        }&lt;br /&gt;
        break;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleNewCharacter(&lt;br /&gt;
  characters,&lt;br /&gt;
  characterTemplate,&lt;br /&gt;
  charactersContainer,&lt;br /&gt;
  battle,&lt;br /&gt;
  pseudo&lt;br /&gt;
) {&lt;br /&gt;
  var newCharacterTemplate = characterTemplate.cloneNode(true);&lt;br /&gt;
  var spanInput = newCharacterTemplate.querySelector(&amp;quot;span.input&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  newCharacterTemplate.setAttribute(&amp;quot;tabindex&amp;quot;, &amp;quot;0&amp;quot;);&lt;br /&gt;
  charactersContainer.appendChild(newCharacterTemplate);&lt;br /&gt;
&lt;br /&gt;
  if (pseudo) {&lt;br /&gt;
    spanInput.textContent = pseudo;&lt;br /&gt;
    spanInput.setAttribute(&amp;quot;data-name&amp;quot;, pseudo);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  newCharacterTemplate.addEventListener(&amp;quot;click&amp;quot;, function (event) {&lt;br /&gt;
    var target = event.target;&lt;br /&gt;
&lt;br /&gt;
    if (target.tagName === &amp;quot;path&amp;quot; || target.tagName === &amp;quot;svg&amp;quot;) {&lt;br /&gt;
      handleClickOnCharacter(&lt;br /&gt;
        spanInput,&lt;br /&gt;
        target,&lt;br /&gt;
        characters,&lt;br /&gt;
        newCharacterTemplate,&lt;br /&gt;
        battle&lt;br /&gt;
      );&lt;br /&gt;
    } else {&lt;br /&gt;
      handleClickOnCharacter(&lt;br /&gt;
        spanInput,&lt;br /&gt;
        null,&lt;br /&gt;
        characters,&lt;br /&gt;
        newCharacterTemplate,&lt;br /&gt;
        battle,&lt;br /&gt;
        true&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  newCharacterTemplate.addEventListener(&amp;quot;keydown&amp;quot;, function (event) {&lt;br /&gt;
    if (event.keyCode === 13) {&lt;br /&gt;
      event.target.click();&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  return [newCharacterTemplate, spanInput];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function validPseudo(pseudo) {&lt;br /&gt;
  var newPseudo = pseudoFormat(pseudo);&lt;br /&gt;
&lt;br /&gt;
  if (!newPseudo) {&lt;br /&gt;
    return &amp;quot;Pseudo&amp;quot;;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return newPseudo;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addNewCharacter(&lt;br /&gt;
  characters,&lt;br /&gt;
  characterTemplate,&lt;br /&gt;
  charactersContainer,&lt;br /&gt;
  battle,&lt;br /&gt;
  pseudoToDuplicate&lt;br /&gt;
) {&lt;br /&gt;
  function editAndSetCharacterPseudoInput(selectedCharacter, spanInput) {&lt;br /&gt;
    var maxPseudoLength = 20;&lt;br /&gt;
&lt;br /&gt;
    var selection = window.getSelection();&lt;br /&gt;
    var range = document.createRange();&lt;br /&gt;
&lt;br /&gt;
    if (pseudoToDuplicate) {&lt;br /&gt;
      spanInput.textContent = pseudoToDuplicate;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    spanInput.contentEditable = true;&lt;br /&gt;
    spanInput.focus();&lt;br /&gt;
    range.selectNodeContents(spanInput);&lt;br /&gt;
    selection.removeAllRanges();&lt;br /&gt;
    selection.addRange(range);&lt;br /&gt;
&lt;br /&gt;
    function pseudoValidation() {&lt;br /&gt;
      var characterPseudo = validPseudo(spanInput.textContent);&lt;br /&gt;
      var characterDataObject = { name: characterPseudo };&lt;br /&gt;
&lt;br /&gt;
      if (pseudoToDuplicate) {&lt;br /&gt;
        characterDataObject = copyObject(&lt;br /&gt;
          characters.savedCharacters[pseudoToDuplicate]&lt;br /&gt;
        );&lt;br /&gt;
        characterDataObject.name = characterPseudo;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      [characterDataObject, characterPseudo] = addUniquePseudo(&lt;br /&gt;
        characterDataObject,&lt;br /&gt;
        Object.keys(characters.savedCharacters)&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      selection.removeAllRanges();&lt;br /&gt;
      spanInput.contentEditable = false;&lt;br /&gt;
      spanInput.textContent = characterPseudo;&lt;br /&gt;
      spanInput.setAttribute(&amp;quot;data-name&amp;quot;, characterPseudo);&lt;br /&gt;
&lt;br /&gt;
      updateForm(&lt;br /&gt;
        characterDataObject,&lt;br /&gt;
        characters.characterCreation,&lt;br /&gt;
        characters,&lt;br /&gt;
        selectedCharacter,&lt;br /&gt;
        battle&lt;br /&gt;
      );&lt;br /&gt;
      saveCharacter(&lt;br /&gt;
        characters.savedCharacters,&lt;br /&gt;
        characters.characterCreation,&lt;br /&gt;
        battle,&lt;br /&gt;
        true&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handleMaxLength(event) {&lt;br /&gt;
      if (spanInput.textContent.length &amp;gt; maxPseudoLength) {&lt;br /&gt;
        spanInput.textContent = spanInput.textContent.slice(0, maxPseudoLength);&lt;br /&gt;
        range.setStart(spanInput.childNodes[0], maxPseudoLength);&lt;br /&gt;
        selection.removeAllRanges();&lt;br /&gt;
        selection.addRange(range);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handleBlur() {&lt;br /&gt;
      spanInput.removeEventListener(&amp;quot;blur&amp;quot;, handleBlur);&lt;br /&gt;
      spanInput.removeEventListener(&amp;quot;input&amp;quot;, handleMaxLength);&lt;br /&gt;
      pseudoValidation();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handleKeyDown(event) {&lt;br /&gt;
      if (event.key === &amp;quot;Enter&amp;quot;) {&lt;br /&gt;
        event.preventDefault();&lt;br /&gt;
&lt;br /&gt;
        spanInput.removeEventListener(&amp;quot;keydown&amp;quot;, handleKeyDown);&lt;br /&gt;
        spanInput.removeEventListener(&amp;quot;blur&amp;quot;, handleBlur);&lt;br /&gt;
        spanInput.removeEventListener(&amp;quot;input&amp;quot;, handleMaxLength);&lt;br /&gt;
&lt;br /&gt;
        pseudoValidation();&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    spanInput.addEventListener(&amp;quot;input&amp;quot;, handleMaxLength);&lt;br /&gt;
    spanInput.addEventListener(&amp;quot;keydown&amp;quot;, handleKeyDown);&lt;br /&gt;
    spanInput.addEventListener(&amp;quot;blur&amp;quot;, handleBlur);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  hideElement(characters.characterCreation);&lt;br /&gt;
  var [selectedCharacter, spanInput] = handleNewCharacter(&lt;br /&gt;
    characters,&lt;br /&gt;
    characterTemplate,&lt;br /&gt;
    charactersContainer,&lt;br /&gt;
    battle&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  editAndSetCharacterPseudoInput(selectedCharacter, spanInput);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleFocus() {&lt;br /&gt;
  var tooltipLinks = document.querySelectorAll(&amp;quot;div.tooltip a&amp;quot;);&lt;br /&gt;
  tooltipLinks.forEach(function (link) {&lt;br /&gt;
    link.setAttribute(&amp;quot;tabindex&amp;quot;, -1);&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleBonusVariationUpdate(characterCreation, bonusVariation) {&lt;br /&gt;
  var selectedBonus = characterCreation.bonusVariation.value;&lt;br /&gt;
&lt;br /&gt;
  if (characterCreation.hasOwnProperty(selectedBonus)) {&lt;br /&gt;
    handleBonusVariation(characterCreation[selectedBonus], bonusVariation);&lt;br /&gt;
  } else {&lt;br /&gt;
    var { minValue, maxValue } = bonusVariation;&lt;br /&gt;
&lt;br /&gt;
    minValue.removeAttribute(&amp;quot;min&amp;quot;);&lt;br /&gt;
    minValue.removeAttribute(&amp;quot;max&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    maxValue.removeAttribute(&amp;quot;min&amp;quot;);&lt;br /&gt;
    maxValue.removeAttribute(&amp;quot;max&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    hideElement(bonusVariation.container);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getTargetContent(targetParent, targetName, isSkill) {&lt;br /&gt;
  var targetContent = &amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  if (targetParent.children.length &amp;lt;= 1) {&lt;br /&gt;
    targetContent = targetParent.textContent;&lt;br /&gt;
  } else if (targetName === &amp;quot;weaponUpgrade&amp;quot;) {&lt;br /&gt;
    targetContent = targetParent.children[1].textContent;&lt;br /&gt;
  } else if (isSkill) {&lt;br /&gt;
    var container = targetParent.children[1];&lt;br /&gt;
&lt;br /&gt;
    for (var index = 1; index &amp;lt; container.children.length; index++) {&lt;br /&gt;
      var element = container.children[index];&lt;br /&gt;
&lt;br /&gt;
      if (element.checkVisibility()) {&lt;br /&gt;
        targetContent += element.textContent;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    for (var index = 1; index &amp;lt; targetParent.children.length; index++) {&lt;br /&gt;
      var element = targetParent.children[index];&lt;br /&gt;
&lt;br /&gt;
      if (element.checkVisibility()) {&lt;br /&gt;
        targetContent += element.textContent;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return targetContent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleBonusVariation(target, bonusVariation, isSelectedByUser) {&lt;br /&gt;
  var { activation, inputDisplay, minValue, maxValue, container } =&lt;br /&gt;
    bonusVariation;&lt;br /&gt;
&lt;br /&gt;
  var {&lt;br /&gt;
    min: targetMin,&lt;br /&gt;
    max: targetMax,&lt;br /&gt;
    name: targetName,&lt;br /&gt;
    value: targetValue,&lt;br /&gt;
    parentElement: targetParent,&lt;br /&gt;
    tagName,&lt;br /&gt;
  } = target;&lt;br /&gt;
&lt;br /&gt;
  targetMin = Number(targetMin);&lt;br /&gt;
  targetMax = Number(targetMax);&lt;br /&gt;
  targetValue = Number(targetValue);&lt;br /&gt;
&lt;br /&gt;
  var isSkill = tagName === &amp;quot;SELECT&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  if (container.contains(target) || targetName == 0) {&lt;br /&gt;
    if (!isSelectedByUser) {&lt;br /&gt;
      hideElement(container);&lt;br /&gt;
    }&lt;br /&gt;
    return;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (isSkill) {&lt;br /&gt;
    var options = target.options;&lt;br /&gt;
&lt;br /&gt;
    targetMin = options[0].value;&lt;br /&gt;
    targetMax = options[options.length - 1].value;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  minValue.min = targetMin;&lt;br /&gt;
  minValue.max = targetMax;&lt;br /&gt;
&lt;br /&gt;
  maxValue.min = targetMin;&lt;br /&gt;
  maxValue.max = targetMax;&lt;br /&gt;
&lt;br /&gt;
  if (isSelectedByUser) {&lt;br /&gt;
    var { input, tab } = bonusVariation;&lt;br /&gt;
&lt;br /&gt;
    inputDisplay.value = getTargetContent(targetParent, targetName, isSkill);&lt;br /&gt;
&lt;br /&gt;
    input.value = targetName;&lt;br /&gt;
    minValue.value = Math.max(targetValue - 10, targetMin);&lt;br /&gt;
    maxValue.value = Math.min(targetValue + 10, targetMax);&lt;br /&gt;
&lt;br /&gt;
    activation.checked = true;&lt;br /&gt;
&lt;br /&gt;
    tab.click();&lt;br /&gt;
    tab.scrollIntoView(true);&lt;br /&gt;
&lt;br /&gt;
    input.dispatchEvent(new Event(&amp;quot;change&amp;quot;, { bubbles: true }));&lt;br /&gt;
  } else {&lt;br /&gt;
    if (minValue.value &amp;lt; targetMin) {&lt;br /&gt;
      minValue.value = targetMin;&lt;br /&gt;
      minValue.dispatchEvent(new Event(&amp;quot;change&amp;quot;, { bubbles: true }));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (maxValue.value &amp;gt; targetMax) {&lt;br /&gt;
      maxValue.value = targetMax;&lt;br /&gt;
      maxValue.dispatchEvent(new Event(&amp;quot;change&amp;quot;, { bubbles: true }));&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  inputDisplay.style.width = inputDisplay.value.length * 0.55 + &amp;quot;em&amp;quot;;&lt;br /&gt;
  showElement(container);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function characterManagement(characters, battle) {&lt;br /&gt;
  var {&lt;br /&gt;
    newCharacterTemplate: characterTemplate,&lt;br /&gt;
    charactersContainer,&lt;br /&gt;
    addNewCharacterButton,&lt;br /&gt;
    saveButton,&lt;br /&gt;
    characterCreation,&lt;br /&gt;
    bonusVariation,&lt;br /&gt;
  } = characters;&lt;br /&gt;
&lt;br /&gt;
  Object.keys(characters.savedCharacters).forEach(function (pseudo) {&lt;br /&gt;
    handleNewCharacter(&lt;br /&gt;
      characters,&lt;br /&gt;
      characterTemplate,&lt;br /&gt;
      charactersContainer,&lt;br /&gt;
      battle,&lt;br /&gt;
      pseudo&lt;br /&gt;
    );&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  addNewCharacterButton.addEventListener(&amp;quot;click&amp;quot;, function (event) {&lt;br /&gt;
    if (!characters.unsavedChanges) {&lt;br /&gt;
      addNewCharacter(&lt;br /&gt;
        characters,&lt;br /&gt;
        characterTemplate,&lt;br /&gt;
        charactersContainer,&lt;br /&gt;
        battle&lt;br /&gt;
      );&lt;br /&gt;
    } else {&lt;br /&gt;
      var result = confirm(&lt;br /&gt;
        &amp;quot;Voulez-vous continuer ? Les dernières modifications ne seront pas sauvegardées.&amp;quot;&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      if (result) {&lt;br /&gt;
        addNewCharacter(&lt;br /&gt;
          characters,&lt;br /&gt;
          characterTemplate,&lt;br /&gt;
          charactersContainer,&lt;br /&gt;
          battle&lt;br /&gt;
        );&lt;br /&gt;
        saveButtonGreen(saveButton);&lt;br /&gt;
        characters.unsavedChanges = false;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  handleUploadCharacter(&lt;br /&gt;
    characters,&lt;br /&gt;
    characterTemplate,&lt;br /&gt;
    charactersContainer,&lt;br /&gt;
    battle&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;change&amp;quot;, function () {&lt;br /&gt;
    saveButtonOrange(saveButton);&lt;br /&gt;
    characters.unsavedChanges = true;&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  function handleLongPress(target) {&lt;br /&gt;
    if (target.tagName !== &amp;quot;INPUT&amp;quot; &amp;amp;&amp;amp; target.tagName !== &amp;quot;SELECT&amp;quot;) {&lt;br /&gt;
      target = target.querySelector(&amp;quot;input&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      !target ||&lt;br /&gt;
      (target.type !== &amp;quot;number&amp;quot; &amp;amp;&amp;amp;&lt;br /&gt;
        !target.classList.contains(&amp;quot;skill-select&amp;quot;) &amp;amp;&amp;amp;&lt;br /&gt;
        target.name !== &amp;quot;weaponUpgrade&amp;quot;)&lt;br /&gt;
    ) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    handleBonusVariation(target, bonusVariation, true);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;click&amp;quot;, function (event) {&lt;br /&gt;
    if (event.shiftKey || event.ctrlKey) {&lt;br /&gt;
      handleLongPress(event.target);&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  var longPressTimer;&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;touchstart&amp;quot;, function (event) {&lt;br /&gt;
    longPressTimer = setTimeout(function () {&lt;br /&gt;
      handleLongPress(event.target);&lt;br /&gt;
    }, 800);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;touchend&amp;quot;, function () {&lt;br /&gt;
    clearTimeout(longPressTimer);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;touchmove&amp;quot;, function () {&lt;br /&gt;
    clearTimeout(longPressTimer);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  filterForm(characters, battle);&lt;br /&gt;
  characterCreationListener(characters, battle);&lt;br /&gt;
  handleFocus();&lt;br /&gt;
&lt;br /&gt;
  window.addEventListener(&amp;quot;beforeunload&amp;quot;, function (event) {&lt;br /&gt;
    if (characters.unsavedChanges) {&lt;br /&gt;
      event.preventDefault();&lt;br /&gt;
      return &amp;quot;&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function removeFromIframe(iframe, monsterVnum, addButton) {&lt;br /&gt;
  var iframeDoc = iframe.contentDocument || iframe.contentWindow.document;&lt;br /&gt;
  var removeButton = iframeDoc.querySelector(&lt;br /&gt;
    &amp;quot;.handle-monster[data-monster-id='&amp;quot; + monsterVnum + &amp;quot;']&amp;quot;&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  if (removeButton) {&lt;br /&gt;
    replaceMonsterButton(removeButton, addButton, monsterVnum);&lt;br /&gt;
    return true;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return false;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addMonsterElement(characters, battle, monsterVnum) {&lt;br /&gt;
  var {&lt;br /&gt;
    monsteriFrame,&lt;br /&gt;
    stoneiFrame,&lt;br /&gt;
    monsterTemplate,&lt;br /&gt;
    monstersContainer,&lt;br /&gt;
    monsterButtonTemplates,&lt;br /&gt;
  } = characters;&lt;br /&gt;
  var addButton = monsterButtonTemplates.children[0];&lt;br /&gt;
  var monsterElement = monsterTemplate.cloneNode(true);&lt;br /&gt;
&lt;br /&gt;
  var spanInput = monsterElement.querySelector(&amp;quot;span.input&amp;quot;);&lt;br /&gt;
  var deleteSvg = monsterElement.querySelector(&amp;quot;svg&amp;quot;);&lt;br /&gt;
  var monsterName = getMonsterName(monsterVnum);&lt;br /&gt;
&lt;br /&gt;
  var link = document.createElement(&amp;quot;a&amp;quot;);&lt;br /&gt;
  link.href = mw.util.getUrl(monsterName);&lt;br /&gt;
  link.title = monsterName;&lt;br /&gt;
  link.textContent = monsterName;&lt;br /&gt;
&lt;br /&gt;
  spanInput.appendChild(link);&lt;br /&gt;
&lt;br /&gt;
  monsterElement.setAttribute(&amp;quot;tabindex&amp;quot;, &amp;quot;0&amp;quot;);&lt;br /&gt;
  monsterElement.setAttribute(&amp;quot;data-monster-id&amp;quot;, monsterVnum);&lt;br /&gt;
&lt;br /&gt;
  monstersContainer.appendChild(monsterElement);&lt;br /&gt;
&lt;br /&gt;
  deleteSvg.addEventListener(&amp;quot;click&amp;quot;, function () {&lt;br /&gt;
    deleteMonster(characters, battle, monsterVnum, monsterElement);&lt;br /&gt;
    var isRemoved = removeFromIframe(monsteriFrame, monsterVnum, addButton);&lt;br /&gt;
    if (!isRemoved) {&lt;br /&gt;
      removeFromIframe(stoneiFrame, monsterVnum, addButton);&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addNewMonster(characters, battle, monsterVnum, monsterImage) {&lt;br /&gt;
  if (isValueInArray(monsterVnum, Object.keys(characters.savedMonsters)))&lt;br /&gt;
    return;&lt;br /&gt;
&lt;br /&gt;
  characters.savedMonsters[monsterVnum] = { image: monsterImage };&lt;br /&gt;
  addMonsterElement(characters, battle, monsterVnum);&lt;br /&gt;
  updateSavedMonsters(characters.savedMonsters);&lt;br /&gt;
  addBattleChoice(battle, monsterVnum, true);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function replaceMonsterButton(currentButton, newButton, monsterVnum) {&lt;br /&gt;
  var newButtonClone = newButton.cloneNode(true);&lt;br /&gt;
  newButtonClone.dataset.monsterId = monsterVnum;&lt;br /&gt;
  currentButton.replaceWith(newButtonClone);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addButtonsToCards(&lt;br /&gt;
  iframeDoc,&lt;br /&gt;
  nameToVnum,&lt;br /&gt;
  addButton,&lt;br /&gt;
  removeButton,&lt;br /&gt;
  characters&lt;br /&gt;
) {&lt;br /&gt;
  var cardToEdit = iframeDoc.getElementById(&amp;quot;cards-container&amp;quot;).children;&lt;br /&gt;
  var addedMonsters = Object.keys(characters.savedMonsters);&lt;br /&gt;
&lt;br /&gt;
  for (var cardIndex = 0; cardIndex &amp;lt; cardToEdit.length; cardIndex++) {&lt;br /&gt;
    var card = cardToEdit[cardIndex];&lt;br /&gt;
    var cardName = card.querySelector(&amp;quot;[data-name]&amp;quot;).firstChild.title;&lt;br /&gt;
&lt;br /&gt;
    if (!nameToVnum.hasOwnProperty(cardName)) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var monsterVnum = nameToVnum[cardName];&lt;br /&gt;
    var buttonClone;&lt;br /&gt;
&lt;br /&gt;
    if (isValueInArray(monsterVnum, addedMonsters)) {&lt;br /&gt;
      buttonClone = removeButton.cloneNode(true);&lt;br /&gt;
    } else {&lt;br /&gt;
      buttonClone = addButton.cloneNode(true);&lt;br /&gt;
    }&lt;br /&gt;
    buttonClone.dataset.monsterId = monsterVnum;&lt;br /&gt;
    card.lastElementChild.appendChild(buttonClone);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getMonsterImage(addButton) {&lt;br /&gt;
  var elder = addButton.parentElement.firstElementChild;&lt;br /&gt;
  var image = elder.querySelector(&amp;quot;img&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (image) {&lt;br /&gt;
    return image.getAttribute(&amp;quot;src&amp;quot;) || &amp;quot;&amp;quot;;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return &amp;quot;&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleiFrame(category, iframe, nameToVnum, characters, battle) {&lt;br /&gt;
  var [addButton, removeButton] = characters.monsterButtonTemplates.children;&lt;br /&gt;
&lt;br /&gt;
  iframe.src = mw.util.getUrl(category);&lt;br /&gt;
&lt;br /&gt;
  iframe.addEventListener(&amp;quot;load&amp;quot;, function () {&lt;br /&gt;
    var iframeDoc = this.contentDocument || this.contentWindow.document;&lt;br /&gt;
    var iframeBody = iframeDoc.body;&lt;br /&gt;
&lt;br /&gt;
    content = iframeDoc.getElementById(&amp;quot;show-after-loading&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    iframeBody.firstElementChild.replaceWith(content);&lt;br /&gt;
&lt;br /&gt;
    iframeBody.style.background = &amp;quot;transparent&amp;quot;;&lt;br /&gt;
    iframeBody.style.paddingRight = &amp;quot;10px&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    addButtonsToCards(&lt;br /&gt;
      iframeDoc,&lt;br /&gt;
      nameToVnum,&lt;br /&gt;
      addButton,&lt;br /&gt;
      removeButton,&lt;br /&gt;
      characters&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    iframeDoc.addEventListener(&amp;quot;click&amp;quot;, function (event) {&lt;br /&gt;
      var target = event.target;&lt;br /&gt;
      var link = target.closest(&amp;quot;a&amp;quot;);&lt;br /&gt;
      var currentButton = target.closest(&amp;quot;.handle-monster&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
      if (link) {&lt;br /&gt;
        event.preventDefault();&lt;br /&gt;
        window.open(link.href, &amp;quot;_blank&amp;quot;);&lt;br /&gt;
      } else if (currentButton) {&lt;br /&gt;
        var { monsterId: monsterVnum, action } = currentButton.dataset;&lt;br /&gt;
        var newButton;&lt;br /&gt;
&lt;br /&gt;
        if (action === &amp;quot;add&amp;quot;) {&lt;br /&gt;
          var monsterImage = getMonsterImage(currentButton);&lt;br /&gt;
          addNewMonster(characters, battle, monsterVnum, monsterImage);&lt;br /&gt;
          newButton = removeButton;&lt;br /&gt;
        } else if (action === &amp;quot;remove&amp;quot;) {&lt;br /&gt;
          deleteMonster(characters, battle, monsterVnum);&lt;br /&gt;
          newButton = addButton;&lt;br /&gt;
        }&lt;br /&gt;
        replaceMonsterButton(currentButton, newButton, monsterVnum);&lt;br /&gt;
      }&lt;br /&gt;
    });&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getNameToVnumMapping() {&lt;br /&gt;
  var nameToVnum = {};&lt;br /&gt;
&lt;br /&gt;
  for (var monsterVnum in monsterData) {&lt;br /&gt;
    nameToVnum[monsterData[monsterVnum][monsterData[monsterVnum].length - 1]] =&lt;br /&gt;
      monsterVnum;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return nameToVnum;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function monsterManagement(characters, battle) {&lt;br /&gt;
  var { monsteriFrame, stoneiFrame } = characters;&lt;br /&gt;
  var nameToVnum = getNameToVnumMapping();&lt;br /&gt;
  var monsterVnums = Object.keys(monsterData);&lt;br /&gt;
&lt;br /&gt;
  var iframeLoaded = { monster: false, stone: false };&lt;br /&gt;
&lt;br /&gt;
  document.addEventListener(&amp;quot;modalOpen&amp;quot;, function (event) {&lt;br /&gt;
    var modalName = event.detail.name;&lt;br /&gt;
&lt;br /&gt;
    if (modalName === &amp;quot;monster&amp;quot; &amp;amp;&amp;amp; !iframeLoaded.monster) {&lt;br /&gt;
      handleiFrame(&amp;quot;Monstres&amp;quot;, monsteriFrame, nameToVnum, characters, battle);&lt;br /&gt;
      iframeLoaded.monster = true;&lt;br /&gt;
    } else if (modalName === &amp;quot;stone&amp;quot; &amp;amp;&amp;amp; !iframeLoaded.stone) {&lt;br /&gt;
      handleiFrame(&lt;br /&gt;
        &amp;quot;Pierres Metin&amp;quot;,&lt;br /&gt;
        stoneiFrame,&lt;br /&gt;
        nameToVnum,&lt;br /&gt;
        characters,&lt;br /&gt;
        battle&lt;br /&gt;
      );&lt;br /&gt;
      iframeLoaded.stone = true;&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  Object.keys(characters.savedMonsters)&lt;br /&gt;
    .slice()&lt;br /&gt;
    .forEach(function (monsterVnum) {&lt;br /&gt;
      if (isValueInArray(monsterVnum, monsterVnums)) {&lt;br /&gt;
        addMonsterElement(characters, battle, monsterVnum);&lt;br /&gt;
      } else {&lt;br /&gt;
        deleteMonster(characters, battle, monsterVnum);&lt;br /&gt;
      }&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function removeBattleChoice(battle, name) {&lt;br /&gt;
  var battleSelects = [battle.attackerSelection, battle.victimSelection];&lt;br /&gt;
&lt;br /&gt;
  battleSelects.forEach(function (battleSelect) {&lt;br /&gt;
    for (&lt;br /&gt;
      var optionIndex = 0;&lt;br /&gt;
      optionIndex &amp;lt; battleSelect.options.length;&lt;br /&gt;
      optionIndex++&lt;br /&gt;
    ) {&lt;br /&gt;
      if (battleSelect.options[optionIndex].value === name) {&lt;br /&gt;
        battleSelect.remove(optionIndex);&lt;br /&gt;
        break;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addBattleChoice(battle, name, isMonster = false) {&lt;br /&gt;
  function createOption(text, vnum) {&lt;br /&gt;
    var option = document.createElement(&amp;quot;option&amp;quot;);&lt;br /&gt;
    option.textContent = text;&lt;br /&gt;
    option.value = vnum;&lt;br /&gt;
&lt;br /&gt;
    if (!isMonster) {&lt;br /&gt;
      option.classList.add(&amp;quot;notranslate&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return option;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var vnum = name;&lt;br /&gt;
&lt;br /&gt;
  if (isMonster) {&lt;br /&gt;
    name = getMonsterName(name);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (isMonster &amp;amp;&amp;amp; monsterData[vnum][1]) {&lt;br /&gt;
    // pass&lt;br /&gt;
  } else {&lt;br /&gt;
    battle.attackerSelection.appendChild(createOption(name, vnum));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  battle.victimSelection.appendChild(createOption(name, vnum));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateBattleChoice(characters, battle) {&lt;br /&gt;
  function addChoices(names, isMonster) {&lt;br /&gt;
    for (var index = 0; index &amp;lt; names.length; index++) {&lt;br /&gt;
      addBattleChoice(battle, names[index], isMonster);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var characterNames = Object.keys(characters.savedCharacters);&lt;br /&gt;
  var monsterNames = Object.keys(characters.savedMonsters);&lt;br /&gt;
&lt;br /&gt;
  addChoices(characterNames, false);&lt;br /&gt;
  addChoices(monsterNames, true);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isPC(character) {&lt;br /&gt;
  if (character.race === 0 || character.race === 1) {&lt;br /&gt;
    return false;&lt;br /&gt;
  }&lt;br /&gt;
  return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isBoss(character) {&lt;br /&gt;
  return character.race === 0 &amp;amp;&amp;amp; character.rank &amp;gt;= 5;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isStone(character) {&lt;br /&gt;
  return character.race === 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isMeleeAttacker(monster) {&lt;br /&gt;
  return monster.attack == 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isRangeAttacker(monster) {&lt;br /&gt;
  return monster.attack == 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isMagicAttacker(monster) {&lt;br /&gt;
  return monster.attack == 2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isMagicClass(character) {&lt;br /&gt;
  return character.race === &amp;quot;shaman&amp;quot; || character.class === &amp;quot;black_magic&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isDispell(character, skillId) {&lt;br /&gt;
  return character.class === &amp;quot;weaponary&amp;quot; &amp;amp;&amp;amp; skillId === 6;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isPolymorph(character) {&lt;br /&gt;
  return isChecked(character.isPolymorph);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isRiding(character) {&lt;br /&gt;
  return isChecked(character.isRiding);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isBow(weapon) {&lt;br /&gt;
  return weapon.type === 2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcAttackFactor(attacker, victim) {&lt;br /&gt;
  function calcCoeffK(dex, level) {&lt;br /&gt;
    return Math.min(90, Math.floor((2 * dex + level) / 3));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var K1 = calcCoeffK(attacker.polymorphDex, attacker.level);&lt;br /&gt;
  var K2 = calcCoeffK(victim.polymorphDex, attacker.level);&lt;br /&gt;
&lt;br /&gt;
  var AR = (K1 + 210) / 300;&lt;br /&gt;
  var ER = (((2 * K2 + 5) / (K2 + 95)) * 3) / 10;&lt;br /&gt;
&lt;br /&gt;
  return truncateNumber(AR - ER, 8);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcMainAttackValue(attacker) {&lt;br /&gt;
  var leadership = 0;&lt;br /&gt;
  var rawWeaponAttackValue = 0;&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker)) {&lt;br /&gt;
    var weaponUpgrades = attacker.weapon.upgrades;&lt;br /&gt;
    var maxUpgrade = weaponUpgrades.length - 1;&lt;br /&gt;
&lt;br /&gt;
    if (attacker.hasOwnProperty(&amp;quot;weaponUpgrade&amp;quot;)) {&lt;br /&gt;
      rawWeaponAttackValue =&lt;br /&gt;
        weaponUpgrades[Math.min(attacker.weaponUpgrade, maxUpgrade)];&lt;br /&gt;
&lt;br /&gt;
      // rare bug when weaponUpgrade is deleted&lt;br /&gt;
    } else {&lt;br /&gt;
      console.log(&amp;quot;Warming: weaponUpgrade is missing.&amp;quot;);&lt;br /&gt;
      rawWeaponAttackValue = weaponUpgrades[maxUpgrade];&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    leadership = attacker.leadership;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return 2 * (attacker.level + rawWeaponAttackValue) + leadership;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcStatAttackValue(character) {&lt;br /&gt;
  switch (character.race) {&lt;br /&gt;
    case &amp;quot;warrior&amp;quot;:&lt;br /&gt;
    case &amp;quot;sura&amp;quot;:&lt;br /&gt;
      return 2 * character.str;&lt;br /&gt;
    case &amp;quot;ninja&amp;quot;:&lt;br /&gt;
      return Math.floor((1 / 4) * (character.str + 7 * character.dex));&lt;br /&gt;
    case &amp;quot;shaman&amp;quot;:&lt;br /&gt;
      return Math.floor((1 / 3) * (5 * character.int + character.dex));&lt;br /&gt;
    case &amp;quot;lycan&amp;quot;:&lt;br /&gt;
      return character.vit + 2 * character.dex;&lt;br /&gt;
    default:&lt;br /&gt;
      return 2 * character.str;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcSecondaryAttackValue(attacker) {&lt;br /&gt;
  var attackValueOther = 0;&lt;br /&gt;
&lt;br /&gt;
  var minAttackValue = 0;&lt;br /&gt;
  var maxAttackValue = 0;&lt;br /&gt;
&lt;br /&gt;
  var minAttackValueSlash = 0;&lt;br /&gt;
  var maxAttackValueSlash = 0;&lt;br /&gt;
&lt;br /&gt;
  var attackerWeapon = attacker.weapon;&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker)) {&lt;br /&gt;
    if (attackerWeapon.isSerpent) {&lt;br /&gt;
      var rawAttackValue = attackerWeapon.upgrades[attacker.weaponUpgrade];&lt;br /&gt;
&lt;br /&gt;
      minAttackValue = attacker.minAttackValueRandom - rawAttackValue;&lt;br /&gt;
      maxAttackValue = attacker.maxAttackValueRandom - rawAttackValue;&lt;br /&gt;
&lt;br /&gt;
      minAttackValue = Math.max(0, minAttackValue);&lt;br /&gt;
      maxAttackValue = Math.max(minAttackValue, maxAttackValue);&lt;br /&gt;
    } else {&lt;br /&gt;
      minAttackValue = attackerWeapon.minAttackValue;&lt;br /&gt;
      maxAttackValue = attackerWeapon.maxAttackValue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    minAttackValueSlash = Math.min(&lt;br /&gt;
      attacker.minAttackValueSlash,&lt;br /&gt;
      attacker.maxAttackValueSlash&lt;br /&gt;
    );&lt;br /&gt;
    maxAttackValueSlash = Math.max(&lt;br /&gt;
      attacker.minAttackValueSlash,&lt;br /&gt;
      attacker.maxAttackValueSlash&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    attackValueOther += attacker.attackValue;&lt;br /&gt;
&lt;br /&gt;
    if (isBow(attackerWeapon) &amp;amp;&amp;amp; !isPolymorph(attacker)) {&lt;br /&gt;
      attackValueOther += 25;&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    minAttackValue = attacker.minAttackValue;&lt;br /&gt;
    maxAttackValue = attacker.maxAttackValue;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  minAttackValue += attacker.minAttackValuePolymorph;&lt;br /&gt;
  maxAttackValue += attacker.maxAttackValuePolymorph;&lt;br /&gt;
&lt;br /&gt;
  attackValueOther += attacker.statAttackValue;&lt;br /&gt;
  attackValueOther += attacker.horseAttackValue;&lt;br /&gt;
&lt;br /&gt;
  var weaponInterval = maxAttackValue - minAttackValue + 1;&lt;br /&gt;
  var slashInterval = maxAttackValueSlash - minAttackValueSlash + 1;&lt;br /&gt;
&lt;br /&gt;
  var totalCardinal = weaponInterval * slashInterval * 1_000_000;&lt;br /&gt;
  var minInterval = Math.min(weaponInterval, slashInterval);&lt;br /&gt;
&lt;br /&gt;
  minAttackValue += minAttackValueSlash;&lt;br /&gt;
  maxAttackValue += maxAttackValueSlash;&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    minAttackValue: minAttackValue,&lt;br /&gt;
    maxAttackValue: maxAttackValue,&lt;br /&gt;
    attackValueOther: attackValueOther,&lt;br /&gt;
    totalCardinal: totalCardinal,&lt;br /&gt;
    weights: calcWeights(minAttackValue, maxAttackValue, minInterval),&lt;br /&gt;
    possibleDamagesCount: maxAttackValue - minAttackValue + 1,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcMagicAttackValue(attacker) {&lt;br /&gt;
  var minMagicAttackValue = 0;&lt;br /&gt;
  var maxMagicAttackValue = 0;&lt;br /&gt;
&lt;br /&gt;
  var minMagicAttackValueSlash = 0;&lt;br /&gt;
  var maxMagicAttackValueSlash = 0;&lt;br /&gt;
&lt;br /&gt;
  var attackerWeapon = attacker.weapon;&lt;br /&gt;
&lt;br /&gt;
  if (attackerWeapon.isSerpent) {&lt;br /&gt;
    minMagicAttackValue = attacker.minMagicAttackValueRandom;&lt;br /&gt;
    maxMagicAttackValue = attacker.maxMagicAttackValueRandom;&lt;br /&gt;
&lt;br /&gt;
    maxMagicAttackValue = Math.max(minMagicAttackValue, maxMagicAttackValue);&lt;br /&gt;
  } else {&lt;br /&gt;
    var rawWeaponAttackValue = attackerWeapon.upgrades[attacker.weaponUpgrade];&lt;br /&gt;
&lt;br /&gt;
    if (!rawWeaponAttackValue) {&lt;br /&gt;
      rawWeaponAttackValue = 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    minMagicAttackValue =&lt;br /&gt;
      attackerWeapon.minMagicAttackValue + rawWeaponAttackValue;&lt;br /&gt;
    maxMagicAttackValue =&lt;br /&gt;
      attackerWeapon.maxMagicAttackValue + rawWeaponAttackValue;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  minMagicAttackValueSlash = Math.min(&lt;br /&gt;
    attacker.minMagicAttackValueSlash,&lt;br /&gt;
    attacker.maxMagicAttackValueSlash&lt;br /&gt;
  );&lt;br /&gt;
  maxMagicAttackValueSlash = Math.max(&lt;br /&gt;
    attacker.minMagicAttackValueSlash,&lt;br /&gt;
    attacker.maxMagicAttackValueSlash&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  var weaponInterval = maxMagicAttackValue - minMagicAttackValue + 1;&lt;br /&gt;
  var slashInterval = maxMagicAttackValueSlash - minMagicAttackValueSlash + 1;&lt;br /&gt;
&lt;br /&gt;
  var totalCardinal = weaponInterval * slashInterval * 1_000_000;&lt;br /&gt;
  var minInterval = Math.min(weaponInterval, slashInterval);&lt;br /&gt;
&lt;br /&gt;
  minMagicAttackValue += minMagicAttackValueSlash;&lt;br /&gt;
  maxMagicAttackValue += maxMagicAttackValueSlash;&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    minMagicAttackValue: minMagicAttackValue,&lt;br /&gt;
    maxMagicAttackValue: maxMagicAttackValue,&lt;br /&gt;
    magicAttackValueAugmentation: getMagicAttackValueAugmentation(&lt;br /&gt;
      minMagicAttackValue,&lt;br /&gt;
      maxMagicAttackValue,&lt;br /&gt;
      attacker.magicAttackValue&lt;br /&gt;
    ),&lt;br /&gt;
    totalCardinal: totalCardinal,&lt;br /&gt;
    weights: calcWeights(minMagicAttackValue, maxMagicAttackValue, minInterval),&lt;br /&gt;
    possibleDamagesCount: maxMagicAttackValue - minMagicAttackValue + 1,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getPolymorphPower(polymorphPoint, polymorphPowerTable) {&lt;br /&gt;
  return polymorphPowerTable[polymorphPoint];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSkillPower(skillPoint, skillPowerTable) {&lt;br /&gt;
  return skillPowerTable[skillPoint];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getMarriageBonusValue(character, marriageTable, itemName) {&lt;br /&gt;
  var index;&lt;br /&gt;
  var lovePoint = character.lovePoint;&lt;br /&gt;
&lt;br /&gt;
  if (lovePoint &amp;lt; 65) {&lt;br /&gt;
    index = 0;&lt;br /&gt;
  } else if (lovePoint &amp;lt; 80) {&lt;br /&gt;
    index = 1;&lt;br /&gt;
  } else if (lovePoint &amp;lt; 100) {&lt;br /&gt;
    index = 2;&lt;br /&gt;
  } else {&lt;br /&gt;
    index = 3;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return marriageTable[itemName][index];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcDamageWithPrimaryBonuses(damages, bonusValues) {&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.attackValueCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  damages += bonusValues.attackValueMarriage;&lt;br /&gt;
&lt;br /&gt;
  damages = Math.floor(&lt;br /&gt;
    (damages * bonusValues.monsterResistanceMarriageCoeff) / 100&lt;br /&gt;
  );&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.monsterResistanceCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  damages += Math.floor((damages * bonusValues.typeBonusCoeff) / 100);&lt;br /&gt;
  damages +=&lt;br /&gt;
    Math.floor((damages * bonusValues.raceBonusCoeff) / 100) -&lt;br /&gt;
    Math.floor((damages * bonusValues.raceResistanceCoeff) / 100);&lt;br /&gt;
  damages += Math.floor((damages * bonusValues.stoneBonusCoeff) / 100);&lt;br /&gt;
  damages += Math.floor((damages * bonusValues.monsterBonusCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  var elementBonusCoeff = bonusValues.elementBonusCoeff;&lt;br /&gt;
&lt;br /&gt;
  damages +=&lt;br /&gt;
    Math.trunc((damages * elementBonusCoeff[0]) / 10000) +&lt;br /&gt;
    Math.trunc((damages * elementBonusCoeff[1]) / 10000) +&lt;br /&gt;
    Math.trunc((damages * elementBonusCoeff[2]) / 10000) +&lt;br /&gt;
    Math.trunc((damages * elementBonusCoeff[3]) / 10000) +&lt;br /&gt;
    Math.trunc((damages * elementBonusCoeff[4]) / 10000) +&lt;br /&gt;
    Math.trunc((damages * elementBonusCoeff[5]) / 10000);&lt;br /&gt;
&lt;br /&gt;
  damages = Math.floor(damages * bonusValues.damageMultiplier);&lt;br /&gt;
&lt;br /&gt;
  return damages;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcDamageWithSecondaryBonuses(&lt;br /&gt;
  damages,&lt;br /&gt;
  bonusValues,&lt;br /&gt;
  damagesType,&lt;br /&gt;
  minPiercingDamages,&lt;br /&gt;
  damagesWithPrimaryBonuses&lt;br /&gt;
) {&lt;br /&gt;
  damages = Math.floor(damages * bonusValues.magicResistanceCoeff);&lt;br /&gt;
  damages = Math.trunc((damages * bonusValues.weaponDefenseCoeff) / 100);&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.tigerStrengthCoeff) / 100);&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.blessingBonusCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  if (damagesType.criticalHit) {&lt;br /&gt;
    damages *= 2;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (damagesType.piercingHit) {&lt;br /&gt;
    damages += bonusValues.defenseBoost + Math.min(0, minPiercingDamages);&lt;br /&gt;
    damages += Math.floor(&lt;br /&gt;
      (damagesWithPrimaryBonuses * bonusValues.extraPiercingHitCoeff) / 1000&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.averageDamageCoeff) / 100);&lt;br /&gt;
  damages = Math.floor(&lt;br /&gt;
    (damages * bonusValues.averageDamageResistanceCoeff) / 100&lt;br /&gt;
  );&lt;br /&gt;
  damages = Math.floor(&lt;br /&gt;
    (damages * bonusValues.skillDamageResistanceCoeff) / 100&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.rankBonusCoeff) / 100);&lt;br /&gt;
  damages = Math.max(0, damages + bonusValues.defensePercent);&lt;br /&gt;
  damages += Math.min(&lt;br /&gt;
    300,&lt;br /&gt;
    Math.floor((damages * bonusValues.damageBonusCoeff) / 100)&lt;br /&gt;
  );&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.empireMalusCoeff) / 10);&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.sungMaStrBonusCoeff) / 10000);&lt;br /&gt;
  damages -= Math.floor(damages * bonusValues.sungmaStrMalusCoeff);&lt;br /&gt;
&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.whiteDragonElixirCoeff) / 100);&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.steelDragonElixirCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  return damages;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcSkillDamageWithSecondaryBonuses(&lt;br /&gt;
  damages,&lt;br /&gt;
  bonusValues,&lt;br /&gt;
  damagesType,&lt;br /&gt;
  minPiercingDamages&lt;br /&gt;
) {&lt;br /&gt;
  damages = Math.floor(damages * bonusValues.magicResistanceCoeff);&lt;br /&gt;
  damages = Math.trunc((damages * bonusValues.weaponDefenseCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  damages -= bonusValues.defense;&lt;br /&gt;
&lt;br /&gt;
  damages = floorMultiplication(damages, bonusValues.skillWardCoeff);&lt;br /&gt;
  damages = floorMultiplication(damages, bonusValues.skillBonusCoeff);&lt;br /&gt;
&lt;br /&gt;
  var tempDamages = Math.floor(&lt;br /&gt;
    (damages * bonusValues.skillBonusByBonusCoeff) / 100&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  damages = Math.floor(&lt;br /&gt;
    (tempDamages * bonusValues.magicAttackValueCoeff) / 100 + 0.5&lt;br /&gt;
  );&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.tigerStrengthCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  if (damagesType.criticalHit) {&lt;br /&gt;
    damages *= 2;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (damagesType.piercingHit) {&lt;br /&gt;
    damages += bonusValues.defenseBoost + Math.min(0, minPiercingDamages);&lt;br /&gt;
    damages += Math.floor(&lt;br /&gt;
      (tempDamages * bonusValues.extraPiercingHitCoeff) / 1000&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.skillDamageCoeff) / 100);&lt;br /&gt;
  damages = Math.floor(&lt;br /&gt;
    (damages * bonusValues.skillDamageResistanceCoeff) / 100&lt;br /&gt;
  );&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.rankBonusCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  damages = Math.max(0, damages + bonusValues.defensePercent);&lt;br /&gt;
  damages += Math.min(&lt;br /&gt;
    300,&lt;br /&gt;
    Math.floor((damages * bonusValues.damageBonusCoeff) / 100)&lt;br /&gt;
  );&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.empireMalusCoeff) / 10);&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.sungMaStrBonusCoeff) / 10000);&lt;br /&gt;
  damages -= Math.floor(damages * bonusValues.sungmaStrMalusCoeff);&lt;br /&gt;
&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.whiteDragonElixirCoeff) / 100);&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.steelDragonElixirCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  return damages;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function computePolymorphPoint(attacker, victim, polymorphPowerTable) {&lt;br /&gt;
  attacker.statAttackValue = 0;&lt;br /&gt;
&lt;br /&gt;
  attacker.polymorphDex = attacker.dex;&lt;br /&gt;
  victim.polymorphDex = victim.dex;&lt;br /&gt;
&lt;br /&gt;
  attacker.minAttackValuePolymorph = 0;&lt;br /&gt;
  attacker.maxAttackValuePolymorph = 0;&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker) &amp;amp;&amp;amp; isPolymorph(attacker)) {&lt;br /&gt;
    var polymorphPowerPct =&lt;br /&gt;
      getPolymorphPower(attacker.polymorphPoint, polymorphPowerTable) / 100;&lt;br /&gt;
    var polymorphMonster = createMonster(attacker.polymorphMonster);&lt;br /&gt;
&lt;br /&gt;
    var polymorphStr = floorMultiplication(&lt;br /&gt;
      polymorphPowerPct,&lt;br /&gt;
      polymorphMonster.str&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    attacker.polymorphDex += floorMultiplication(&lt;br /&gt;
      polymorphPowerPct,&lt;br /&gt;
      polymorphMonster.dex&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    attacker.minAttackValuePolymorph = floorMultiplication(&lt;br /&gt;
      polymorphPowerPct,&lt;br /&gt;
      polymorphMonster.minAttackValue&lt;br /&gt;
    );&lt;br /&gt;
    attacker.maxAttackValuePolymorph = floorMultiplication(&lt;br /&gt;
      polymorphPowerPct,&lt;br /&gt;
      polymorphMonster.maxAttackValue&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    if (!attacker.weapon) {&lt;br /&gt;
      attacker.maxAttackValuePolymorph += 1;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    attacker.attackValue = 0;&lt;br /&gt;
&lt;br /&gt;
    if (isMagicClass(attacker)) {&lt;br /&gt;
      attacker.statAttackValue = 2 * (polymorphStr + attacker.int);&lt;br /&gt;
    } else {&lt;br /&gt;
      attacker.statAttackValue = 2 * (polymorphStr + attacker.str);&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    attacker.statAttackValue = calcStatAttackValue(attacker);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function computeHorse(attacker) {&lt;br /&gt;
  attacker.horseAttackValue = 0;&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker) &amp;amp;&amp;amp; isRiding(attacker)) {&lt;br /&gt;
    var horseConstant = 30;&lt;br /&gt;
&lt;br /&gt;
    if (attacker.class === &amp;quot;weaponary&amp;quot;) {&lt;br /&gt;
      horseConstant = 60;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    attacker.horseAttackValue = floorMultiplication(&lt;br /&gt;
      2 * attacker.level + attacker.statAttackValue,&lt;br /&gt;
      attacker.horsePoint / horseConstant&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getRankBonus(attacker) {&lt;br /&gt;
  if (!isChecked(attacker.lowRank)) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  switch (attacker.playerRank) {&lt;br /&gt;
    case &amp;quot;aggressive&amp;quot;:&lt;br /&gt;
      return 1;&lt;br /&gt;
    case &amp;quot;fraudulent&amp;quot;:&lt;br /&gt;
      return 2;&lt;br /&gt;
    case &amp;quot;malicious&amp;quot;:&lt;br /&gt;
      return 3;&lt;br /&gt;
    case &amp;quot;cruel&amp;quot;:&lt;br /&gt;
      return 5;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcElementCoeffPvP(elementBonus, mapping, attacker, victim) {&lt;br /&gt;
  var minElementMalus = 0;&lt;br /&gt;
  var maxDifference = 0;&lt;br /&gt;
  var savedElementDifferences = [];&lt;br /&gt;
  var elementBonusIndex = 0;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; elementBonus.length; index++) {&lt;br /&gt;
    if (!attacker[mapping.elementBonus[index]]) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var elementDifference =&lt;br /&gt;
      attacker[mapping.elementBonus[index]] -&lt;br /&gt;
      victim[mapping.elementResistance[index]];&lt;br /&gt;
&lt;br /&gt;
    if (elementDifference &amp;gt;= 0) {&lt;br /&gt;
      elementBonus[elementBonusIndex] = 10 * elementDifference;&lt;br /&gt;
      minElementMalus -= elementDifference;&lt;br /&gt;
      maxDifference = Math.max(maxDifference, elementDifference);&lt;br /&gt;
      elementBonusIndex++;&lt;br /&gt;
    } else {&lt;br /&gt;
      savedElementDifferences.push(elementDifference);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (!savedElementDifferences.length) {&lt;br /&gt;
    return;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  minElementMalus += maxDifference;&lt;br /&gt;
  savedElementDifferences.sort(compareNumbers);&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; savedElementDifferences.length; index++) {&lt;br /&gt;
    var elementDifference = savedElementDifferences[index];&lt;br /&gt;
&lt;br /&gt;
    elementBonus[elementBonusIndex + index] =&lt;br /&gt;
      10 * Math.max(minElementMalus, elementDifference);&lt;br /&gt;
&lt;br /&gt;
    minElementMalus = Math.min(&lt;br /&gt;
      0,&lt;br /&gt;
      Math.max(minElementMalus, minElementMalus - elementDifference)&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function skillChanceReduction(value) {&lt;br /&gt;
  if (value &amp;lt;= 9) {&lt;br /&gt;
    return Math.floor(value / 2);&lt;br /&gt;
  }&lt;br /&gt;
  return 5 + Math.floor((value - 10) / 4);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function magicResistanceToCoeff(magicResistance) {&lt;br /&gt;
  if (magicResistance) {&lt;br /&gt;
    return 2000 / (6 * magicResistance + 1000) - 1;&lt;br /&gt;
  }&lt;br /&gt;
  return 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createBattleValues(attacker, victim, battle, skillType) {&lt;br /&gt;
  var { mapping, constants } = battle;&lt;br /&gt;
  var calcAttackValues;&lt;br /&gt;
&lt;br /&gt;
  var missPercentage = 0;&lt;br /&gt;
  var attackValueMeleeMagic = 0;&lt;br /&gt;
  var attackValueMarriage = 0;&lt;br /&gt;
  var monsterResistanceMarriage = 0;&lt;br /&gt;
  var monsterResistance = 0;&lt;br /&gt;
  var typeBonus = 0;&lt;br /&gt;
  var raceBonus = 0;&lt;br /&gt;
  var raceResistance = 0;&lt;br /&gt;
  var stoneBonus = 0;&lt;br /&gt;
  var monsterBonus = 0;&lt;br /&gt;
  var elementBonus = [0, 0, 0, 0, 0, 0]; // fire, ice, lightning, earth, darkness, wind, order doesn't matter&lt;br /&gt;
  var defenseMarriage = 0;&lt;br /&gt;
  var damageMultiplier = 1;&lt;br /&gt;
  var useDamages = 1;&lt;br /&gt;
  var defense = victim.defense;&lt;br /&gt;
  var defenseBoost = defense;&lt;br /&gt;
  var magicResistance = 0;&lt;br /&gt;
  var weaponDefense = 0;&lt;br /&gt;
  var tigerStrength = 0;&lt;br /&gt;
  var blessingBonus = 0;&lt;br /&gt;
  var magicAttackValueMeleeMagic = 0;&lt;br /&gt;
  var criticalHitPercentage = attacker.criticalHit;&lt;br /&gt;
  var piercingHitPercentage = attacker.piercingHit;&lt;br /&gt;
  var extraPiercingHitPercentage = Math.max(0, piercingHitPercentage - 100);&lt;br /&gt;
  var averageDamage = 0;&lt;br /&gt;
  var averageDamageResistance = 0;&lt;br /&gt;
  var skillDamage = 0;&lt;br /&gt;
  var skillDamageResistance = 0;&lt;br /&gt;
  var rankBonus = 0;&lt;br /&gt;
  var defensePercent = 0;&lt;br /&gt;
  var damageBonus = 0;&lt;br /&gt;
  var empireMalus = 0;&lt;br /&gt;
  var sungMaStrBonus = 0;&lt;br /&gt;
  var sungmaStrMalus = 0;&lt;br /&gt;
  var whiteDragonElixir = 0;&lt;br /&gt;
  var steelDragonElixir = 0;&lt;br /&gt;
&lt;br /&gt;
  computePolymorphPoint(attacker, victim, constants.polymorphPowerTable);&lt;br /&gt;
  computeHorse(attacker);&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker)) {&lt;br /&gt;
    if (weaponData.hasOwnProperty(attacker.weapon)) {&lt;br /&gt;
      attacker.weapon = createWeapon(attacker.weapon);&lt;br /&gt;
    } else {&lt;br /&gt;
      attacker.weapon = createWeapon(0);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    attackValueMeleeMagic =&lt;br /&gt;
      attacker.attackValuePercent + Math.min(100, attacker.attackMeleeMagic);&lt;br /&gt;
&lt;br /&gt;
    var weaponType = attacker.weapon.type;&lt;br /&gt;
&lt;br /&gt;
    if (skillType &amp;amp;&amp;amp; attacker.class === &amp;quot;archery&amp;quot;) {&lt;br /&gt;
      if (weaponType !== 2) {&lt;br /&gt;
        useDamages = 0;&lt;br /&gt;
        weaponType = 2;&lt;br /&gt;
      }&lt;br /&gt;
      defense = 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var weaponDefenseName = mapping.defenseWeapon[weaponType];&lt;br /&gt;
    var weaponDefenseBreakName = mapping.breakWeapon[weaponType];&lt;br /&gt;
&lt;br /&gt;
    if (victim.hasOwnProperty(weaponDefenseName)) {&lt;br /&gt;
      weaponDefense = victim[weaponDefenseName];&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isChecked(attacker.whiteDragonElixir)) {&lt;br /&gt;
      whiteDragonElixir = 10;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isPC(victim)) {&lt;br /&gt;
      if (!skillType) {&lt;br /&gt;
        if (weaponType === 2 &amp;amp;&amp;amp; !isPolymorph(attacker)) {&lt;br /&gt;
          missPercentage = victim.arrowBlock;&lt;br /&gt;
        } else {&lt;br /&gt;
          missPercentage = victim.meleeBlock;&lt;br /&gt;
        }&lt;br /&gt;
        missPercentage +=&lt;br /&gt;
          victim.meleeArrowBlock -&lt;br /&gt;
          (missPercentage * victim.meleeArrowBlock) / 100;&lt;br /&gt;
&lt;br /&gt;
        blessingBonus = calcBlessingBonus(constants.skillPowerTable, victim);&lt;br /&gt;
        averageDamageResistance = victim.averageDamageResistance;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      typeBonus = Math.max(1, attacker.humanBonus - victim.humanResistance);&lt;br /&gt;
      raceBonus = attacker[mapping.raceBonus[victim.race]];&lt;br /&gt;
      raceResistance = victim[mapping.raceResistance[attacker.race]];&lt;br /&gt;
&lt;br /&gt;
      calcElementCoeffPvP(elementBonus, mapping, attacker, victim);&lt;br /&gt;
&lt;br /&gt;
      if (weaponType !== 2 &amp;amp;&amp;amp; attacker.hasOwnProperty(weaponDefenseBreakName)) {&lt;br /&gt;
        weaponDefense -= attacker[weaponDefenseBreakName];&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      criticalHitPercentage = 0;&lt;br /&gt;
    } else {&lt;br /&gt;
      if (isChecked(attacker.isMarried)) {&lt;br /&gt;
        if (isChecked(attacker.loveNecklace)) {&lt;br /&gt;
          attackValueMarriage = getMarriageBonusValue(&lt;br /&gt;
            attacker,&lt;br /&gt;
            constants.marriageTable,&lt;br /&gt;
            &amp;quot;loveNecklace&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isChecked(attacker.loveEarrings)) {&lt;br /&gt;
          criticalHitPercentage += getMarriageBonusValue(&lt;br /&gt;
            attacker,&lt;br /&gt;
            constants.marriageTable,&lt;br /&gt;
            &amp;quot;loveEarrings&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isChecked(attacker.harmonyEarrings)) {&lt;br /&gt;
          piercingHitPercentage += getMarriageBonusValue(&lt;br /&gt;
            attacker,&lt;br /&gt;
            constants.marriageTable,&lt;br /&gt;
            &amp;quot;harmonyEarrings&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (isChecked(attacker.tigerStrength)) {&lt;br /&gt;
        tigerStrength = 40;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      for (var index = 0; index &amp;lt; elementBonus.length; index++) {&lt;br /&gt;
        var elementBonusName = mapping.elementBonus[index];&lt;br /&gt;
        var elementResistanceName = mapping.elementResistance[index];&lt;br /&gt;
&lt;br /&gt;
        if (attacker[elementBonusName] &amp;amp;&amp;amp; victim[elementBonusName]) {&lt;br /&gt;
          elementBonus[index] =&lt;br /&gt;
            50 * (attacker[elementBonusName] - victim[elementResistanceName]);&lt;br /&gt;
        } else {&lt;br /&gt;
          elementBonus[index] = 5 * attacker[elementBonusName];&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      var victimType = victim.type;&lt;br /&gt;
&lt;br /&gt;
      if (victimType !== -1) {&lt;br /&gt;
        typeBonus = attacker[mapping.typeFlag[victimType]];&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      monsterBonus = attacker.monsterBonus;&lt;br /&gt;
&lt;br /&gt;
      if (isStone(victim)) {&lt;br /&gt;
        stoneBonus = attacker.stoneBonus;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (isBoss(victim)) {&lt;br /&gt;
        if (skillType) {&lt;br /&gt;
          skillDamage += attacker.skillBossDamage;&lt;br /&gt;
        } else {&lt;br /&gt;
          averageDamage += attacker.bossDamage;&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (isChecked(attacker.onYohara)) {&lt;br /&gt;
        var sungmaStrDifference = attacker.sungmaStr - attacker.sungmaStrMalus;&lt;br /&gt;
&lt;br /&gt;
        if (sungmaStrDifference &amp;gt;= 0) {&lt;br /&gt;
          sungMaStrBonus = sungmaStrDifference;&lt;br /&gt;
        } else {&lt;br /&gt;
          sungmaStrMalus = 0.5;&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (skillType) {&lt;br /&gt;
      skillDamage += attacker.skillDamage;&lt;br /&gt;
    } else {&lt;br /&gt;
      averageDamage += attacker.averageDamage;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    rankBonus = getRankBonus(attacker);&lt;br /&gt;
    damageBonus = attacker.damageBonus;&lt;br /&gt;
&lt;br /&gt;
    if (isChecked(attacker.empireMalus)) {&lt;br /&gt;
      empireMalus = 1;&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    if (isPC(victim)) {&lt;br /&gt;
      if (isChecked(victim.isMarried)) {&lt;br /&gt;
        if (isChecked(victim.harmonyBracelet)) {&lt;br /&gt;
          monsterResistanceMarriage = getMarriageBonusValue(&lt;br /&gt;
            victim,&lt;br /&gt;
            constants.marriageTable,&lt;br /&gt;
            &amp;quot;harmonyBracelet&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isChecked(victim.harmonyNecklace) &amp;amp;&amp;amp; !skillType) {&lt;br /&gt;
          defenseMarriage = getMarriageBonusValue(&lt;br /&gt;
            victim,&lt;br /&gt;
            constants.marriageTable,&lt;br /&gt;
            &amp;quot;harmonyNecklace&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      monsterResistance = victim.monsterResistance;&lt;br /&gt;
&lt;br /&gt;
      for (var index = 0; index &amp;lt; elementBonus.length; index++) {&lt;br /&gt;
        var elementBonusName = mapping.elementBonus[index];&lt;br /&gt;
        var elementResistanceName = mapping.elementResistance[index];&lt;br /&gt;
&lt;br /&gt;
        if (attacker[elementBonusName]) {&lt;br /&gt;
          elementBonus[index] =&lt;br /&gt;
            80 * (attacker[elementBonusName] - victim[elementResistanceName]);&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (!skillType) {&lt;br /&gt;
        if (isMeleeAttacker(attacker)) {&lt;br /&gt;
          missPercentage = victim.meleeBlock;&lt;br /&gt;
          averageDamageResistance = victim.averageDamageResistance;&lt;br /&gt;
          blessingBonus = calcBlessingBonus(constants.skillPowerTable, victim);&lt;br /&gt;
        } else if (isRangeAttacker(attacker)) {&lt;br /&gt;
          missPercentage = victim.arrowBlock;&lt;br /&gt;
          weaponDefense = victim.arrowDefense;&lt;br /&gt;
          averageDamageResistance = victim.averageDamageResistance;&lt;br /&gt;
          blessingBonus = calcBlessingBonus(constants.skillPowerTable, victim);&lt;br /&gt;
        } else if (isMagicAttacker(attacker)) {&lt;br /&gt;
          missPercentage = victim.arrowBlock;&lt;br /&gt;
          skillDamageResistance = victim.skillDamageResistance;&lt;br /&gt;
          magicResistance = victim.magicResistance;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        missPercentage +=&lt;br /&gt;
          victim.meleeArrowBlock -&lt;br /&gt;
          (missPercentage * victim.meleeArrowBlock) / 100;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    typeBonus = 1;&lt;br /&gt;
    damageMultiplier = attacker.damageMultiplier;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillType) {&lt;br /&gt;
    criticalHitPercentage = skillChanceReduction(criticalHitPercentage);&lt;br /&gt;
    piercingHitPercentage = skillChanceReduction(piercingHitPercentage);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (isPC(victim)) {&lt;br /&gt;
    if (!skillType &amp;amp;&amp;amp; isChecked(victim.biologist70)) {&lt;br /&gt;
      defenseBoost = Math.floor((defenseBoost * 110) / 100);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    criticalHitPercentage = Math.max(&lt;br /&gt;
      0,&lt;br /&gt;
      criticalHitPercentage - victim.criticalHitResistance&lt;br /&gt;
    );&lt;br /&gt;
    piercingHitPercentage = Math.max(&lt;br /&gt;
      0,&lt;br /&gt;
      piercingHitPercentage - victim.piercingHitResistance&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    if (skillType) {&lt;br /&gt;
      skillDamageResistance = victim.skillDamageResistance;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isMagicClass(victim)) {&lt;br /&gt;
      defensePercent = (-2 * victim.magicDefense * victim.defensePercent) / 100;&lt;br /&gt;
    } else {&lt;br /&gt;
      defensePercent = (-2 * defenseBoost * victim.defensePercent) / 100;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isChecked(victim.steelDragonElixir)) {&lt;br /&gt;
      steelDragonElixir = 10;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillType === &amp;quot;magic&amp;quot;) {&lt;br /&gt;
    attackValueMeleeMagic = 0;&lt;br /&gt;
    magicAttackValueMeleeMagic =&lt;br /&gt;
      attacker.attackMagic + Math.min(100, attacker.attackMeleeMagic);&lt;br /&gt;
    attackValueMarriage = 0;&lt;br /&gt;
    defense = 0;&lt;br /&gt;
    if (!isDispell(attacker, 6)) {&lt;br /&gt;
      magicResistance = victim.magicResistance;&lt;br /&gt;
    }&lt;br /&gt;
    weaponDefense = 0;&lt;br /&gt;
    calcAttackValues = calcMagicAttackValue;&lt;br /&gt;
  } else {&lt;br /&gt;
    calcAttackValues = calcSecondaryAttackValue;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  missPercentage = Math.min(100, missPercentage);&lt;br /&gt;
&lt;br /&gt;
  var bonusValues = {&lt;br /&gt;
    missPercentage: missPercentage,&lt;br /&gt;
    weaponBonusCoeff: 1,&lt;br /&gt;
    attackValueCoeff: 100 + attackValueMeleeMagic,&lt;br /&gt;
    attackValueMarriage: attackValueMarriage,&lt;br /&gt;
    monsterResistanceMarriageCoeff: 100 - monsterResistanceMarriage,&lt;br /&gt;
    monsterResistanceCoeff: 100 - monsterResistance,&lt;br /&gt;
    typeBonusCoeff: typeBonus,&lt;br /&gt;
    raceBonusCoeff: raceBonus,&lt;br /&gt;
    raceResistanceCoeff: raceResistance,&lt;br /&gt;
    stoneBonusCoeff: stoneBonus,&lt;br /&gt;
    monsterBonusCoeff: monsterBonus,&lt;br /&gt;
    elementBonusCoeff: elementBonus,&lt;br /&gt;
    damageMultiplier: damageMultiplier,&lt;br /&gt;
    useDamages: useDamages,&lt;br /&gt;
    defense: defense,&lt;br /&gt;
    defenseBoost: defenseBoost,&lt;br /&gt;
    defenseMarriage: defenseMarriage,&lt;br /&gt;
    tigerStrengthCoeff: 100 + tigerStrength,&lt;br /&gt;
    magicResistanceCoeff: magicResistanceToCoeff(magicResistance),&lt;br /&gt;
    weaponDefenseCoeff: 100 - weaponDefense,&lt;br /&gt;
    blessingBonusCoeff: 100 - blessingBonus,&lt;br /&gt;
    magicAttackValueCoeff: 100 + magicAttackValueMeleeMagic,&lt;br /&gt;
    extraPiercingHitCoeff: 5 * extraPiercingHitPercentage,&lt;br /&gt;
    averageDamageCoeff: 100 + averageDamage,&lt;br /&gt;
    averageDamageResistanceCoeff: 100 - Math.min(99, averageDamageResistance),&lt;br /&gt;
    skillDamageCoeff: 100 + skillDamage,&lt;br /&gt;
    skillDamageResistanceCoeff: 100 - Math.min(99, skillDamageResistance),&lt;br /&gt;
    rankBonusCoeff: 100 + rankBonus,&lt;br /&gt;
    defensePercent: Math.floor(defensePercent),&lt;br /&gt;
    damageBonusCoeff: damageBonus,&lt;br /&gt;
    empireMalusCoeff: 10 - empireMalus,&lt;br /&gt;
    sungMaStrBonusCoeff: 10000 + sungMaStrBonus,&lt;br /&gt;
    sungmaStrMalusCoeff: sungmaStrMalus,&lt;br /&gt;
    whiteDragonElixirCoeff: 100 + whiteDragonElixir,&lt;br /&gt;
    steelDragonElixirCoeff: 100 - steelDragonElixir,&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  criticalHitPercentage = Math.min(criticalHitPercentage, 100);&lt;br /&gt;
  piercingHitPercentage = Math.min(piercingHitPercentage, 100);&lt;br /&gt;
&lt;br /&gt;
  var damagesTypeCombinaison = [&lt;br /&gt;
    {&lt;br /&gt;
      criticalHit: false,&lt;br /&gt;
      piercingHit: false,&lt;br /&gt;
      weight:&lt;br /&gt;
        (100 - criticalHitPercentage) *&lt;br /&gt;
        (100 - piercingHitPercentage) *&lt;br /&gt;
        (100 - missPercentage),&lt;br /&gt;
      name: &amp;quot;normalHit&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      criticalHit: true,&lt;br /&gt;
      piercingHit: false,&lt;br /&gt;
      weight:&lt;br /&gt;
        criticalHitPercentage *&lt;br /&gt;
        (100 - piercingHitPercentage) *&lt;br /&gt;
        (100 - missPercentage),&lt;br /&gt;
      name: &amp;quot;criticalHit&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      criticalHit: false,&lt;br /&gt;
      piercingHit: true,&lt;br /&gt;
      weight:&lt;br /&gt;
        (100 - criticalHitPercentage) *&lt;br /&gt;
        piercingHitPercentage *&lt;br /&gt;
        (100 - missPercentage),&lt;br /&gt;
      name: &amp;quot;piercingHit&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      criticalHit: true,&lt;br /&gt;
      piercingHit: true,&lt;br /&gt;
      weight:&lt;br /&gt;
        criticalHitPercentage * piercingHitPercentage * (100 - missPercentage),&lt;br /&gt;
      name: &amp;quot;criticalPiercingHit&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
  ];&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    attacker: attacker,&lt;br /&gt;
    victim: victim,&lt;br /&gt;
    attackFactor: calcAttackFactor(attacker, victim),&lt;br /&gt;
    mainAttackValue: calcMainAttackValue(attacker),&lt;br /&gt;
    attackValues: calcAttackValues(attacker),&lt;br /&gt;
    bonusValues: bonusValues,&lt;br /&gt;
    damagesTypeCombinaison: damagesTypeCombinaison,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateBattleValues(battleValues, skillFormula, skillInfo) {&lt;br /&gt;
  var weaponBonus = 0;&lt;br /&gt;
  var skillWard = 0;&lt;br /&gt;
  var skillBonus = 0;&lt;br /&gt;
  var skillBonusByBonus = 0;&lt;br /&gt;
  var { attacker: attacker, bonusValues: bonusValues } = battleValues;&lt;br /&gt;
  var {&lt;br /&gt;
    range: [minVariation, maxVariation],&lt;br /&gt;
  } = skillInfo;&lt;br /&gt;
  var variationLength = maxVariation - minVariation + 1;&lt;br /&gt;
&lt;br /&gt;
  if (skillInfo.hasOwnProperty(&amp;quot;weaponBonus&amp;quot;)) {&lt;br /&gt;
    var [weaponType, weaponBonusValue] = skillInfo.weaponBonus;&lt;br /&gt;
&lt;br /&gt;
    if (weaponType === attacker.weapon.type) {&lt;br /&gt;
      weaponBonus = weaponBonusValue;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillInfo.skillBonus) {&lt;br /&gt;
    skillBonus = skillInfo.skillBonus;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillInfo.skillWard) {&lt;br /&gt;
    skillWard = skillInfo.skillWard;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillInfo.skillBonusByBonus) {&lt;br /&gt;
    skillBonusByBonus = skillInfo.skillBonusByBonus;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillInfo.removeWeaponReduction) {&lt;br /&gt;
    bonusValues.weaponDefenseCoeff = 100;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  bonusValues.weaponBonusCoeff = 100 + weaponBonus;&lt;br /&gt;
  bonusValues.skillWardCoeff = 1 - skillWard / 100;&lt;br /&gt;
  bonusValues.skillBonusCoeff = 1 + skillBonus / 100;&lt;br /&gt;
  bonusValues.skillBonusByBonusCoeff = 100 + skillBonusByBonus;&lt;br /&gt;
&lt;br /&gt;
  battleValues.skillFormula = skillFormula;&lt;br /&gt;
  battleValues.skillRange = skillInfo.range;&lt;br /&gt;
  battleValues.attackValues.totalCardinal *= variationLength;&lt;br /&gt;
  battleValues.attackValues.possibleDamagesCount *= variationLength;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcWeights(minValue, maxValue, minInterval) {&lt;br /&gt;
  var firstWeightLimit = minValue + minInterval - 1;&lt;br /&gt;
  var lastWeightsLimit = maxValue - minInterval + 1;&lt;br /&gt;
  var weights = [];&lt;br /&gt;
&lt;br /&gt;
  for (var value = minValue; value &amp;lt; firstWeightLimit; value++) {&lt;br /&gt;
    weights.push(value - minValue + 1);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (var value = firstWeightLimit; value &amp;lt;= lastWeightsLimit; value++) {&lt;br /&gt;
    weights.push(minInterval);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (var value = lastWeightsLimit + 1; value &amp;lt;= maxValue; value++) {&lt;br /&gt;
    weights.push(maxValue - value + 1);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return weights;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcBlessingBonus(skillPowerTable, victim) {&lt;br /&gt;
  if (!isChecked(victim.isBlessed)) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var int = victim.intBlessing;&lt;br /&gt;
  var dex = victim.dexBlessing;&lt;br /&gt;
  var skillPower = getSkillPower(victim[&amp;quot;skillBlessing&amp;quot;], skillPowerTable);&lt;br /&gt;
&lt;br /&gt;
  if (!skillPower) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var blessingBonus = floorMultiplication(&lt;br /&gt;
    ((int * 0.3 + 5) * (2 * skillPower + 0.5) + 0.3 * dex) / (skillPower + 2.3),&lt;br /&gt;
    1&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  if (victim.class === &amp;quot;dragon&amp;quot; &amp;amp;&amp;amp; isChecked(ictim.blessingOnself)) {&lt;br /&gt;
    blessingBonus = floorMultiplication(blessingBonus, 1.1);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return blessingBonus;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSkillFormula(battle, skillId, battleValues, removeSkillVariation) {&lt;br /&gt;
  var { attacker, victim, attackFactor } = battleValues;&lt;br /&gt;
  var skillPowerTable = battle.constants.skillPowerTable;&lt;br /&gt;
&lt;br /&gt;
  var skillFormula;&lt;br /&gt;
  var skillInfo = { range: [0, 0] };&lt;br /&gt;
&lt;br /&gt;
  var { class: attackerClass, level: lv, vit, str, int, dex } = attacker;&lt;br /&gt;
&lt;br /&gt;
  if (skillId &amp;lt;= 9) {&lt;br /&gt;
    var skillPower = getSkillPower(&lt;br /&gt;
      attacker[&amp;quot;attackSkill&amp;quot; + skillId],&lt;br /&gt;
      skillPowerTable&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    var improvedBySkillBonus = false;&lt;br /&gt;
    var improvedByBonus = false;&lt;br /&gt;
&lt;br /&gt;
    if (attackerClass === &amp;quot;body&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Triple lacération&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.1 * atk + (0.5 * atk + 1.5 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Moulinet à l'épée&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              3 * atk + (0.8 * atk + 5 * str + 3 * dex + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Accélération&lt;br /&gt;
        case 5:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * atk + (atk + dex * 3 + str * 7 + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Volonté de vivre&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              (3 * atk + (atk + 1.5 * str) * skillPower) * 1.07,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          break;&lt;br /&gt;
        // Tremblement de terre&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              3 * atk +&lt;br /&gt;
                (0.9 * atk + variation + 5 * str + 3 * dex + lv) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;mental&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Attaque de l'esprit&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2.3 * atk + (4 * atk + 4 * str + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Attaque de la paume&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2.3 * atk + (3 * atk + 4 * str + 3 * vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Charge&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * atk + (2 * atk + 2 * dex + 2 * vit + 4 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          break;&lt;br /&gt;
        // Coup d'épée&lt;br /&gt;
        case 5:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * atk + (atk + 3 * dex + 5 * str + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Orbe de l'épée&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              (2 * atk + (2 * atk + 2 * dex + 2 * vit + 4 * str) * skillPower) *&lt;br /&gt;
                1.1,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          break;&lt;br /&gt;
        // Tremblement de terre&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              3 * atk +&lt;br /&gt;
                (0.9 * atk + variation + 5 * str + 3 * dex + lv) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;blade_fight&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Embuscade&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk + (1.2 * atk + variation + 4 * dex + 4 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [1, 50];&lt;br /&gt;
          skillInfo.range = [500, 700];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Attaque rapide&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk + (1.6 * atk + variation + 7 * dex + 7 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [1, 35];&lt;br /&gt;
          skillInfo.range = [200, 300];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Dague filante&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * atk + (0.5 * atk + 9 * dex + 7 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Brume empoisonnée&lt;br /&gt;
        case 5:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * lv + (atk + 3 * str + 18 * dex) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Poison insidieux&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              (2 * lv + (atk + 3 * str + 18 * dex) * skillPower) * 1.1,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          break;&lt;br /&gt;
        // Étoiles brillantes&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk + (1.7 * atk + variation + 6 * dex + 5 * lv) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;archery&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Tir à répétition&lt;br /&gt;
        // case 1:&lt;br /&gt;
        //   skillFormula = function (atk) {&lt;br /&gt;
        //     return floorMultiplication(&lt;br /&gt;
        //       atk + 0.2 * atk * Math.floor(2 + 6 * skillPower) + (0.8 * atk + 8 * dex * attackFactor + 2 * int) * skillPower,&lt;br /&gt;
        //       1&lt;br /&gt;
        //     );&lt;br /&gt;
        //   };&lt;br /&gt;
        //   improvedByBonus = true;&lt;br /&gt;
        //   break;&lt;br /&gt;
        // Pluie de flèches&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk + (1.7 * atk + 5 * dex + str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Flèche de feu&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.5 * atk + (2.6 * atk + 0.9 * int + variation) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [100, 300];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Foulée de plume&lt;br /&gt;
        case 4:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              (3 * dex + 200 + 2 * str + 2 * int) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.removeWeaponReduction = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Flèche empoisonnée&lt;br /&gt;
        case 5:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk +&lt;br /&gt;
                (1.4 * atk + variation + 7 * dex + 4 * str + 4 * int) *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [100, 200];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Coup étincelant&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              (atk +&lt;br /&gt;
                (1.2 * atk + variation + 6 * dex + 3 * str + 3 * int) *&lt;br /&gt;
                  skillPower) *&lt;br /&gt;
                1.2,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [100, 200];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Tir tempête&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.9 * atk + (2.6 * atk + variation) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;weaponary&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Toucher brûlant&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk +&lt;br /&gt;
                2 * lv +&lt;br /&gt;
                2 * int +&lt;br /&gt;
                (2 * atk + 4 * str + 14 * int) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Tourbillon du dragon&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.1 * atk +&lt;br /&gt;
                2 * lv +&lt;br /&gt;
                2 * int +&lt;br /&gt;
                (1.5 * atk + str + 12 * int) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Contre-sort&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              40 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                2 * int +&lt;br /&gt;
                (10 * int + 7 * mav + variation) * attackFactor * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [50, 100];&lt;br /&gt;
          break;&lt;br /&gt;
        // Coup démoniaque&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.9 * atk + (2.6 * atk + variation) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;black_magic&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Attaque des ténèbres&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              40 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                2 * int +&lt;br /&gt;
                (13 * int + 6 * mav + variation) * attackFactor * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [50, 100];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Attaque de flammes&lt;br /&gt;
        // case 2:&lt;br /&gt;
        //   skillFormula = function (mav, variation) {&lt;br /&gt;
        //     return floorMultiplication(&lt;br /&gt;
        //       5 * lv + 2 * int + (7 * int + 8 * mav + 4 * str + 2 * vit + variation) * skillPower,&lt;br /&gt;
        //       1&lt;br /&gt;
        //     );&lt;br /&gt;
        //   };&lt;br /&gt;
        //   skillInfo.range = [180, 100];&lt;br /&gt;
        //   improvedByBonus = true;&lt;br /&gt;
        //   break;&lt;br /&gt;
        // Esprit de flammes&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              30 +&lt;br /&gt;
                2 * lv +&lt;br /&gt;
                2 * int +&lt;br /&gt;
                (7 * int + 6 * mav + variation) * attackFactor * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [200, 500];&lt;br /&gt;
          break;&lt;br /&gt;
        // Frappe de l'esprit&lt;br /&gt;
        // case 5:&lt;br /&gt;
        //   skillFormula = function (mav, variation) {&lt;br /&gt;
        //     return floorMultiplication(&lt;br /&gt;
        //       40 + 2 * lv + 2 * int + (2 * vit + 2 * dex + 13 * int + 6 * mav + variation) * attackFactor * skillPower,&lt;br /&gt;
        //       1&lt;br /&gt;
        //     );&lt;br /&gt;
        //   };&lt;br /&gt;
        //   skillInfo.range = [180, 200];&lt;br /&gt;
        //   break;&lt;br /&gt;
        // Orbe des ténèbres&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (mav) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              120 +&lt;br /&gt;
                6 * lv +&lt;br /&gt;
                (5 * vit + 5 * dex + 29 * int + 9 * mav) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Vague mortelle&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              120 +&lt;br /&gt;
                6 * lv +&lt;br /&gt;
                (5 * vit + 5 * dex + 30 * int + variation + 9 * mav) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;dragon&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Talisman volant&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (mav) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              70 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                (18 * int + 7 * str + 5 * mav + 50) * attackFactor * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [4, 10];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Dragon chassant&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (mav) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              60 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                (16 * int + 6 * dex + 6 * mav + 120) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [4, 10];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Rugissement du dragon&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (mav) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              70 +&lt;br /&gt;
                3 * lv +&lt;br /&gt;
                (20 * int + 3 * str + 10 * mav + 100) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [4, 10];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Météore&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              120 +&lt;br /&gt;
                6 * lv +&lt;br /&gt;
                (5 * vit + 5 * dex + 30 * int + variation + 9 * mav) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;heal&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Jet de foudre&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              60 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                (8 * int + 2 * dex + 8 * mav + variation) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [6, 10];&lt;br /&gt;
          skillInfo.range = [5 * int, 15 * int];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Invocation de foudre&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              40 +&lt;br /&gt;
                4 * lv +&lt;br /&gt;
                (13 * int + 2 * str + 10 * mav + variation) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [6, 10];&lt;br /&gt;
          skillInfo.range = [5 * int, 16 * int];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Griffe de foudre&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              50 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                (8 * int + 2 * str + 8 * mav + variation) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 800];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;lycan&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Déchiqueter&lt;br /&gt;
        // case 1:&lt;br /&gt;
        //   skillFormula = function (atk) {&lt;br /&gt;
        //     return floorMultiplication(&lt;br /&gt;
        //       1.1 * atk + (0.3 * atk + 1.5 * str) * skillPower,&lt;br /&gt;
        //       1&lt;br /&gt;
        //     );&lt;br /&gt;
        //   };&lt;br /&gt;
        //   skillInfo.weaponBonus = [5, 54];&lt;br /&gt;
        //   improvedByBonus = true;&lt;br /&gt;
        //   break;&lt;br /&gt;
        // Souffle de loup&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * atk + (atk + 3 * dex + 5 * str + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [5, 35];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Bond de loup&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk + (1.6 * atk + 200 + 7 * dex + 7 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [5, 35];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Griffe de loup&lt;br /&gt;
        case 4:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              3 * atk + (0.8 * atk + 6 * str + 2 * dex + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Tempête cinglante&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.8 * atk +&lt;br /&gt;
                (atk + 6 * dex + variation + 3 * str + lv) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
    if (improvedBySkillBonus) {&lt;br /&gt;
      skillInfo.skillBonus =&lt;br /&gt;
        16 * getSkillPower(attacker.skillBonus, skillPowerTable);&lt;br /&gt;
&lt;br /&gt;
      var skillWardChoice = victim.skillWardChoice;&lt;br /&gt;
&lt;br /&gt;
      if (skillWardChoice &amp;amp;&amp;amp; skillWardChoice === attackerClass) {&lt;br /&gt;
        skillInfo.skillWard =&lt;br /&gt;
          24 * getSkillPower(victim.skillWard, skillPowerTable);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (improvedByBonus) {&lt;br /&gt;
      skillInfo.skillBonusByBonus = attacker[&amp;quot;skillBonus&amp;quot; + skillId];&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (removeSkillVariation) {&lt;br /&gt;
      var averageVariation = (skillInfo.range[0] + skillInfo.range[0]) / 2;&lt;br /&gt;
      skillInfo.range = [averageVariation, averageVariation];&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    var skillPower = getSkillPower(&lt;br /&gt;
      attacker[&amp;quot;horseSkill&amp;quot; + skillId],&lt;br /&gt;
      skillPowerTable&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    switch (skillId) {&lt;br /&gt;
      // Combat équestre&lt;br /&gt;
      case 137:&lt;br /&gt;
        skillFormula = function (atk) {&lt;br /&gt;
          return floorMultiplication(atk + 2 * atk * skillPower, 1);&lt;br /&gt;
        };&lt;br /&gt;
        break;&lt;br /&gt;
      // Charge à cheval&lt;br /&gt;
      case 138:&lt;br /&gt;
        skillFormula = function (atk) {&lt;br /&gt;
          return floorMultiplication(&lt;br /&gt;
            2.4 * (200 + 1.5 * lv) + 600 * skillPower,&lt;br /&gt;
            1&lt;br /&gt;
          );&lt;br /&gt;
        };&lt;br /&gt;
        break;&lt;br /&gt;
      // Vague de Pouvoir&lt;br /&gt;
      case 139:&lt;br /&gt;
        skillFormula = function (atk) {&lt;br /&gt;
          return floorMultiplication(&lt;br /&gt;
            2 * (200 + 1.5 * lv) + 600 * skillPower,&lt;br /&gt;
            1&lt;br /&gt;
          );&lt;br /&gt;
        };&lt;br /&gt;
        break;&lt;br /&gt;
      // Grêle de flèches&lt;br /&gt;
      case 140:&lt;br /&gt;
        skillFormula = function (atk) {&lt;br /&gt;
          return floorMultiplication(atk + 2 * atk * skillPower, 1);&lt;br /&gt;
        };&lt;br /&gt;
        break;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  updateBattleValues(battleValues, skillFormula, skillInfo);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcMagicAttackValueAugmentation(&lt;br /&gt;
  magicAttackValueWeapon,&lt;br /&gt;
  magicAttackValueBonus&lt;br /&gt;
) {&lt;br /&gt;
  if (magicAttackValueBonus) {&lt;br /&gt;
    return Math.max(&lt;br /&gt;
      1,&lt;br /&gt;
      0.0025056 *&lt;br /&gt;
        magicAttackValueBonus ** 0.602338 *&lt;br /&gt;
        magicAttackValueWeapon ** 1.20476&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
  return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getMagicAttackValueAugmentation(&lt;br /&gt;
  minMagicAttackValue,&lt;br /&gt;
  maxMagicAttackValue,&lt;br /&gt;
  magicAttackValueBonus&lt;br /&gt;
) {&lt;br /&gt;
  var magicAttackValueAugmentation = [];&lt;br /&gt;
&lt;br /&gt;
  for (&lt;br /&gt;
    var magicAttackValue = minMagicAttackValue;&lt;br /&gt;
    magicAttackValue &amp;lt;= maxMagicAttackValue;&lt;br /&gt;
    magicAttackValue++&lt;br /&gt;
  ) {&lt;br /&gt;
    magicAttackValueAugmentation.push(&lt;br /&gt;
      calcMagicAttackValueAugmentation(magicAttackValue, magicAttackValueBonus)&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return magicAttackValueAugmentation;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcPhysicalDamages(battleValues) {&lt;br /&gt;
  var {&lt;br /&gt;
    attackFactor,&lt;br /&gt;
    mainAttackValue,&lt;br /&gt;
    attackValues: { minAttackValue, maxAttackValue, attackValueOther, weights },&lt;br /&gt;
    bonusValues,&lt;br /&gt;
    damagesTypeCombinaison,&lt;br /&gt;
  } = battleValues;&lt;br /&gt;
&lt;br /&gt;
  var damagesWeightedByType = {};&lt;br /&gt;
&lt;br /&gt;
  if (bonusValues.missPercentage) {&lt;br /&gt;
    damagesWeightedByType.miss = bonusValues.missPercentage / 100;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (var damagesType of damagesTypeCombinaison) {&lt;br /&gt;
    if (!damagesType.weight) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var damagesWeighted = {};&lt;br /&gt;
    damagesWeightedByType[damagesType.name] = damagesWeighted;&lt;br /&gt;
&lt;br /&gt;
    for (&lt;br /&gt;
      var attackValue = minAttackValue;&lt;br /&gt;
      attackValue &amp;lt;= maxAttackValue;&lt;br /&gt;
      attackValue++&lt;br /&gt;
    ) {&lt;br /&gt;
      var weight = weights[attackValue - minAttackValue] * damagesType.weight;&lt;br /&gt;
&lt;br /&gt;
      var secondaryAttackValue = 2 * attackValue + attackValueOther;&lt;br /&gt;
      var rawDamages =&lt;br /&gt;
        mainAttackValue +&lt;br /&gt;
        floorMultiplication(attackFactor, secondaryAttackValue);&lt;br /&gt;
&lt;br /&gt;
      var damagesWithPrimaryBonuses = calcDamageWithPrimaryBonuses(&lt;br /&gt;
        rawDamages,&lt;br /&gt;
        bonusValues&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      var minPiercingDamages =&lt;br /&gt;
        damagesWithPrimaryBonuses -&lt;br /&gt;
        bonusValues.defenseBoost +&lt;br /&gt;
        bonusValues.defenseMarriage;&lt;br /&gt;
&lt;br /&gt;
      if (minPiercingDamages &amp;lt;= 2) {&lt;br /&gt;
        for (var damages = 1; damages &amp;lt;= 5; damages++) {&lt;br /&gt;
          var finalDamages = calcDamageWithSecondaryBonuses(&lt;br /&gt;
            damages,&lt;br /&gt;
            bonusValues,&lt;br /&gt;
            damagesType,&lt;br /&gt;
            minPiercingDamages,&lt;br /&gt;
            damagesWithPrimaryBonuses&lt;br /&gt;
          );&lt;br /&gt;
&lt;br /&gt;
          addKeyValue(damagesWeighted, finalDamages, weight / 5);&lt;br /&gt;
        }&lt;br /&gt;
      } else {&lt;br /&gt;
        var finalDamages = calcDamageWithSecondaryBonuses(&lt;br /&gt;
          minPiercingDamages,&lt;br /&gt;
          bonusValues,&lt;br /&gt;
          damagesType,&lt;br /&gt;
          minPiercingDamages,&lt;br /&gt;
          damagesWithPrimaryBonuses&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        addKeyValue(damagesWeighted, finalDamages, weight);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return damagesWeightedByType;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcPhysicalSkillDamages(battleValues) {&lt;br /&gt;
  var {&lt;br /&gt;
    attackFactor,&lt;br /&gt;
    mainAttackValue,&lt;br /&gt;
    attackValues: { minAttackValue, maxAttackValue, attackValueOther, weights },&lt;br /&gt;
    bonusValues,&lt;br /&gt;
    damagesTypeCombinaison,&lt;br /&gt;
    skillFormula,&lt;br /&gt;
    skillRange: [minVariation, maxVariation],&lt;br /&gt;
  } = battleValues;&lt;br /&gt;
&lt;br /&gt;
  var damagesWeightedByType = {};&lt;br /&gt;
&lt;br /&gt;
  for (var damagesType of damagesTypeCombinaison) {&lt;br /&gt;
    if (!damagesType.weight) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var damagesWeighted = {};&lt;br /&gt;
    var savedDamages = {};&lt;br /&gt;
&lt;br /&gt;
    damagesWeightedByType[damagesType.name] = damagesWeighted;&lt;br /&gt;
&lt;br /&gt;
    for (&lt;br /&gt;
      var attackValue = minAttackValue;&lt;br /&gt;
      attackValue &amp;lt;= maxAttackValue;&lt;br /&gt;
      attackValue++&lt;br /&gt;
    ) {&lt;br /&gt;
      var weight = weights[attackValue - minAttackValue] * damagesType.weight;&lt;br /&gt;
&lt;br /&gt;
      var secondaryAttackValue = 2 * attackValue + attackValueOther;&lt;br /&gt;
      var rawDamages =&lt;br /&gt;
        mainAttackValue +&lt;br /&gt;
        floorMultiplication(attackFactor, secondaryAttackValue);&lt;br /&gt;
&lt;br /&gt;
      var damagesWithPrimaryBonuses = calcDamageWithPrimaryBonuses(&lt;br /&gt;
        rawDamages,&lt;br /&gt;
        bonusValues&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      for (&lt;br /&gt;
        var variation = minVariation;&lt;br /&gt;
        variation &amp;lt;= maxVariation;&lt;br /&gt;
        variation++&lt;br /&gt;
      ) {&lt;br /&gt;
        if (damagesWithPrimaryBonuses &amp;lt;= 2) {&lt;br /&gt;
          for (var damages = 1; damages &amp;lt;= 5; damages++) {&lt;br /&gt;
            damages *= bonusValues.useDamages;&lt;br /&gt;
&lt;br /&gt;
            var damagesWithFormula = skillFormula(damages, variation);&lt;br /&gt;
&lt;br /&gt;
            damagesWithFormula = Math.floor(&lt;br /&gt;
              (damagesWithFormula * bonusValues.weaponBonusCoeff) / 100&lt;br /&gt;
            );&lt;br /&gt;
&lt;br /&gt;
            var finalDamages = calcSkillDamageWithSecondaryBonuses(&lt;br /&gt;
              damagesWithFormula,&lt;br /&gt;
              bonusValues,&lt;br /&gt;
              damagesType,&lt;br /&gt;
              damagesWithPrimaryBonuses&lt;br /&gt;
            );&lt;br /&gt;
&lt;br /&gt;
            addKeyValue(damagesWeighted, finalDamages, weight / 5);&lt;br /&gt;
          }&lt;br /&gt;
        } else {&lt;br /&gt;
          damagesWithPrimaryBonuses *= bonusValues.useDamages;&lt;br /&gt;
&lt;br /&gt;
          var damagesWithFormula = skillFormula(&lt;br /&gt;
            damagesWithPrimaryBonuses,&lt;br /&gt;
            variation&lt;br /&gt;
          );&lt;br /&gt;
&lt;br /&gt;
          if (savedDamages.hasOwnProperty(damagesWithFormula)) {&lt;br /&gt;
            var finalDamages = savedDamages[damagesWithFormula];&lt;br /&gt;
            damagesWeighted[finalDamages] += weight;&lt;br /&gt;
            continue;&lt;br /&gt;
          }&lt;br /&gt;
&lt;br /&gt;
          var finalDamages = Math.floor(&lt;br /&gt;
            (damagesWithFormula * bonusValues.weaponBonusCoeff) / 100&lt;br /&gt;
          );&lt;br /&gt;
&lt;br /&gt;
          finalDamages = calcSkillDamageWithSecondaryBonuses(&lt;br /&gt;
            finalDamages,&lt;br /&gt;
            bonusValues,&lt;br /&gt;
            damagesType,&lt;br /&gt;
            damagesWithPrimaryBonuses&lt;br /&gt;
          );&lt;br /&gt;
&lt;br /&gt;
          savedDamages[damagesWithFormula] = finalDamages;&lt;br /&gt;
          addKeyValue(damagesWeighted, finalDamages, weight);&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return damagesWeightedByType;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcMagicSkillDamages(battleValues) {&lt;br /&gt;
  var {&lt;br /&gt;
    attackValues: {&lt;br /&gt;
      minMagicAttackValue,&lt;br /&gt;
      maxMagicAttackValue,&lt;br /&gt;
      magicAttackValueAugmentation,&lt;br /&gt;
      weights,&lt;br /&gt;
    },&lt;br /&gt;
    bonusValues,&lt;br /&gt;
    damagesTypeCombinaison,&lt;br /&gt;
    skillFormula,&lt;br /&gt;
    skillRange: [minVariation, maxVariation],&lt;br /&gt;
  } = battleValues;&lt;br /&gt;
&lt;br /&gt;
  var damagesWeightedByType = {};&lt;br /&gt;
&lt;br /&gt;
  for (var damagesType of damagesTypeCombinaison) {&lt;br /&gt;
    if (!damagesType.weight) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var damagesWeighted = {};&lt;br /&gt;
    var savedDamages = {};&lt;br /&gt;
&lt;br /&gt;
    damagesWeightedByType[damagesType.name] = damagesWeighted;&lt;br /&gt;
&lt;br /&gt;
    for (&lt;br /&gt;
      var magicAttackValue = minMagicAttackValue;&lt;br /&gt;
      magicAttackValue &amp;lt;= maxMagicAttackValue;&lt;br /&gt;
      magicAttackValue++&lt;br /&gt;
    ) {&lt;br /&gt;
      var index = magicAttackValue - minMagicAttackValue;&lt;br /&gt;
      var weight = weights[index] * damagesType.weight;&lt;br /&gt;
&lt;br /&gt;
      for (&lt;br /&gt;
        var variation = minVariation;&lt;br /&gt;
        variation &amp;lt;= maxVariation;&lt;br /&gt;
        variation++&lt;br /&gt;
      ) {&lt;br /&gt;
        var rawDamages = skillFormula(&lt;br /&gt;
          magicAttackValue + magicAttackValueAugmentation[index],&lt;br /&gt;
          variation&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        if (savedDamages.hasOwnProperty(rawDamages)) {&lt;br /&gt;
          var finalDamages = savedDamages[rawDamages];&lt;br /&gt;
          damagesWeighted[finalDamages] += weight;&lt;br /&gt;
          continue;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var damagesWithPrimaryBonuses = Math.floor(&lt;br /&gt;
          (rawDamages * bonusValues.weaponBonusCoeff) / 100&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        damagesWithPrimaryBonuses = calcDamageWithPrimaryBonuses(&lt;br /&gt;
          damagesWithPrimaryBonuses,&lt;br /&gt;
          bonusValues&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        if (damagesWithPrimaryBonuses &amp;lt;= 2) {&lt;br /&gt;
          for (var damages = 1; damages &amp;lt;= 5; damages++) {&lt;br /&gt;
            var finalDamages = calcSkillDamageWithSecondaryBonuses(&lt;br /&gt;
              damages,&lt;br /&gt;
              bonusValues,&lt;br /&gt;
              damagesType,&lt;br /&gt;
              damagesWithPrimaryBonuses&lt;br /&gt;
            );&lt;br /&gt;
            addKeyValue(damagesWeighted, finalDamages, weight / 5);&lt;br /&gt;
          }&lt;br /&gt;
        } else {&lt;br /&gt;
          var finalDamages = calcSkillDamageWithSecondaryBonuses(&lt;br /&gt;
            damagesWithPrimaryBonuses,&lt;br /&gt;
            bonusValues,&lt;br /&gt;
            damagesType,&lt;br /&gt;
            damagesWithPrimaryBonuses&lt;br /&gt;
          );&lt;br /&gt;
&lt;br /&gt;
          savedDamages[rawDamages] = finalDamages;&lt;br /&gt;
          addKeyValue(damagesWeighted, finalDamages, weight);&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return damagesWeightedByType;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcDamages(&lt;br /&gt;
  attacker,&lt;br /&gt;
  victim,&lt;br /&gt;
  attackType,&lt;br /&gt;
  battle,&lt;br /&gt;
  removeSkillVariation&lt;br /&gt;
) {&lt;br /&gt;
  var damagesCalculator, skillId, skillType;&lt;br /&gt;
&lt;br /&gt;
  if (attackType === &amp;quot;physical&amp;quot;) {&lt;br /&gt;
    damagesCalculator = calcPhysicalDamages;&lt;br /&gt;
  } else if (attackType.startsWith(&amp;quot;attackSkill&amp;quot;)) {&lt;br /&gt;
    skillId = Number(attackType.split(&amp;quot;attackSkill&amp;quot;)[1]);&lt;br /&gt;
&lt;br /&gt;
    if (isMagicClass(attacker) || isDispell(attacker, skillId)) {&lt;br /&gt;
      skillType = &amp;quot;magic&amp;quot;;&lt;br /&gt;
      damagesCalculator = calcMagicSkillDamages;&lt;br /&gt;
    } else {&lt;br /&gt;
      skillType = &amp;quot;physical&amp;quot;;&lt;br /&gt;
      damagesCalculator = calcPhysicalSkillDamages;&lt;br /&gt;
    }&lt;br /&gt;
  } else if (attackType.startsWith(&amp;quot;horseSkill&amp;quot;)) {&lt;br /&gt;
    skillType = &amp;quot;physical&amp;quot;;&lt;br /&gt;
    skillId = Number(attackType.split(&amp;quot;horseSkill&amp;quot;)[1]);&lt;br /&gt;
    damagesCalculator = calcPhysicalSkillDamages;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var battleValues = createBattleValues(attacker, victim, battle, skillType);&lt;br /&gt;
&lt;br /&gt;
  if (skillId) {&lt;br /&gt;
    getSkillFormula(battle, skillId, battleValues, removeSkillVariation);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var {&lt;br /&gt;
    attackValues: { totalCardinal, possibleDamagesCount },&lt;br /&gt;
  } = battleValues;&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    damagesWeightedByType: damagesCalculator(battleValues),&lt;br /&gt;
    totalCardinal: totalCardinal,&lt;br /&gt;
    possibleDamagesCount: possibleDamagesCount,&lt;br /&gt;
    skillType: skillType,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function damagesWithoutVariation(&lt;br /&gt;
  attacker,&lt;br /&gt;
  victim,&lt;br /&gt;
  attackType,&lt;br /&gt;
  battle,&lt;br /&gt;
  characters&lt;br /&gt;
) {&lt;br /&gt;
  startDamagesTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
  var {&lt;br /&gt;
    damagesWeightedByType,&lt;br /&gt;
    totalCardinal,&lt;br /&gt;
    possibleDamagesCount,&lt;br /&gt;
    skillType,&lt;br /&gt;
  } = calcDamages(attacker, victim, attackType, battle);&lt;br /&gt;
&lt;br /&gt;
  endDamagesTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
  possibleDamagesCount = displayResults(&lt;br /&gt;
    possibleDamagesCount,&lt;br /&gt;
    totalCardinal,&lt;br /&gt;
    damagesWeightedByType,&lt;br /&gt;
    battle,&lt;br /&gt;
    attacker.name,&lt;br /&gt;
    victim.name&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  endDisplayTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
  displayFightInfo(&lt;br /&gt;
    possibleDamagesCount,&lt;br /&gt;
    endDamagesTime - startDamagesTime,&lt;br /&gt;
    endDisplayTime - endDamagesTime,&lt;br /&gt;
    battle&lt;br /&gt;
  );&lt;br /&gt;
  addPotentialErrorInformation(&lt;br /&gt;
    battle.errorInformation,&lt;br /&gt;
    attacker,&lt;br /&gt;
    victim,&lt;br /&gt;
    skillType,&lt;br /&gt;
    characters&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  hideElement(battle.bonusVariationResultContainer);&lt;br /&gt;
  showElement(battle.fightResultContainer);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function damagesWithVariation(&lt;br /&gt;
  attacker,&lt;br /&gt;
  victim,&lt;br /&gt;
  attackType,&lt;br /&gt;
  battle,&lt;br /&gt;
  entity,&lt;br /&gt;
  entityVariation&lt;br /&gt;
) {&lt;br /&gt;
  startTime = performance.now();&lt;br /&gt;
  var damagesByBonus = [];&lt;br /&gt;
  var augmentationByBonus = [];&lt;br /&gt;
  var {&lt;br /&gt;
    bonusVariationMinValue: minVariation,&lt;br /&gt;
    bonusVariationMaxValue: maxVariation,&lt;br /&gt;
  } = entity;&lt;br /&gt;
  var step = Math.ceil((maxVariation - minVariation + 1) / 500);&lt;br /&gt;
  var simulationCount = 0;&lt;br /&gt;
  var simulationTime;&lt;br /&gt;
&lt;br /&gt;
  for (&lt;br /&gt;
    var bonusValue = minVariation;&lt;br /&gt;
    bonusValue &amp;lt;= maxVariation;&lt;br /&gt;
    bonusValue += step&lt;br /&gt;
  ) {&lt;br /&gt;
    entity[entityVariation] = bonusValue;&lt;br /&gt;
&lt;br /&gt;
    var { damagesWeightedByType, totalCardinal } = calcDamages(&lt;br /&gt;
      copyObject(attacker),&lt;br /&gt;
      copyObject(victim),&lt;br /&gt;
      attackType,&lt;br /&gt;
      battle,&lt;br /&gt;
      true&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    var meanDamages = calcMeanDamages(damagesWeightedByType, totalCardinal);&lt;br /&gt;
&lt;br /&gt;
    if (bonusValue === minVariation) {&lt;br /&gt;
      var firstDamages = Math.max(meanDamages, 1e-3);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    damagesByBonus.push({ x: bonusValue, y: meanDamages });&lt;br /&gt;
    augmentationByBonus.push({&lt;br /&gt;
      x: bonusValue,&lt;br /&gt;
      y: meanDamages / firstDamages - 1,&lt;br /&gt;
    });&lt;br /&gt;
    simulationCount++;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  endTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
  battle.damagesByBonus = damagesByBonus.concat(entityVariation);&lt;br /&gt;
&lt;br /&gt;
  addToBonusVariationChart(&lt;br /&gt;
    damagesByBonus,&lt;br /&gt;
    augmentationByBonus,&lt;br /&gt;
    entity.bonusVariationDisplay,&lt;br /&gt;
    battle.bonusVariationChart&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  simulationCount = battle.numberFormats.default.format(simulationCount);&lt;br /&gt;
  simulationTime = battle.numberFormats.second.format(&lt;br /&gt;
    (endTime - startTime) / 1000&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  battle.simulationCounter.textContent = simulationCount;&lt;br /&gt;
  battle.simulationTime.textContent = simulationTime;&lt;br /&gt;
&lt;br /&gt;
  hideElement(battle.fightResultContainer);&lt;br /&gt;
  showElement(battle.bonusVariationResultContainer);&lt;br /&gt;
&lt;br /&gt;
  if (&lt;br /&gt;
    isChecked(attacker.bonusVariationActivation) &amp;amp;&amp;amp;&lt;br /&gt;
    isChecked(victim.bonusVariationActivation)&lt;br /&gt;
  ) {&lt;br /&gt;
    showElement(battle.errorInformation[&amp;quot;attacker-victim-variation&amp;quot;]);&lt;br /&gt;
  } else {&lt;br /&gt;
    hideElement(battle.errorInformation[&amp;quot;attacker-victim-variation&amp;quot;]);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function changeMonsterValues(monster, instance, attacker) {&lt;br /&gt;
  switch (instance) {&lt;br /&gt;
    case &amp;quot;SungMahiTower&amp;quot;:&lt;br /&gt;
      var sungMahiFloor = 1;&lt;br /&gt;
      var sungMahiStep = 1;&lt;br /&gt;
      var rawDefense = 120;&lt;br /&gt;
&lt;br /&gt;
      if (isPC(attacker)) {&lt;br /&gt;
        sungMahiFloor = attacker.sungMahiFloor;&lt;br /&gt;
        sungMahiStep = attacker.sungMahiStep;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (monster.rank === 5) {&lt;br /&gt;
        monster.level = 121;&lt;br /&gt;
        monster.dex = 75;&lt;br /&gt;
        rawDefense += 1;&lt;br /&gt;
      } else if (monster.rank === 6) {&lt;br /&gt;
        monster.level = 123;&lt;br /&gt;
        monster.dex = 75;&lt;br /&gt;
        rawDefense += 1;&lt;br /&gt;
      } else {&lt;br /&gt;
        monster.level = 120;&lt;br /&gt;
        monster.dex = 68;&lt;br /&gt;
      }&lt;br /&gt;
      monster.vit = 100;&lt;br /&gt;
      monster.rawDefense = rawDefense + (sungMahiStep - 1) * 6;&lt;br /&gt;
      monster.fistDefense = 0;&lt;br /&gt;
      monster.swordDefense = 0;&lt;br /&gt;
      monster.twoHandedSwordDefense = 0;&lt;br /&gt;
      monster.daggerDefense = 0;&lt;br /&gt;
      monster.bellDefense = 0;&lt;br /&gt;
      monster.fanDefense = 0;&lt;br /&gt;
      monster.arrowDefense = 0;&lt;br /&gt;
      monster.clawDefense = 0;&lt;br /&gt;
      monster.magicResistance = 0;&lt;br /&gt;
      monster.fireResistance = -20;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  // Alastor&lt;br /&gt;
  if (monster.vnum === 6790) {&lt;br /&gt;
    monster.iceResistance = 0;&lt;br /&gt;
    monster.iceBonus = 0;&lt;br /&gt;
    monster.lightningResistance = -10;&lt;br /&gt;
    monster.lightningBonus = 65;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createWeapon(weaponVnum) {&lt;br /&gt;
  var weapon = weaponData[weaponVnum];&lt;br /&gt;
  var weaponName = weapon[0];&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    name: weaponName,&lt;br /&gt;
    type: weapon[1],&lt;br /&gt;
    minAttackValue: weapon[2][2],&lt;br /&gt;
    maxAttackValue: weapon[2][3],&lt;br /&gt;
    minMagicAttackValue: weapon[2][0],&lt;br /&gt;
    maxMagicAttackValue: weapon[2][1],&lt;br /&gt;
    upgrades: weapon[3],&lt;br /&gt;
    isSerpent: isValueInArray(&amp;quot;serpent&amp;quot;, weaponName.toLowerCase()),&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createMonster(monsterVnum, attacker) {&lt;br /&gt;
  var monsterAttributes = monsterData[monsterVnum];&lt;br /&gt;
&lt;br /&gt;
  var monster = {&lt;br /&gt;
    vnum: Number(monsterVnum),&lt;br /&gt;
    name: monsterAttributes[36],&lt;br /&gt;
    rank: monsterAttributes[0],&lt;br /&gt;
    race: monsterAttributes[1],&lt;br /&gt;
    attack: monsterAttributes[2],&lt;br /&gt;
    level: monsterAttributes[3],&lt;br /&gt;
    type: monsterAttributes[4],&lt;br /&gt;
    str: monsterAttributes[5],&lt;br /&gt;
    dex: monsterAttributes[6],&lt;br /&gt;
    vit: monsterAttributes[7],&lt;br /&gt;
    int: monsterAttributes[8],&lt;br /&gt;
    minAttackValue: monsterAttributes[9],&lt;br /&gt;
    maxAttackValue: monsterAttributes[10],&lt;br /&gt;
    rawDefense: monsterAttributes[11],&lt;br /&gt;
    criticalHit: monsterAttributes[12],&lt;br /&gt;
    piercingHit: monsterAttributes[13],&lt;br /&gt;
    fistDefense: monsterAttributes[14],&lt;br /&gt;
    swordDefense: monsterAttributes[15],&lt;br /&gt;
    twoHandedSwordDefense: monsterAttributes[16],&lt;br /&gt;
    daggerDefense: monsterAttributes[17],&lt;br /&gt;
    bellDefense: monsterAttributes[18],&lt;br /&gt;
    fanDefense: monsterAttributes[19],&lt;br /&gt;
    arrowDefense: monsterAttributes[20],&lt;br /&gt;
    clawDefense: monsterAttributes[21],&lt;br /&gt;
    fireResistance: monsterAttributes[22],&lt;br /&gt;
    lightningResistance: monsterAttributes[23],&lt;br /&gt;
    magicResistance: monsterAttributes[24],&lt;br /&gt;
    windResistance: monsterAttributes[25],&lt;br /&gt;
    lightningBonus: monsterAttributes[26],&lt;br /&gt;
    fireBonus: monsterAttributes[27],&lt;br /&gt;
    iceBonus: monsterAttributes[28],&lt;br /&gt;
    windBonus: monsterAttributes[29],&lt;br /&gt;
    earthBonus: monsterAttributes[30],&lt;br /&gt;
    darknessBonus: monsterAttributes[31],&lt;br /&gt;
    darknessResistance: monsterAttributes[32],&lt;br /&gt;
    iceResistance: monsterAttributes[33],&lt;br /&gt;
    earthResistance: monsterAttributes[34],&lt;br /&gt;
    damageMultiplier: monsterAttributes[35],&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  // monster.instance = 0;&lt;br /&gt;
&lt;br /&gt;
  // if (attacker &amp;amp;&amp;amp; monster.instance === 0) {&lt;br /&gt;
  //   changeMonsterValues(monster, &amp;quot;SungMahiTower&amp;quot;, attacker);&lt;br /&gt;
  // }&lt;br /&gt;
&lt;br /&gt;
  changeMonsterValues(monster);&lt;br /&gt;
&lt;br /&gt;
  monster.defense = monster.rawDefense + monster.level + monster.vit;&lt;br /&gt;
&lt;br /&gt;
  return monster;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addPotentialErrorInformation(&lt;br /&gt;
  errorInformation,&lt;br /&gt;
  attacker,&lt;br /&gt;
  victim,&lt;br /&gt;
  skillType,&lt;br /&gt;
  characters&lt;br /&gt;
) {&lt;br /&gt;
  for (var error of Object.values(errorInformation)) {&lt;br /&gt;
    hideElement(error);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker)) {&lt;br /&gt;
    if (isRiding(attacker)) {&lt;br /&gt;
      if (attacker.horsePoint === 0) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;horse-level&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
      showElement(errorInformation[&amp;quot;horse-stat&amp;quot;]);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isPolymorph(attacker)) {&lt;br /&gt;
      if (attacker.polymorphPoint === 0) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;polymorph-level&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (&lt;br /&gt;
        (attacker.polymorphPoint &amp;lt;= 39 &amp;amp;&amp;amp; attacker.attackValuePercent &amp;lt;= 199) ||&lt;br /&gt;
        (attacker.polymorphPoint === 40 &amp;amp;&amp;amp; attacker.attackValuePercent &amp;lt;= 299)&lt;br /&gt;
      ) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;polymorph-bonus&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
    if (skillType === &amp;quot;magic&amp;quot;) {&lt;br /&gt;
      if (attacker.magicAttackValue) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;magic-attack-value-bonus&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
      if (victim.magicResistance) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;magic-resistance&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    showElement(errorInformation[&amp;quot;monster-attacker&amp;quot;]);&lt;br /&gt;
    if (isMagicAttacker(attacker) &amp;amp;&amp;amp; victim.magicResistance) {&lt;br /&gt;
      showElement(errorInformation[&amp;quot;magic-resistance&amp;quot;]);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (isPC(victim)) {&lt;br /&gt;
    if (isRiding(victim)) {&lt;br /&gt;
      showElement(errorInformation[&amp;quot;horse-stat&amp;quot;]);&lt;br /&gt;
    }&lt;br /&gt;
    if (isPolymorph(victim)) {&lt;br /&gt;
      if (attacker.polymorphPoint === 0) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;polymorph-level&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
      showElement(errorInformation[&amp;quot;polymorph-defense&amp;quot;]);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (characters.unsavedChanges) {&lt;br /&gt;
    showElement(errorInformation[&amp;quot;save&amp;quot;]);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function reduceChartPointsListener(battle) {&lt;br /&gt;
  var {&lt;br /&gt;
    reduceChartPointsContainer,&lt;br /&gt;
    reduceChartPoints,&lt;br /&gt;
    numberFormats: { second: numberFormat },&lt;br /&gt;
    displayTime,&lt;br /&gt;
  } = battle;&lt;br /&gt;
&lt;br /&gt;
  reduceChartPoints.addEventListener(&amp;quot;change&amp;quot;, function () {&lt;br /&gt;
    var startDisplayTime = performance.now();&lt;br /&gt;
    var scatterDataByType = battle.scatterDataByType;&lt;br /&gt;
    var {&lt;br /&gt;
      chart,&lt;br /&gt;
      maxPoints,&lt;br /&gt;
      chart: {&lt;br /&gt;
        data: { datasets },&lt;br /&gt;
      },&lt;br /&gt;
    } = battle.damagesChart;&lt;br /&gt;
    var addAnimations = false;&lt;br /&gt;
&lt;br /&gt;
    for (var index = 0; index &amp;lt; datasets.length; index++) {&lt;br /&gt;
      var dataset = datasets[index];&lt;br /&gt;
      var scatterData = scatterDataByType[dataset.name];&lt;br /&gt;
&lt;br /&gt;
      if (dataset.canBeReduced &amp;amp;&amp;amp; reduceChartPoints.checked) {&lt;br /&gt;
        dataset.data = aggregateDamages(scatterData, maxPoints);&lt;br /&gt;
        addAnimations = true;&lt;br /&gt;
      } else {&lt;br /&gt;
        dataset.data = scatterData;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    handleChartAnimations(chart, addAnimations);&lt;br /&gt;
    chart.update();&lt;br /&gt;
&lt;br /&gt;
    displayTime.textContent = numberFormat.format(&lt;br /&gt;
      (performance.now() - startDisplayTime) / 1000&lt;br /&gt;
    );&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  reduceChartPointsContainer.addEventListener(&amp;quot;pointerup&amp;quot;, function (event) {&lt;br /&gt;
    if (event.pointerType === &amp;quot;mouse&amp;quot;) {&lt;br /&gt;
      reduceChartPoints.click();&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function downloadRawDataListener(battle) {&lt;br /&gt;
  var { downLoadRawData, downLoadRawDataVariation } = battle;&lt;br /&gt;
  var fileType = &amp;quot;text/csv;charset=utf-8;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  downLoadRawData.addEventListener(&amp;quot;click&amp;quot;, function () {&lt;br /&gt;
    var damagesWeightedByType = battle.damagesWeightedByType;&lt;br /&gt;
    var filename = &amp;quot;raw_damages.csv&amp;quot;;&lt;br /&gt;
    var csvContent = &amp;quot;damage,probabilities,damageType\n&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    for (var damagesType in damagesWeightedByType) {&lt;br /&gt;
      var damagesWeighted = damagesWeightedByType[damagesType];&lt;br /&gt;
&lt;br /&gt;
      for (var damages in damagesWeighted) {&lt;br /&gt;
        csvContent +=&lt;br /&gt;
          damages + &amp;quot;,&amp;quot; + damagesWeighted[damages] + &amp;quot;,&amp;quot; + damagesType + &amp;quot;\n&amp;quot;;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    downloadData(csvContent, fileType, filename);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  downLoadRawDataVariation.addEventListener(&amp;quot;click&amp;quot;, function () {&lt;br /&gt;
    var damagesByBonus = battle.damagesByBonus;&lt;br /&gt;
    var damagesByBonusLength = damagesByBonus.length;&lt;br /&gt;
    var filename = &amp;quot;damages_variation.csv&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    if (!damagesByBonusLength) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var csvContent =&lt;br /&gt;
      damagesByBonus[damagesByBonusLength - 1] + &amp;quot;,averageDamage\n&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    for (var index = 0; index &amp;lt; damagesByBonusLength - 1; index++) {&lt;br /&gt;
      var row = damagesByBonus[index];&lt;br /&gt;
&lt;br /&gt;
      csvContent += row.x + &amp;quot;,&amp;quot; + row.y + &amp;quot;\n&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    downloadData(csvContent, fileType, filename);&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function displayResults(&lt;br /&gt;
  possibleDamagesCount,&lt;br /&gt;
  totalCardinal,&lt;br /&gt;
  damagesWeightedByType,&lt;br /&gt;
  battle,&lt;br /&gt;
  attackerName,&lt;br /&gt;
  victimName&lt;br /&gt;
) {&lt;br /&gt;
  var [&lt;br /&gt;
    meanDamages,&lt;br /&gt;
    minDamages,&lt;br /&gt;
    maxDamages,&lt;br /&gt;
    scatterDataByType,&lt;br /&gt;
    possibleDamagesCount,&lt;br /&gt;
    uniqueDamagesCount,&lt;br /&gt;
  ] = prepareDamagesData(&lt;br /&gt;
    damagesWeightedByType,&lt;br /&gt;
    possibleDamagesCount,&lt;br /&gt;
    totalCardinal&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  addToDamagesChart(&lt;br /&gt;
    scatterDataByType,&lt;br /&gt;
    battle.damagesChart,&lt;br /&gt;
    battle.reduceChartPoints.checked&lt;br /&gt;
  );&lt;br /&gt;
  updateDamagesChartDescription(&lt;br /&gt;
    battle.uniqueDamagesCounters,&lt;br /&gt;
    uniqueDamagesCount,&lt;br /&gt;
    battle.numberFormats.default&lt;br /&gt;
  );&lt;br /&gt;
  displayFightResults(&lt;br /&gt;
    battle,&lt;br /&gt;
    attackerName,&lt;br /&gt;
    victimName,&lt;br /&gt;
    meanDamages,&lt;br /&gt;
    minDamages,&lt;br /&gt;
    maxDamages&lt;br /&gt;
  );&lt;br /&gt;
  battle.damagesWeightedByType = damagesWeightedByType;&lt;br /&gt;
  battle.scatterDataByType = scatterDataByType;&lt;br /&gt;
&lt;br /&gt;
  return possibleDamagesCount;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function displayFightResults(&lt;br /&gt;
  battle,&lt;br /&gt;
  attackerName,&lt;br /&gt;
  victimName,&lt;br /&gt;
  meanDamages,&lt;br /&gt;
  minDamages,&lt;br /&gt;
  maxDamages&lt;br /&gt;
) {&lt;br /&gt;
  var {&lt;br /&gt;
    tableResultFight,&lt;br /&gt;
    tableResultHistory,&lt;br /&gt;
    attackTypeSelection,&lt;br /&gt;
    savedFights,&lt;br /&gt;
    numberFormats: { default: numberFormat },&lt;br /&gt;
    deleteFightTemplate,&lt;br /&gt;
  } = battle;&lt;br /&gt;
&lt;br /&gt;
  hideElement(tableResultHistory.rows[1]);&lt;br /&gt;
&lt;br /&gt;
  var valuesToDisplay = [&lt;br /&gt;
    attackerName,&lt;br /&gt;
    victimName,&lt;br /&gt;
    attackTypeSelection.options[attackTypeSelection.selectedIndex].textContent,&lt;br /&gt;
    meanDamages,&lt;br /&gt;
    minDamages,&lt;br /&gt;
    maxDamages,&lt;br /&gt;
  ];&lt;br /&gt;
&lt;br /&gt;
  savedFights.push(valuesToDisplay);&lt;br /&gt;
  updateSavedFights(savedFights);&lt;br /&gt;
&lt;br /&gt;
  editTableResultRow(tableResultFight.rows[1], valuesToDisplay, numberFormat);&lt;br /&gt;
  addRowToTableResultHistory(&lt;br /&gt;
    tableResultHistory,&lt;br /&gt;
    valuesToDisplay,&lt;br /&gt;
    deleteFightTemplate,&lt;br /&gt;
    numberFormat&lt;br /&gt;
  );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function displayFightInfo(&lt;br /&gt;
  possibleDamagesCount,&lt;br /&gt;
  damagesTime,&lt;br /&gt;
  displayTime,&lt;br /&gt;
  battle&lt;br /&gt;
) {&lt;br /&gt;
  var container = battle.possibleDamagesCounter.parentElement;&lt;br /&gt;
&lt;br /&gt;
  if (possibleDamagesCount &amp;lt;= 1) {&lt;br /&gt;
    hideElement(container);&lt;br /&gt;
    return;&lt;br /&gt;
  } else {&lt;br /&gt;
    showElement(container);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  possibleDamagesCount =&lt;br /&gt;
    battle.numberFormats.default.format(possibleDamagesCount);&lt;br /&gt;
  damagesTime = battle.numberFormats.second.format(damagesTime / 1000);&lt;br /&gt;
  displayTime = battle.numberFormats.second.format(displayTime / 1000);&lt;br /&gt;
&lt;br /&gt;
  battle.possibleDamagesCounter.textContent = possibleDamagesCount;&lt;br /&gt;
  battle.damagesTime.textContent = damagesTime;&lt;br /&gt;
  battle.displayTime.textContent = displayTime;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isPseudoSaved(characters, pseudo) {&lt;br /&gt;
  return characters.savedCharacters.hasOwnProperty(pseudo);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createBattle(characters, battle) {&lt;br /&gt;
  battle.battleForm.addEventListener(&amp;quot;submit&amp;quot;, function (event) {&lt;br /&gt;
    event.preventDefault();&lt;br /&gt;
&lt;br /&gt;
    // auto save&lt;br /&gt;
    if (characters.unsavedChanges) {&lt;br /&gt;
      characters.saveButton.click();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var battleInfo = new FormData(event.target);&lt;br /&gt;
    var attackerName = battleInfo.get(&amp;quot;attacker&amp;quot;);&lt;br /&gt;
    var attackType = battleInfo.get(&amp;quot;attackTypeSelection&amp;quot;);&lt;br /&gt;
    var victimName = battleInfo.get(&amp;quot;victim&amp;quot;);&lt;br /&gt;
    var attackerVariation;&lt;br /&gt;
    var victimVariation;&lt;br /&gt;
&lt;br /&gt;
    if (!attackerName &amp;amp;&amp;amp; !attackType &amp;amp;&amp;amp; !victimName) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isPseudoSaved(characters, attackerName)) {&lt;br /&gt;
      var attacker = copyObject(characters.savedCharacters[attackerName]);&lt;br /&gt;
      attackerVariation = attacker.bonusVariation;&lt;br /&gt;
    } else {&lt;br /&gt;
      var attacker = createMonster(attackerName);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isPseudoSaved(characters, victimName)) {&lt;br /&gt;
      var victim = copyObject(characters.savedCharacters[victimName]);&lt;br /&gt;
      victimVariation = victim.bonusVariation;&lt;br /&gt;
    } else {&lt;br /&gt;
      var victim = createMonster(victimName, attacker);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      isChecked(attacker.bonusVariationActivation) &amp;amp;&amp;amp;&lt;br /&gt;
      attacker.hasOwnProperty(attackerVariation) &amp;amp;&amp;amp;&lt;br /&gt;
      attacker.bonusVariationMinValue &amp;lt; attacker.bonusVariationMaxValue&lt;br /&gt;
    ) {&lt;br /&gt;
      damagesWithVariation(&lt;br /&gt;
        attacker,&lt;br /&gt;
        victim,&lt;br /&gt;
        attackType,&lt;br /&gt;
        battle,&lt;br /&gt;
        attacker,&lt;br /&gt;
        attackerVariation&lt;br /&gt;
      );&lt;br /&gt;
    } else if (&lt;br /&gt;
      isChecked(victim.bonusVariationActivation) &amp;amp;&amp;amp;&lt;br /&gt;
      victim.hasOwnProperty(victimVariation) &amp;amp;&amp;amp;&lt;br /&gt;
      victim.bonusVariationMinValue &amp;lt; victim.bonusVariationMaxValue&lt;br /&gt;
    ) {&lt;br /&gt;
      damagesWithVariation(&lt;br /&gt;
        attacker,&lt;br /&gt;
        victim,&lt;br /&gt;
        attackType,&lt;br /&gt;
        battle,&lt;br /&gt;
        victim,&lt;br /&gt;
        victimVariation&lt;br /&gt;
      );&lt;br /&gt;
    } else {&lt;br /&gt;
      damagesWithoutVariation(attacker, victim, attackType, battle, characters);&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createMapping() {&lt;br /&gt;
  mapping = {&lt;br /&gt;
    typeFlag: [&lt;br /&gt;
      &amp;quot;animalBonus&amp;quot;, // 0&lt;br /&gt;
      &amp;quot;humanBonus&amp;quot;, // 1&lt;br /&gt;
      &amp;quot;orcBonus&amp;quot;, // 2&lt;br /&gt;
      &amp;quot;mysticBonus&amp;quot;, // 3&lt;br /&gt;
      &amp;quot;undeadBonus&amp;quot;, // 4&lt;br /&gt;
      &amp;quot;insectBonus&amp;quot;, // 5&lt;br /&gt;
      &amp;quot;desertBonus&amp;quot;, // 6&lt;br /&gt;
      &amp;quot;devilBonus&amp;quot;, // 7&lt;br /&gt;
    ],&lt;br /&gt;
    raceBonus: {&lt;br /&gt;
      warrior: &amp;quot;warriorBonus&amp;quot;,&lt;br /&gt;
      sura: &amp;quot;suraBonus&amp;quot;,&lt;br /&gt;
      ninja: &amp;quot;ninjaBonus&amp;quot;,&lt;br /&gt;
      shaman: &amp;quot;shamanBonus&amp;quot;,&lt;br /&gt;
      lycan: &amp;quot;lycanBonus&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    raceResistance: {&lt;br /&gt;
      warrior: &amp;quot;warriorResistance&amp;quot;,&lt;br /&gt;
      sura: &amp;quot;suraResistance&amp;quot;,&lt;br /&gt;
      ninja: &amp;quot;ninjaResistance&amp;quot;,&lt;br /&gt;
      shaman: &amp;quot;shamanResistance&amp;quot;,&lt;br /&gt;
      lycan: &amp;quot;lycanResistance&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    defenseWeapon: [&lt;br /&gt;
      &amp;quot;swordDefense&amp;quot;, // 0&lt;br /&gt;
      &amp;quot;daggerDefense&amp;quot;, // 1&lt;br /&gt;
      &amp;quot;arrowDefense&amp;quot;, // 2&lt;br /&gt;
      &amp;quot;twoHandedSwordDefense&amp;quot;, // 3&lt;br /&gt;
      &amp;quot;bellDefense&amp;quot;, // 4&lt;br /&gt;
      &amp;quot;clawDefense&amp;quot;, // 5&lt;br /&gt;
      &amp;quot;fanDefense&amp;quot;, // 6&lt;br /&gt;
      &amp;quot;swordDefense&amp;quot;, // 7&lt;br /&gt;
      &amp;quot;fistDefense&amp;quot;, // 8&lt;br /&gt;
    ],&lt;br /&gt;
    breakWeapon: [&lt;br /&gt;
      &amp;quot;breakSwordDefense&amp;quot;, // 0&lt;br /&gt;
      &amp;quot;breakDaggerDefense&amp;quot;, // 1&lt;br /&gt;
      &amp;quot;breakArrowDefense&amp;quot;, // 2&lt;br /&gt;
      &amp;quot;breakTwoHandedSwordDefense&amp;quot;, // 3&lt;br /&gt;
      &amp;quot;breakBellDefense&amp;quot;, // 4&lt;br /&gt;
      &amp;quot;breakClawDefense&amp;quot;, // 5&lt;br /&gt;
      &amp;quot;breakFanDefense&amp;quot;, // 6&lt;br /&gt;
      &amp;quot;breakSwordDefense&amp;quot;, // 7&lt;br /&gt;
    ],&lt;br /&gt;
    elementBonus: [&lt;br /&gt;
      &amp;quot;fireBonus&amp;quot;, // 0&lt;br /&gt;
      &amp;quot;iceBonus&amp;quot;, // 1&lt;br /&gt;
      &amp;quot;windBonus&amp;quot;, // 2&lt;br /&gt;
      &amp;quot;lightningBonus&amp;quot;, // 3&lt;br /&gt;
      &amp;quot;earthBonus&amp;quot;, // 4&lt;br /&gt;
      &amp;quot;darknessBonus&amp;quot;, // 5&lt;br /&gt;
    ],&lt;br /&gt;
    elementResistance: [&lt;br /&gt;
      &amp;quot;fireResistance&amp;quot;, // 0&lt;br /&gt;
      &amp;quot;iceResistance&amp;quot;, // 1&lt;br /&gt;
      &amp;quot;windResistance&amp;quot;, // 2&lt;br /&gt;
      &amp;quot;lightningResistance&amp;quot;, // 3&lt;br /&gt;
      &amp;quot;earthResistance&amp;quot;, // 4&lt;br /&gt;
      &amp;quot;darknessResistance&amp;quot;, // 5&lt;br /&gt;
    ],&lt;br /&gt;
  };&lt;br /&gt;
  return mapping;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createConstants() {&lt;br /&gt;
  var constants = {&lt;br /&gt;
    polymorphPowerTable: [&lt;br /&gt;
      10, 11, 11, 12, 13, 13, 14, 15, 16, 17, 18, 19, 20, 22, 23, 24, 26, 27,&lt;br /&gt;
      29, 31, 33, 35, 37, 39, 41, 44, 46, 49, 52, 55, 59, 62, 66, 70, 74, 79,&lt;br /&gt;
      84, 89, 94, 100, 0,&lt;br /&gt;
    ],&lt;br /&gt;
    skillPowerTable: [&lt;br /&gt;
      0, 0.05, 0.06, 0.08, 0.1, 0.12, 0.14, 0.16, 0.18, 0.2, 0.22, 0.24, 0.26,&lt;br /&gt;
      0.28, 0.3, 0.32, 0.34, 0.36, 0.38, 0.4, 0.5, 0.52, 0.54, 0.56, 0.58, 0.6,&lt;br /&gt;
      0.63, 0.66, 0.69, 0.72, 0.82, 0.85, 0.88, 0.91, 0.94, 0.98, 1.02, 1.06,&lt;br /&gt;
      1.1, 1.15, 1.25,&lt;br /&gt;
    ],&lt;br /&gt;
    marriageTable: {&lt;br /&gt;
      harmonyEarrings: [4, 5, 6, 8],&lt;br /&gt;
      loveEarrings: [4, 5, 6, 8],&lt;br /&gt;
      harmonyBracelet: [4, 5, 6, 8],&lt;br /&gt;
      loveNecklace: [20, 25, 30, 40],&lt;br /&gt;
      harmonyNecklace: [12, 16, 20, 30],&lt;br /&gt;
    },&lt;br /&gt;
    allowedWeaponsPerRace: {&lt;br /&gt;
      warrior: [0, 3, 8],&lt;br /&gt;
      ninja: [0, 1, 2, 8],&lt;br /&gt;
      sura: [0, 7, 8],&lt;br /&gt;
      shaman: [4, 6, 8],&lt;br /&gt;
      lycan: [5, 8],&lt;br /&gt;
    },&lt;br /&gt;
    translation: {&lt;br /&gt;
      fr: {&lt;br /&gt;
        damages: &amp;quot;Dégâts&amp;quot;,&lt;br /&gt;
        percentage: &amp;quot;Pourcentage&amp;quot;,&lt;br /&gt;
        miss: &amp;quot;Miss&amp;quot;,&lt;br /&gt;
        normalHit: &amp;quot;Coup classique&amp;quot;,&lt;br /&gt;
        criticalHit: &amp;quot;Coup critique&amp;quot;,&lt;br /&gt;
        piercingHit: &amp;quot;Coup perçant&amp;quot;,&lt;br /&gt;
        criticalPiercingHit: &amp;quot;Coup critique perçant&amp;quot;,&lt;br /&gt;
        damagesRepartition: &amp;quot;Distribution des dégâts&amp;quot;,&lt;br /&gt;
        averageDamages: &amp;quot;Dégâts moyens&amp;quot;,&lt;br /&gt;
        damagesAugmentation: &amp;quot;Augmentation des dégâts&amp;quot;,&lt;br /&gt;
        bonusVariationTitle: [&lt;br /&gt;
          &amp;quot;Évolution des dégâts moyens&amp;quot;,&lt;br /&gt;
          &amp;quot;par rapport à la valeur d'un bonus&amp;quot;,&lt;br /&gt;
        ],&lt;br /&gt;
      },&lt;br /&gt;
      en: {&lt;br /&gt;
        damages: &amp;quot;Damage&amp;quot;,&lt;br /&gt;
        percentage: &amp;quot;Percentage&amp;quot;,&lt;br /&gt;
        miss: &amp;quot;Miss&amp;quot;,&lt;br /&gt;
        normalHit: &amp;quot;Normal Hit&amp;quot;,&lt;br /&gt;
        criticalHit: &amp;quot;Critical Hit&amp;quot;,&lt;br /&gt;
        piercingHit: &amp;quot;Piercing Hit&amp;quot;,&lt;br /&gt;
        criticalPiercingHit: &amp;quot;Critical Piercing Hit&amp;quot;,&lt;br /&gt;
        damagesRepartition: &amp;quot;Damage Repartition&amp;quot;,&lt;br /&gt;
        averageDamages: &amp;quot;Average Damage&amp;quot;,&lt;br /&gt;
        damagesAugmentation: &amp;quot;Damage Augmentation&amp;quot;,&lt;br /&gt;
        bonusVariationTitle: [&lt;br /&gt;
          &amp;quot;Evolution of Average Damage&amp;quot;,&lt;br /&gt;
          &amp;quot;Relative to a Bonus Value&amp;quot;,&lt;br /&gt;
        ],&lt;br /&gt;
      },&lt;br /&gt;
      tr: {&lt;br /&gt;
        damages: &amp;quot;Hasar&amp;quot;,&lt;br /&gt;
        percentage: &amp;quot;Yüzde&amp;quot;,&lt;br /&gt;
        miss: &amp;quot;Miss Vuruş&amp;quot;,&lt;br /&gt;
        normalHit: &amp;quot;Düz Vuruş&amp;quot;,&lt;br /&gt;
        criticalHit: &amp;quot;Kritik Vuruş&amp;quot;,&lt;br /&gt;
        piercingHit: &amp;quot;Delici Vuruş&amp;quot;,&lt;br /&gt;
        criticalPiercingHit: &amp;quot;Kritikli Delici Vuruş&amp;quot;,&lt;br /&gt;
        damagesRepartition: &amp;quot;Hasar Dağılımı&amp;quot;,&lt;br /&gt;
        averageDamages: &amp;quot;Ortalama Hasar&amp;quot;,&lt;br /&gt;
        damagesAugmentation: &amp;quot;Ortalama Hasar Artışı&amp;quot;,&lt;br /&gt;
        bonusVariationTitle: [&lt;br /&gt;
          &amp;quot;Bir bonusun değerine kıyasla&amp;quot;,&lt;br /&gt;
          &amp;quot;Ortalama Hasar Çizelgesi&amp;quot;,&lt;br /&gt;
        ],&lt;br /&gt;
      },&lt;br /&gt;
      ro: {&lt;br /&gt;
        damages: &amp;quot;Daune&amp;quot;,&lt;br /&gt;
        percentage: &amp;quot;Procent&amp;quot;,&lt;br /&gt;
        miss: &amp;quot;Miss&amp;quot;,&lt;br /&gt;
        normalHit: &amp;quot;Lovitura normala&amp;quot;,&lt;br /&gt;
        criticalHit: &amp;quot;Lovitura critica&amp;quot;,&lt;br /&gt;
        piercingHit: &amp;quot;Lovitura patrunzatoare&amp;quot;,&lt;br /&gt;
        criticalPiercingHit: &amp;quot;Lovitura critica si patrunzatoare&amp;quot;,&lt;br /&gt;
        damagesRepartition: &amp;quot;Distribuția daunelor&amp;quot;,&lt;br /&gt;
        averageDamages: &amp;quot;Media damageului&amp;quot;,&lt;br /&gt;
        damagesAugmentation: &amp;quot;Damage imbunatatit&amp;quot;,&lt;br /&gt;
        bonusVariationTitle: [&lt;br /&gt;
          &amp;quot;Evolutia mediei damageului&amp;quot;,&lt;br /&gt;
          &amp;quot;relativ la o valoare bonus&amp;quot;,&lt;br /&gt;
        ],&lt;br /&gt;
      },&lt;br /&gt;
      de: {&lt;br /&gt;
        damages: &amp;quot;Schäden&amp;quot;,&lt;br /&gt;
        percentage: &amp;quot;Prozentsatz&amp;quot;,&lt;br /&gt;
        miss: &amp;quot;Verfehlen&amp;quot;,&lt;br /&gt;
        normalHit: &amp;quot;Normaler Treffer&amp;quot;,&lt;br /&gt;
        criticalHit: &amp;quot;Kritischer Treffer&amp;quot;,&lt;br /&gt;
        piercingHit: &amp;quot;Durchdringender Treffer&amp;quot;,&lt;br /&gt;
        criticalPiercingHit: &amp;quot;Kritischer durchdringender Treffer&amp;quot;,&lt;br /&gt;
        damagesRepartition: &amp;quot;Schadensverteilung&amp;quot;,&lt;br /&gt;
        averageDamages: &amp;quot;Durchschnittlicher Schaden&amp;quot;,&lt;br /&gt;
        damagesAugmentation: &amp;quot;Schadenserhöhung&amp;quot;,&lt;br /&gt;
        bonusVariationTitle: [&lt;br /&gt;
          &amp;quot;Entwicklung des durchschnittlichen Schadens&amp;quot;,&lt;br /&gt;
          &amp;quot;im Verhältnis zu einem Bonus&amp;quot;,&lt;br /&gt;
        ],&lt;br /&gt;
      },&lt;br /&gt;
      pt: {&lt;br /&gt;
        damages: &amp;quot;Dano&amp;quot;,&lt;br /&gt;
        percentage: &amp;quot;Percentagem&amp;quot;,&lt;br /&gt;
        miss: &amp;quot;Miss&amp;quot;,&lt;br /&gt;
        normalHit: &amp;quot;Dano normal&amp;quot;,&lt;br /&gt;
        criticalHit: &amp;quot;Dano crítico&amp;quot;,&lt;br /&gt;
        piercingHit: &amp;quot;Dano perfurante&amp;quot;,&lt;br /&gt;
        criticalPiercingHit: &amp;quot;Dano crítico perfurante&amp;quot;,&lt;br /&gt;
        damagesRepartition: &amp;quot;Repartição de dano&amp;quot;,&lt;br /&gt;
        averageDamages: &amp;quot;Dano médio&amp;quot;,&lt;br /&gt;
        damagesAugmentation: &amp;quot;Aumento de dano&amp;quot;,&lt;br /&gt;
        bonusVariationTitle: [&amp;quot;Evolução do dano médio&amp;quot;, &amp;quot;relativo a um bónus&amp;quot;],&lt;br /&gt;
      },&lt;br /&gt;
      // es: {&lt;br /&gt;
      //   damages: &amp;quot;Daño&amp;quot;,&lt;br /&gt;
      //   percentage: &amp;quot;Porcentaje&amp;quot;,&lt;br /&gt;
      //   miss: &amp;quot;Miss&amp;quot;,&lt;br /&gt;
      //   normalHit: &amp;quot;Daño normal&amp;quot;,&lt;br /&gt;
      //   criticalHit: &amp;quot;Daño crítico&amp;quot;,&lt;br /&gt;
      //   piercingHit: &amp;quot;Daño perforante&amp;quot;,&lt;br /&gt;
      //   criticalPiercingHit: &amp;quot;Daño crítico perforante&amp;quot;,&lt;br /&gt;
      //   damagesRepartition: &amp;quot;Repartición de daños&amp;quot;,&lt;br /&gt;
      //   averageDamages: &amp;quot;Daño medio&amp;quot;,&lt;br /&gt;
      //   damagesAugmentation: &amp;quot;Aumento de daño&amp;quot;,&lt;br /&gt;
      //   bonusVariationTitle: [&amp;quot;Evolución del daño medio&amp;quot;, &amp;quot;Relativo a una bonificación&amp;quot;]&lt;br /&gt;
      // },&lt;br /&gt;
    },&lt;br /&gt;
  };&lt;br /&gt;
  return constants;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initResultTableHistory(battle) {&lt;br /&gt;
  var {&lt;br /&gt;
    tableResultHistory,&lt;br /&gt;
    savedFights,&lt;br /&gt;
    deleteFightTemplate,&lt;br /&gt;
    numberFormats: { default: numberFormat },&lt;br /&gt;
  } = battle;&lt;br /&gt;
  var startIndex = 3;&lt;br /&gt;
&lt;br /&gt;
  if (savedFights.length) {&lt;br /&gt;
    hideElement(tableResultHistory.rows[1]);&lt;br /&gt;
&lt;br /&gt;
    for (var savedFight of savedFights) {&lt;br /&gt;
      addRowToTableResultHistory(&lt;br /&gt;
        tableResultHistory,&lt;br /&gt;
        savedFight,&lt;br /&gt;
        deleteFightTemplate,&lt;br /&gt;
        numberFormat&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  tableResultHistory.addEventListener(&amp;quot;click&amp;quot;, function (event) {&lt;br /&gt;
    var deleteButton = event.target.closest(&amp;quot;.svg-icon-delete&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (deleteButton) {&lt;br /&gt;
      var row = deleteButton.closest(&amp;quot;tr&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
      if (row) {&lt;br /&gt;
        savedFights.splice(row.rowIndex - startIndex, 1);&lt;br /&gt;
        updateSavedFights(savedFights);&lt;br /&gt;
&lt;br /&gt;
        row.remove();&lt;br /&gt;
&lt;br /&gt;
        if (tableResultHistory.rows.length === startIndex) {&lt;br /&gt;
          showElement(tableResultHistory.rows[1]);&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initDamagesChart(battle) {&lt;br /&gt;
  var { translation, reduceChartPointsContainer, reduceChartPoints } = battle;&lt;br /&gt;
  var percentFormat = battle.numberFormats.percent;&lt;br /&gt;
  var customPlugins = {&lt;br /&gt;
    id: &amp;quot;customPlugins&amp;quot;,&lt;br /&gt;
    afterDraw(chart) {&lt;br /&gt;
      var missPercentage = chart.data.missPercentage;&lt;br /&gt;
&lt;br /&gt;
      if (!missPercentage) {&lt;br /&gt;
        return;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      var {&lt;br /&gt;
        ctx,&lt;br /&gt;
        chartArea: { top, right },&lt;br /&gt;
      } = chart;&lt;br /&gt;
      ctx.save();&lt;br /&gt;
      var text =&lt;br /&gt;
        translation.miss + &amp;quot; : &amp;quot; + percentFormat.format(missPercentage);&lt;br /&gt;
      var padding = 4;&lt;br /&gt;
      var fontSize = 14;&lt;br /&gt;
&lt;br /&gt;
      ctx.font = fontSize + &amp;quot;px Helvetica Neue&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
      var textWidth = ctx.measureText(text).width;&lt;br /&gt;
      var xPosition = right - textWidth - 5;&lt;br /&gt;
      var yPosition = top + 5;&lt;br /&gt;
&lt;br /&gt;
      ctx.fillStyle = &amp;quot;rgba(255, 0, 0, 0.2)&amp;quot;;&lt;br /&gt;
      ctx.fillRect(&lt;br /&gt;
        xPosition - padding,&lt;br /&gt;
        yPosition - padding,&lt;br /&gt;
        textWidth + 2 * padding,&lt;br /&gt;
        fontSize + 2 * padding&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      ctx.strokeStyle = &amp;quot;red&amp;quot;;&lt;br /&gt;
      ctx.strokeRect(&lt;br /&gt;
        xPosition - padding,&lt;br /&gt;
        yPosition - padding,&lt;br /&gt;
        textWidth + 2 * padding,&lt;br /&gt;
        fontSize + 2 * padding&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      ctx.fillStyle = &amp;quot;#666&amp;quot;;&lt;br /&gt;
      ctx.textBaseline = &amp;quot;top&amp;quot;;&lt;br /&gt;
      ctx.fillText(text, xPosition, yPosition + 1);&lt;br /&gt;
&lt;br /&gt;
      ctx.restore();&lt;br /&gt;
    },&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  Chart.register(customPlugins);&lt;br /&gt;
&lt;br /&gt;
  var ctx = battle.plotDamages.getContext(&amp;quot;2d&amp;quot;);&lt;br /&gt;
  var maxLabelsInTooltip = 10;&lt;br /&gt;
  var nullLabelText = &amp;quot; ...&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  var chart = new Chart(ctx, {&lt;br /&gt;
    type: &amp;quot;scatter&amp;quot;,&lt;br /&gt;
    data: {&lt;br /&gt;
      missPercentage: 0,&lt;br /&gt;
      datasets: [],&lt;br /&gt;
    },&lt;br /&gt;
    options: {&lt;br /&gt;
      responsive: true,&lt;br /&gt;
      maintainAspectRatio: false,&lt;br /&gt;
      plugins: {&lt;br /&gt;
        legend: {&lt;br /&gt;
          display: true,&lt;br /&gt;
          onHover: function (e) {&lt;br /&gt;
            e.native.target.style.cursor = &amp;quot;pointer&amp;quot;;&lt;br /&gt;
          },&lt;br /&gt;
          onLeave: function (e) {&lt;br /&gt;
            e.native.target.style.cursor = &amp;quot;default&amp;quot;;&lt;br /&gt;
          },&lt;br /&gt;
          onClick: function (e, legendItem, legend) {&lt;br /&gt;
            var currentIndex = legendItem.datasetIndex;&lt;br /&gt;
            var ci = legend.chart;&lt;br /&gt;
            var isCurrentDatasetVisible = ci.isDatasetVisible(currentIndex);&lt;br /&gt;
            var datasets = ci.data.datasets;&lt;br /&gt;
            var hideReducePoints = true;&lt;br /&gt;
            var isReducePointsChecked = reduceChartPoints.checked;&lt;br /&gt;
&lt;br /&gt;
            datasets[currentIndex].hidden = isCurrentDatasetVisible;&lt;br /&gt;
            legendItem.hidden = isCurrentDatasetVisible;&lt;br /&gt;
&lt;br /&gt;
            for (var index in datasets) {&lt;br /&gt;
              if (ci.isDatasetVisible(index) &amp;amp;&amp;amp; datasets[index].canBeReduced) {&lt;br /&gt;
                showElement(reduceChartPointsContainer);&lt;br /&gt;
                hideReducePoints = false;&lt;br /&gt;
                break;&lt;br /&gt;
              }&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            if (hideReducePoints) {&lt;br /&gt;
              hideElement(reduceChartPointsContainer);&lt;br /&gt;
              handleChartAnimations(ci, true);&lt;br /&gt;
            } else {&lt;br /&gt;
              handleChartAnimations(ci, isReducePointsChecked);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            ci.update();&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        title: {&lt;br /&gt;
          display: true,&lt;br /&gt;
          text: translation.damagesRepartition,&lt;br /&gt;
          font: {&lt;br /&gt;
            size: 20,&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        tooltip: {&lt;br /&gt;
          callbacks: {&lt;br /&gt;
            label: function (context) {&lt;br /&gt;
              if (context.label === null) {&lt;br /&gt;
                return nullLabelText;&lt;br /&gt;
              }&lt;br /&gt;
&lt;br /&gt;
              var xValue = battle.numberFormats.default.format(&lt;br /&gt;
                context.parsed.x&lt;br /&gt;
              );&lt;br /&gt;
              var yValue = battle.numberFormats.percent.format(&lt;br /&gt;
                context.parsed.y&lt;br /&gt;
              );&lt;br /&gt;
&lt;br /&gt;
              label =&lt;br /&gt;
                &amp;quot; &amp;quot; +&lt;br /&gt;
                context.dataset.label +&lt;br /&gt;
                &amp;quot; : (&amp;quot; +&lt;br /&gt;
                xValue +&lt;br /&gt;
                &amp;quot;, &amp;quot; +&lt;br /&gt;
                yValue +&lt;br /&gt;
                &amp;quot;)&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
              return label;&lt;br /&gt;
            },&lt;br /&gt;
            beforeBody: function (tooltipItems) {&lt;br /&gt;
              if (tooltipItems.length &amp;gt; maxLabelsInTooltip + 1) {&lt;br /&gt;
                tooltipItems.splice(maxLabelsInTooltip + 1);&lt;br /&gt;
                tooltipItems[maxLabelsInTooltip].label = null;&lt;br /&gt;
              }&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          caretPadding: 10,&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
      scales: {&lt;br /&gt;
        x: {&lt;br /&gt;
          type: &amp;quot;linear&amp;quot;,&lt;br /&gt;
          position: &amp;quot;bottom&amp;quot;,&lt;br /&gt;
          title: {&lt;br /&gt;
            display: true,&lt;br /&gt;
            text: translation.damages,&lt;br /&gt;
            font: {&lt;br /&gt;
              size: 16,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        y: {&lt;br /&gt;
          title: {&lt;br /&gt;
            display: true,&lt;br /&gt;
            text: translation.percentage,&lt;br /&gt;
            font: {&lt;br /&gt;
              size: 16,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          ticks: {&lt;br /&gt;
            format: {&lt;br /&gt;
              style: &amp;quot;percent&amp;quot;,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
      elements: {&lt;br /&gt;
        point: {&lt;br /&gt;
          borderWidth: 1,&lt;br /&gt;
          radius: 3,&lt;br /&gt;
          hitRadius: 3,&lt;br /&gt;
          hoverRadius: 6,&lt;br /&gt;
          hoverBorderWidth: 2,&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
    },&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  var datasetsStyle = [&lt;br /&gt;
    {&lt;br /&gt;
      name: &amp;quot;normalHit&amp;quot;,&lt;br /&gt;
      canBeReduced: false,&lt;br /&gt;
      label: translation.normalHit,&lt;br /&gt;
      backgroundColor: &amp;quot;rgba(75, 192, 192, 0.2)&amp;quot;,&lt;br /&gt;
      borderColor: &amp;quot;rgba(75, 192, 192, 1)&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      name: &amp;quot;piercingHit&amp;quot;,&lt;br /&gt;
      canBeReduced: false,&lt;br /&gt;
      label: translation.piercingHit,&lt;br /&gt;
      backgroundColor: &amp;quot;rgba(192, 192, 75, 0.2)&amp;quot;,&lt;br /&gt;
      borderColor: &amp;quot;rgba(192, 192, 75, 1)&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      name: &amp;quot;criticalHit&amp;quot;,&lt;br /&gt;
      canBeReduced: false,&lt;br /&gt;
      label: translation.criticalHit,&lt;br /&gt;
      backgroundColor: &amp;quot;rgba(192, 75, 192, 0.2)&amp;quot;,&lt;br /&gt;
      borderColor: &amp;quot;rgba(192, 75, 192, 1)&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      name: &amp;quot;criticalPiercingHit&amp;quot;,&lt;br /&gt;
      canBeReduced: false,&lt;br /&gt;
      label: translation.criticalPiercingHit,&lt;br /&gt;
      backgroundColor: &amp;quot;rgba(75, 75, 192, 0.2)&amp;quot;,&lt;br /&gt;
      borderColor: &amp;quot;rgba(75, 75, 192, 1)&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
  ];&lt;br /&gt;
  battle.damagesChart = {&lt;br /&gt;
    chart: chart,&lt;br /&gt;
    datasetsStyle: datasetsStyle,&lt;br /&gt;
    maxPoints: 500,&lt;br /&gt;
    reduceChartPointsContainer: reduceChartPointsContainer,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initBonusVariationChart(battle) {&lt;br /&gt;
  var translation = battle.translation;&lt;br /&gt;
&lt;br /&gt;
  var ctx = battle.plotBonusVariation.getContext(&amp;quot;2d&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  var chart = new Chart(ctx, {&lt;br /&gt;
    type: &amp;quot;line&amp;quot;,&lt;br /&gt;
    data: {&lt;br /&gt;
      datasets: [&lt;br /&gt;
        {&lt;br /&gt;
          label: translation.averageDamages,&lt;br /&gt;
          backgroundColor: &amp;quot;rgba(75, 192, 192, 0.2)&amp;quot;,&lt;br /&gt;
          borderColor: &amp;quot;rgba(75, 192, 192, 1)&amp;quot;,&lt;br /&gt;
          fill: true,&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          label: translation.damagesAugmentation,&lt;br /&gt;
          backgroundColor: &amp;quot;rgba(192, 192, 75, 0.2)&amp;quot;,&lt;br /&gt;
          borderColor: &amp;quot;rgba(192, 192, 75, 1)&amp;quot;,&lt;br /&gt;
          hidden: true,&lt;br /&gt;
          yTicksFormat: { style: &amp;quot;percent&amp;quot; },&lt;br /&gt;
          fill: true,&lt;br /&gt;
        },&lt;br /&gt;
      ],&lt;br /&gt;
    },&lt;br /&gt;
    options: {&lt;br /&gt;
      responsive: true,&lt;br /&gt;
      maintainAspectRatio: false,&lt;br /&gt;
      plugins: {&lt;br /&gt;
        legend: {&lt;br /&gt;
          display: true,&lt;br /&gt;
          onHover: function (e) {&lt;br /&gt;
            e.native.target.style.cursor = &amp;quot;pointer&amp;quot;;&lt;br /&gt;
          },&lt;br /&gt;
          onLeave: function (e) {&lt;br /&gt;
            e.native.target.style.cursor = &amp;quot;default&amp;quot;;&lt;br /&gt;
          },&lt;br /&gt;
          onClick: function (e, legendItem, legend) {&lt;br /&gt;
            var currentIndex = legendItem.datasetIndex;&lt;br /&gt;
            var ci = legend.chart;&lt;br /&gt;
            var datasets = ci.data.datasets;&lt;br /&gt;
            var isCurrentDatasetVisible = ci.isDatasetVisible(currentIndex);&lt;br /&gt;
            var yAxis = ci.options.scales.y;&lt;br /&gt;
&lt;br /&gt;
            var otherIndex = currentIndex === 0 ? 1 : 0;&lt;br /&gt;
            var visibleDataset = isCurrentDatasetVisible&lt;br /&gt;
              ? datasets[otherIndex]&lt;br /&gt;
              : datasets[currentIndex];&lt;br /&gt;
&lt;br /&gt;
            datasets[currentIndex].hidden = isCurrentDatasetVisible;&lt;br /&gt;
            datasets[otherIndex].hidden = !isCurrentDatasetVisible;&lt;br /&gt;
&lt;br /&gt;
            yAxis.title.text = visibleDataset.label;&lt;br /&gt;
            yAxis.ticks.format = visibleDataset.yTicksFormat;&lt;br /&gt;
&lt;br /&gt;
            ci.update();&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        title: {&lt;br /&gt;
          display: true,&lt;br /&gt;
          text: translation.bonusVariationTitle,&lt;br /&gt;
          font: {&lt;br /&gt;
            size: 18,&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        tooltip: {&lt;br /&gt;
          caretPadding: 10,&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
      scales: {&lt;br /&gt;
        x: {&lt;br /&gt;
          type: &amp;quot;linear&amp;quot;,&lt;br /&gt;
          position: &amp;quot;bottom&amp;quot;,&lt;br /&gt;
          title: {&lt;br /&gt;
            display: true,&lt;br /&gt;
            text: &amp;quot;Bonus&amp;quot;,&lt;br /&gt;
            font: {&lt;br /&gt;
              size: 16,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          ticks: {&lt;br /&gt;
            callback: function (value) {&lt;br /&gt;
              if (Number.isInteger(value)) {&lt;br /&gt;
                return Number(value);&lt;br /&gt;
              }&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        y: {&lt;br /&gt;
          title: {&lt;br /&gt;
            display: true,&lt;br /&gt;
            text: translation.averageDamages,&lt;br /&gt;
            font: {&lt;br /&gt;
              size: 16,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
      elements: {&lt;br /&gt;
        point: {&lt;br /&gt;
          borderWidth: 1,&lt;br /&gt;
          radius: 3,&lt;br /&gt;
          hitRadius: 3,&lt;br /&gt;
          hoverRadius: 6,&lt;br /&gt;
          hoverBorderWidth: 2,&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
    },&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  battle.bonusVariationChart = chart;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function attackSelectonListener(&lt;br /&gt;
  characters,&lt;br /&gt;
  attackerSelection,&lt;br /&gt;
  attackTypeSelection&lt;br /&gt;
) {&lt;br /&gt;
  attackerSelection.addEventListener(&amp;quot;change&amp;quot;, function (event) {&lt;br /&gt;
    var attackerName = event.target.value;&lt;br /&gt;
&lt;br /&gt;
    if (isPseudoSaved(characters, attackerName)) {&lt;br /&gt;
      var attacker = characters.savedCharacters[attackerName];&lt;br /&gt;
      filterAttackTypeSelection(attacker, attackTypeSelection);&lt;br /&gt;
    } else {&lt;br /&gt;
      filterAttackTypeSelectionMonster(attackTypeSelection);&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getTranslation(translation) {&lt;br /&gt;
  var userLanguage = navigator.language;&lt;br /&gt;
  var langToUse = &amp;quot;en&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  for (var lang in translation) {&lt;br /&gt;
    if (userLanguage.startsWith(lang)) {&lt;br /&gt;
      langToUse = lang;&lt;br /&gt;
      break;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return translation[langToUse];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createDamageCalculatorInformation(chartSource) {&lt;br /&gt;
  var characters = {&lt;br /&gt;
    unsavedChanges: false,&lt;br /&gt;
    savedCharacters: {},&lt;br /&gt;
    currentCharacter: null,&lt;br /&gt;
    savedMonsters: getSavedMonsters(),&lt;br /&gt;
    characterCreation: document.getElementById(&amp;quot;character-creation&amp;quot;),&lt;br /&gt;
    addNewCharacterButton: document.getElementById(&amp;quot;add-new-character&amp;quot;),&lt;br /&gt;
    dropZone: document.getElementById(&amp;quot;character-drop-zone&amp;quot;),&lt;br /&gt;
    characterInput: document.getElementById(&amp;quot;character-input&amp;quot;),&lt;br /&gt;
    newCharacterTemplate: document.getElementById(&amp;quot;new-character-template&amp;quot;)&lt;br /&gt;
      .children[0],&lt;br /&gt;
    charactersContainer: document.getElementById(&amp;quot;characters-container&amp;quot;),&lt;br /&gt;
    monsterButtonTemplates: document.getElementById(&amp;quot;monster-button-templates&amp;quot;),&lt;br /&gt;
    monsterTemplate: document.getElementById(&amp;quot;new-monster-template&amp;quot;)&lt;br /&gt;
      .children[0],&lt;br /&gt;
    monstersContainer: document.getElementById(&amp;quot;monsters-container&amp;quot;),&lt;br /&gt;
    monsteriFrame: document.getElementById(&amp;quot;monster-iframe&amp;quot;),&lt;br /&gt;
    stoneiFrame: document.getElementById(&amp;quot;stone-iframe&amp;quot;),&lt;br /&gt;
    saveButton: document.getElementById(&amp;quot;save-character&amp;quot;),&lt;br /&gt;
    weaponCategory: document.getElementById(&amp;quot;weapon-category&amp;quot;),&lt;br /&gt;
    weaponDisplay: document.getElementById(&amp;quot;weapon-display&amp;quot;),&lt;br /&gt;
    randomAttackValue: document.getElementById(&amp;quot;random-attack-value&amp;quot;),&lt;br /&gt;
    randomMagicAttackValue: document.getElementById(&lt;br /&gt;
      &amp;quot;random-magic-attack-value&amp;quot;&lt;br /&gt;
    ),&lt;br /&gt;
    yoharaCreation: document.getElementById(&amp;quot;yohara-creation&amp;quot;),&lt;br /&gt;
    blessingCreation: document.getElementById(&amp;quot;blessing-creation&amp;quot;),&lt;br /&gt;
    marriageCreation: document.getElementById(&amp;quot;marriage-creation&amp;quot;),&lt;br /&gt;
    bonusVariation: {&lt;br /&gt;
      tab: document.getElementById(&amp;quot;Variation&amp;quot;),&lt;br /&gt;
      activation: document.getElementById(&amp;quot;bonus-variation-activation&amp;quot;),&lt;br /&gt;
      input: document.getElementById(&amp;quot;bonus-variation&amp;quot;),&lt;br /&gt;
      inputDisplay: document.getElementById(&amp;quot;bonus-variation-display&amp;quot;),&lt;br /&gt;
      container: document.getElementById(&amp;quot;bonus-variation-range&amp;quot;),&lt;br /&gt;
      minValue: document.getElementById(&amp;quot;bonus-variation-min-value&amp;quot;),&lt;br /&gt;
      maxValue: document.getElementById(&amp;quot;bonus-variation-max-value&amp;quot;),&lt;br /&gt;
    },&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  characters.bonusVariation.inputDisplay.setAttribute(&amp;quot;readonly&amp;quot;, &amp;quot;&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  for (var [pseudo, character] of Object.entries(getSavedCharacters())) {&lt;br /&gt;
    characters.savedCharacters[pseudo] = character;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var skillContainer = document.getElementById(&amp;quot;skill-container&amp;quot;);&lt;br /&gt;
  characters.skillElementsToFilter =&lt;br /&gt;
    skillContainer.querySelectorAll(&amp;quot;[data-class]&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  var mapping = createMapping();&lt;br /&gt;
  var constants = createConstants();&lt;br /&gt;
&lt;br /&gt;
  var battle = {&lt;br /&gt;
    resetAttackType: false,&lt;br /&gt;
    savedFights: getSavedFights(),&lt;br /&gt;
    battleForm: document.getElementById(&amp;quot;create-battle&amp;quot;),&lt;br /&gt;
    attackerSelection: document.getElementById(&amp;quot;attacker-selection&amp;quot;),&lt;br /&gt;
    attackTypeSelection: document.getElementById(&amp;quot;attack-type-selection&amp;quot;),&lt;br /&gt;
    victimSelection: document.getElementById(&amp;quot;victim-selection&amp;quot;),&lt;br /&gt;
    damagesWeightedByType: {},&lt;br /&gt;
    scatterDataByType: {},&lt;br /&gt;
    damagesByBonus: [],&lt;br /&gt;
    tableResultFight: document.getElementById(&amp;quot;result-table-fight&amp;quot;),&lt;br /&gt;
    tableResultHistory: document.getElementById(&amp;quot;result-table-history&amp;quot;),&lt;br /&gt;
    deleteFightTemplate: document.getElementById(&amp;quot;delete-fight-template&amp;quot;)&lt;br /&gt;
      .children[0],&lt;br /&gt;
    errorInformation: {},&lt;br /&gt;
    fightResultContainer: document.getElementById(&amp;quot;fight-result-container&amp;quot;),&lt;br /&gt;
    downLoadRawData: document.getElementById(&amp;quot;download-raw-data&amp;quot;),&lt;br /&gt;
    downLoadRawDataVariation: document.getElementById(&lt;br /&gt;
      &amp;quot;download-raw-data-variation&amp;quot;&lt;br /&gt;
    ),&lt;br /&gt;
    bonusVariationResultContainer: document.getElementById(&lt;br /&gt;
      &amp;quot;bonus-variation-result-container&amp;quot;&lt;br /&gt;
    ),&lt;br /&gt;
    reduceChartPointsContainer: document.getElementById(&lt;br /&gt;
      &amp;quot;reduce-chart-points-container&amp;quot;&lt;br /&gt;
    ),&lt;br /&gt;
    reduceChartPoints: document.getElementById(&amp;quot;reduce-chart-points&amp;quot;),&lt;br /&gt;
    plotDamages: document.getElementById(&amp;quot;plot-damages&amp;quot;),&lt;br /&gt;
    plotBonusVariation: document.getElementById(&amp;quot;plot-bonus-variation&amp;quot;),&lt;br /&gt;
    uniqueDamagesCounters: document.querySelectorAll(&amp;quot;.unique-damages-counter&amp;quot;),&lt;br /&gt;
    possibleDamagesCounter: document.getElementById(&amp;quot;possible-damages-counter&amp;quot;),&lt;br /&gt;
    damagesTime: document.getElementById(&amp;quot;damages-time&amp;quot;),&lt;br /&gt;
    displayTime: document.getElementById(&amp;quot;display-time&amp;quot;),&lt;br /&gt;
    simulationCounter: document.getElementById(&amp;quot;simulation-counter&amp;quot;),&lt;br /&gt;
    simulationTime: document.getElementById(&amp;quot;simulation-time&amp;quot;),&lt;br /&gt;
    numberFormats: {&lt;br /&gt;
      default: new Intl.NumberFormat(undefined, {&lt;br /&gt;
        minimumFractionDigits: 0,&lt;br /&gt;
        maximumFractionDigits: 1,&lt;br /&gt;
      }),&lt;br /&gt;
      percent: new Intl.NumberFormat(undefined, {&lt;br /&gt;
        style: &amp;quot;percent&amp;quot;,&lt;br /&gt;
        maximumFractionDigits: 3,&lt;br /&gt;
      }),&lt;br /&gt;
      second: new Intl.NumberFormat(undefined, {&lt;br /&gt;
        style: &amp;quot;unit&amp;quot;,&lt;br /&gt;
        unit: &amp;quot;second&amp;quot;,&lt;br /&gt;
        unitDisplay: &amp;quot;long&amp;quot;,&lt;br /&gt;
        maximumFractionDigits: 3,&lt;br /&gt;
      }),&lt;br /&gt;
    },&lt;br /&gt;
    mapping: mapping,&lt;br /&gt;
    constants: constants,&lt;br /&gt;
    translation: getTranslation(constants.translation),&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  attackSelectonListener(&lt;br /&gt;
    characters,&lt;br /&gt;
    battle.attackerSelection,&lt;br /&gt;
    battle.attackTypeSelection&lt;br /&gt;
  );&lt;br /&gt;
  initResultTableHistory(battle);&lt;br /&gt;
  addScript(chartSource, function () {&lt;br /&gt;
    initDamagesChart(battle);&lt;br /&gt;
    initBonusVariationChart(battle);&lt;br /&gt;
  });&lt;br /&gt;
  reduceChartPointsListener(battle);&lt;br /&gt;
  downloadRawDataListener(battle);&lt;br /&gt;
&lt;br /&gt;
  var errorElements = document.querySelectorAll(&amp;quot;[data-error]&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; errorElements.length; index++) {&lt;br /&gt;
    var errorElement = errorElements[index];&lt;br /&gt;
    battle.errorInformation[errorElement.dataset.error] = errorElement;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return [characters, battle];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadStyle(src) {&lt;br /&gt;
  var link = document.createElement(&amp;quot;link&amp;quot;);&lt;br /&gt;
  link.href = src;&lt;br /&gt;
  link.rel = &amp;quot;stylesheet&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  document.head.appendChild(link);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
(function () {&lt;br /&gt;
  var javascriptSource =&lt;br /&gt;
    &amp;quot;/index.php?title=Utilisateur:Ankhseram/Calculator.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&amp;quot;;&lt;br /&gt;
  var cssSource =&lt;br /&gt;
    &amp;quot;/index.php?title=Utilisateur:Ankhseram/Style.css&amp;amp;action=raw&amp;amp;ctype=text/css&amp;quot;;&lt;br /&gt;
  var chartSource = &amp;quot;https://cdn.jsdelivr.net/npm/chart.js&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  loadStyle(cssSource);&lt;br /&gt;
&lt;br /&gt;
  function main() {&lt;br /&gt;
    var [characters, battle] = createDamageCalculatorInformation(chartSource);&lt;br /&gt;
&lt;br /&gt;
    characterManagement(characters, battle);&lt;br /&gt;
    monsterManagement(characters, battle);&lt;br /&gt;
&lt;br /&gt;
    updateBattleChoice(characters, battle);&lt;br /&gt;
    createBattle(characters, battle);&lt;br /&gt;
  }&lt;br /&gt;
  addScript(javascriptSource, main);&lt;br /&gt;
})();&lt;/div&gt;</summary>
		<author><name>Dexter</name></author>
		
	</entry>
	<entry>
		<id>https://fr-wiki.metin2.gameforge.com/index.php?title=Bug_et_probl%C3%A8mes_techniques&amp;diff=105759</id>
		<title>Bug et problèmes techniques</title>
		<link rel="alternate" type="text/html" href="https://fr-wiki.metin2.gameforge.com/index.php?title=Bug_et_probl%C3%A8mes_techniques&amp;diff=105759"/>
		<updated>2024-12-11T20:19:43Z</updated>

		<summary type="html">&lt;p&gt;Dexter : Page blanchie&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Dexter</name></author>
		
	</entry>
	<entry>
		<id>https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Script/Filter.js&amp;diff=105735</id>
		<title>MediaWiki:Script/Filter.js</title>
		<link rel="alternate" type="text/html" href="https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Script/Filter.js&amp;diff=105735"/>
		<updated>2024-12-11T07:32:24Z</updated>

		<summary type="html">&lt;p&gt;Dexter : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;function removeAccent(str) {&lt;br /&gt;
  return str&lt;br /&gt;
    .normalize(&amp;quot;NFD&amp;quot;)&lt;br /&gt;
    .replace(/[\u0300-\u036f]/g, &amp;quot;&amp;quot;)&lt;br /&gt;
    .toLowerCase();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function toNormalForm(str) {&lt;br /&gt;
  return removeAccent(str).replace(/[^a-zA-Z0-9 ]/g, &amp;quot;&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function editCardData(cardsData) {&lt;br /&gt;
  for (let cardIndex = 0; cardIndex &amp;lt; cardsData.length; cardIndex++) {&lt;br /&gt;
    const cardData = cardsData[cardIndex];&lt;br /&gt;
    const cardName = cardData.card.querySelector(&amp;quot;[data-name]&amp;quot;).textContent;&lt;br /&gt;
&lt;br /&gt;
    cardData.name = toNormalForm(cardName);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function observeLanguageChange(filterName, cardsData) {&lt;br /&gt;
  if (!filterName) {&lt;br /&gt;
    return;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  const observer = new MutationObserver(function (mutation) {&lt;br /&gt;
    editCardData(cardsData);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  observer.observe(filterName, { attributes: true });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function openFilter() {&lt;br /&gt;
  const filterButton = document.getElementById(&amp;quot;open-filter&amp;quot;);&lt;br /&gt;
  const filterDropdown = filterButton.nextElementSibling;&lt;br /&gt;
&lt;br /&gt;
  hideElement(filterDropdown);&lt;br /&gt;
&lt;br /&gt;
  filterButton.addEventListener(&amp;quot;click&amp;quot;, handleDropdown);&lt;br /&gt;
&lt;br /&gt;
  function handleDropdown() {&lt;br /&gt;
    toggleElement(filterDropdown);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  document.addEventListener(&amp;quot;mousedown&amp;quot;, function (event) {&lt;br /&gt;
    if (&lt;br /&gt;
      !filterButton.contains(event.target) &amp;amp;&amp;amp;&lt;br /&gt;
      !filterDropdown.contains(event.target)&lt;br /&gt;
    ) {&lt;br /&gt;
      hideElement(filterDropdown);&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function fillData(filter, filterData) {&lt;br /&gt;
  const { filter: category, value } = filter.dataset;&lt;br /&gt;
&lt;br /&gt;
  if (filter.type === &amp;quot;checkbox&amp;quot;) {&lt;br /&gt;
    const span = filter.parentElement.querySelector(&amp;quot;span.counter&amp;quot;);&lt;br /&gt;
    const filterInfo = { value: 0, span };&lt;br /&gt;
    const { checkbox } = filterData;&lt;br /&gt;
&lt;br /&gt;
    checkbox[category] = checkbox[category] || {};&lt;br /&gt;
    checkbox[category][value] = filterInfo;&lt;br /&gt;
  } else if (filter.type === &amp;quot;number&amp;quot;) {&lt;br /&gt;
    const { range } = filterData;&lt;br /&gt;
    if (range.hasOwnProperty(category)) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
    const init = { min: Number(filter.min), max: Number(filter.max) };&lt;br /&gt;
    range[category] = { init: init };&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function extractInitData(card, cardData) {&lt;br /&gt;
  const cardNameElement = card.querySelector(&amp;quot;[data-name]&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  cardData.card = card;&lt;br /&gt;
  cardData.name = toNormalForm(cardNameElement.textContent);&lt;br /&gt;
  cardData.trueName = cardNameElement.firstChild.title;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function extractLevelData(card, cardData) {&lt;br /&gt;
  const levelElement = card.querySelector(&amp;quot;[data-level]&amp;quot;);&lt;br /&gt;
  const [level, rank] = levelElement.textContent.slice(1, -1).split(&amp;quot;, &amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  cardData[&amp;quot;level&amp;quot;] = Number(level);&lt;br /&gt;
  cardData[&amp;quot;rank&amp;quot;] = removeAccent(rank);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function extractElementData(card, cardData) {&lt;br /&gt;
  const elementChild = card.querySelector(&amp;quot;[data-elem]&amp;quot;).children;&lt;br /&gt;
  let elementValue = &amp;quot;&amp;quot;;&lt;br /&gt;
  if (elementChild.length) {&lt;br /&gt;
    for (&lt;br /&gt;
      let elementIndex = 0;&lt;br /&gt;
      elementIndex &amp;lt; elementChild.length;&lt;br /&gt;
      elementIndex++&lt;br /&gt;
    ) {&lt;br /&gt;
      elementValue += elementChild[elementIndex].title + &amp;quot; &amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  elementValue = elementValue.trim() || &amp;quot;Aucun&amp;quot;;&lt;br /&gt;
  cardData.elem = removeAccent(elementValue);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function extractTypeData(card, cardData) {&lt;br /&gt;
  const typeElement = card.querySelector(&amp;quot;[data-type]&amp;quot;);&lt;br /&gt;
  cardData.type = removeAccent(typeElement.textContent.split(&amp;quot; &amp;quot;)[0]);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function extractDamageData(card, cardData) {&lt;br /&gt;
  const damageElement = card.querySelector(&amp;quot;[data-damage]&amp;quot;);&lt;br /&gt;
  cardData.damage = removeAccent(damageElement.textContent.replace(&amp;quot; + &amp;quot;, &amp;quot; &amp;quot;));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function extractLocData(card, cardData) {&lt;br /&gt;
  const locElement = card.querySelector(&amp;quot;[data-loc]&amp;quot;);&lt;br /&gt;
  cardData.loc = locElement.dataset.loc;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getCardsData(cardsContainer, filterData, dataExtractionMapping) {&lt;br /&gt;
  const cards = cardsContainer.children;&lt;br /&gt;
  const activeExtractors = [extractInitData];&lt;br /&gt;
&lt;br /&gt;
  for (const [key, extractorFunction] of Object.entries(&lt;br /&gt;
    dataExtractionMapping&lt;br /&gt;
  )) {&lt;br /&gt;
    if (&lt;br /&gt;
      filterData.range.hasOwnProperty(key) ||&lt;br /&gt;
      filterData.checkbox.hasOwnProperty(key)&lt;br /&gt;
    ) {&lt;br /&gt;
      activeExtractors.push(extractorFunction);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  const cardsData = [];&lt;br /&gt;
&lt;br /&gt;
  for (let cardIndex = 0; cardIndex &amp;lt; cards.length; cardIndex++) {&lt;br /&gt;
    const card = cards[cardIndex];&lt;br /&gt;
    const cardData = {};&lt;br /&gt;
&lt;br /&gt;
    for (const extractor of activeExtractors) {&lt;br /&gt;
      extractor(card, cardData);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    cardsData.push(cardData);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return cardsData;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterInitialization(filterForm) {&lt;br /&gt;
  const filterData = {&lt;br /&gt;
    form: filterForm,&lt;br /&gt;
    filters: { filterName: &amp;quot;&amp;quot;, filter: {}, rangeFilter: {} },&lt;br /&gt;
    range: {},&lt;br /&gt;
    checkbox: {},&lt;br /&gt;
    reverse: false,&lt;br /&gt;
  };&lt;br /&gt;
  const filters = filterForm.querySelectorAll(&amp;quot;[data-filter]&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  filters.forEach((filter) =&amp;gt; fillData(filter, filterData));&lt;br /&gt;
&lt;br /&gt;
  return filterData;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function displayCounterValue(checkbox) {&lt;br /&gt;
  for (let filterCategory in checkbox) {&lt;br /&gt;
    const category = checkbox[filterCategory];&lt;br /&gt;
&lt;br /&gt;
    for (let filterValue in category) {&lt;br /&gt;
      const valueData = category[filterValue];&lt;br /&gt;
&lt;br /&gt;
      valueData.span.textContent = &amp;quot; (&amp;quot; + valueData.value + &amp;quot;)&amp;quot;;&lt;br /&gt;
      valueData.value = 0;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateCounter(cardData, checkbox, filterCategory) {&lt;br /&gt;
  cardData[filterCategory].split(&amp;quot; &amp;quot;).forEach((cardValue) =&amp;gt; {&lt;br /&gt;
    checkbox[filterCategory][cardValue].value += 1;&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isObjectValuesInRangeFilter(parameters, rangeFilter) {&lt;br /&gt;
  return Object.entries(rangeFilter).every(&lt;br /&gt;
    ([property, { min, max }]) =&amp;gt;&lt;br /&gt;
      parameters[property] &amp;gt;= min &amp;amp;&amp;amp; parameters[property] &amp;lt;= max&lt;br /&gt;
  );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterByName(parameters, filterName) {&lt;br /&gt;
  if (filterName) {&lt;br /&gt;
    return parameters.name.includes(filterName);&lt;br /&gt;
  }&lt;br /&gt;
  return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isObjectValuesInFilter(parameters, filter) {&lt;br /&gt;
  return Object.entries(filter).every(([property, values]) =&amp;gt;&lt;br /&gt;
    parameters[property].split(&amp;quot; &amp;quot;).some((value) =&amp;gt; values.includes(value))&lt;br /&gt;
  );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isObjectValuesInFilters(parameters, filter, rangeFilter, filterName) {&lt;br /&gt;
  return (&lt;br /&gt;
    isObjectValuesInFilter(parameters, filter) &amp;amp;&amp;amp;&lt;br /&gt;
    filterByName(parameters, filterName) &amp;amp;&amp;amp;&lt;br /&gt;
    isObjectValuesInRangeFilter(parameters, rangeFilter)&lt;br /&gt;
  );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterCards(cardsContainer, filterData, cardsData) {&lt;br /&gt;
  const { filters, checkbox } = filterData;&lt;br /&gt;
  const { filter, rangeFilter, filterName } = filters;&lt;br /&gt;
&lt;br /&gt;
  if (filterData.reverse) {&lt;br /&gt;
    for (&lt;br /&gt;
      let reverseIndex = 1;&lt;br /&gt;
      reverseIndex &amp;lt; cardsData.length;&lt;br /&gt;
      reverseIndex++&lt;br /&gt;
    ) {&lt;br /&gt;
      cardsContainer.insertBefore(&lt;br /&gt;
        cardsData[reverseIndex].card,&lt;br /&gt;
        cardsContainer.firstChild&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
    cardsData.reverse();&lt;br /&gt;
    filterData.reverse = false;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (let cardIndex = 0; cardIndex &amp;lt; cardsData.length; cardIndex++) {&lt;br /&gt;
    const cardData = cardsData[cardIndex];&lt;br /&gt;
&lt;br /&gt;
    if (isObjectValuesInFilters(cardData, filter, rangeFilter, filterName)) {&lt;br /&gt;
      showElement(cardData.card);&lt;br /&gt;
      for (let filterCategory in checkbox) {&lt;br /&gt;
        updateCounter(cardData, checkbox, filterCategory);&lt;br /&gt;
      }&lt;br /&gt;
    } else {&lt;br /&gt;
      hideElement(cardData.card);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  displayCounterValue(checkbox);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleCheckbox(target, filter) {&lt;br /&gt;
  const { filter: category, value } = target.dataset;&lt;br /&gt;
&lt;br /&gt;
  if (target.checked) {&lt;br /&gt;
    filter[category] = filter[category] || [];&lt;br /&gt;
    filter[category].push(value);&lt;br /&gt;
  } else {&lt;br /&gt;
    const index = filter[category].indexOf(value);&lt;br /&gt;
    if (index !== -1) {&lt;br /&gt;
      filter[category].splice(index, 1);&lt;br /&gt;
    }&lt;br /&gt;
    if (!filter[category].length) {&lt;br /&gt;
      delete filter[category];&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleNumberType(target, rangeFilter, range) {&lt;br /&gt;
  const { filter: category, value: extremum } = target.dataset;&lt;br /&gt;
  const currentValue = Number(target.value);&lt;br /&gt;
  const initialRange = range[category].init;&lt;br /&gt;
&lt;br /&gt;
  if (rangeFilter[category]) {&lt;br /&gt;
    rangeFilter[category][extremum] = currentValue;&lt;br /&gt;
  } else {&lt;br /&gt;
    rangeFilter[category] = {&lt;br /&gt;
      min: initialRange.min,&lt;br /&gt;
      max: initialRange.max,&lt;br /&gt;
    };&lt;br /&gt;
    rangeFilter[category][extremum] = currentValue;&lt;br /&gt;
  }&lt;br /&gt;
  if (&lt;br /&gt;
    rangeFilter[category].max === initialRange.max &amp;amp;&amp;amp;&lt;br /&gt;
    rangeFilter[category].min === initialRange.min&lt;br /&gt;
  ) {&lt;br /&gt;
    delete rangeFilter[category];&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleFormEvents(cardsContainer, filterForm, filterData, cardsData) {&lt;br /&gt;
  const { filters, range } = filterData;&lt;br /&gt;
  let debounceTimer;&lt;br /&gt;
&lt;br /&gt;
  filterForm.addEventListener(&amp;quot;submit&amp;quot;, function (event) {&lt;br /&gt;
    event.preventDefault();&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  filterForm.addEventListener(&amp;quot;change&amp;quot;, updateFilter);&lt;br /&gt;
&lt;br /&gt;
  filterForm.addEventListener(&amp;quot;input&amp;quot;, function (event) {&lt;br /&gt;
    clearTimeout(debounceTimer);&lt;br /&gt;
    debounceTimer = setTimeout(() =&amp;gt; {&lt;br /&gt;
      if (event.target.id === &amp;quot;filter-name&amp;quot;) {&lt;br /&gt;
        updateFilter(event, true);&lt;br /&gt;
      }&lt;br /&gt;
    }, 500);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  function updateFilter(event, filterByName = false) {&lt;br /&gt;
    const target = event.target;&lt;br /&gt;
    const targetType = target.type;&lt;br /&gt;
&lt;br /&gt;
    if (filterByName) {&lt;br /&gt;
      filters.filterName = toNormalForm(target.value);&lt;br /&gt;
    } else if (targetType === &amp;quot;checkbox&amp;quot;) {&lt;br /&gt;
      handleCheckbox(target, filters.filter);&lt;br /&gt;
    } else if (targetType === &amp;quot;number&amp;quot;) {&lt;br /&gt;
      handleNumberType(target, filters.rangeFilter, range);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    filterCards(cardsContainer, filterData, cardsData);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function processUrlParameter(filterName, filterData, key, value) {&lt;br /&gt;
  const { filters } = filterData;&lt;br /&gt;
&lt;br /&gt;
  if (key === &amp;quot;name&amp;quot;) {&lt;br /&gt;
    filterName.value = toNormalForm(value);&lt;br /&gt;
    filters.filterName = value;&lt;br /&gt;
  } else if (Object.keys(filterData.checkbox).indexOf(key) !== -1) {&lt;br /&gt;
    const checkboxElement = document.getElementById(key + &amp;quot;-&amp;quot; + value);&lt;br /&gt;
&lt;br /&gt;
    if (!checkboxElement) return;&lt;br /&gt;
&lt;br /&gt;
    checkboxElement.checked = true;&lt;br /&gt;
    filters.filter[key] = filters.filter[key] || [];&lt;br /&gt;
    filters.filter[key].push(value);&lt;br /&gt;
  } else if (key === &amp;quot;reverse&amp;quot;) {&lt;br /&gt;
    if (value === &amp;quot;1&amp;quot;) {&lt;br /&gt;
      filterData.reverse = true;&lt;br /&gt;
      const reverseElement = document.getElementById(&amp;quot;filter-reverse&amp;quot;);&lt;br /&gt;
      if (reverseElement) {&lt;br /&gt;
        reverseElement.checked = true;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    const [splitKey, extremum] = key.split(&amp;quot;-&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (Object.keys(filterData.range).indexOf(splitKey) !== -1) {&lt;br /&gt;
      const rangeElement = document.getElementById(key);&lt;br /&gt;
&lt;br /&gt;
      if (!rangeElement) return;&lt;br /&gt;
&lt;br /&gt;
      rangeElement.value = value;&lt;br /&gt;
&lt;br /&gt;
      const rangeData = filterData.range[splitKey];&lt;br /&gt;
      const rangeFilter = filters.rangeFilter;&lt;br /&gt;
&lt;br /&gt;
      if (rangeFilter[splitKey]) {&lt;br /&gt;
        rangeFilter[splitKey][extremum] = value;&lt;br /&gt;
      } else {&lt;br /&gt;
        rangeFilter[splitKey] = {&lt;br /&gt;
          min: rangeData.init.min,&lt;br /&gt;
          max: rangeData.init.max,&lt;br /&gt;
        };&lt;br /&gt;
        rangeFilter[splitKey][extremum] = value;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterWithUrl(filterName, filterData) {&lt;br /&gt;
  const url = new URL(window.location.href);&lt;br /&gt;
  const { hash, search } = url;&lt;br /&gt;
  let useParams = true;&lt;br /&gt;
&lt;br /&gt;
  if (hash) {&lt;br /&gt;
    const start = &amp;quot;.3F&amp;quot;;&lt;br /&gt;
    const equal = &amp;quot;.3D&amp;quot;;&lt;br /&gt;
    const and = &amp;quot;.26&amp;quot;;&lt;br /&gt;
    const startParametersIndex = hash.indexOf(start);&lt;br /&gt;
&lt;br /&gt;
    if (startParametersIndex !== -1) {&lt;br /&gt;
      const parameters = hash.slice(startParametersIndex + start.length);&lt;br /&gt;
&lt;br /&gt;
      parameters.split(and).forEach(function (keyValue) {&lt;br /&gt;
        const [key, value] = keyValue.split(equal);&lt;br /&gt;
        processUrlParameter(filterName, filterData, key, value);&lt;br /&gt;
      });&lt;br /&gt;
&lt;br /&gt;
      useParams = false;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (useParams) {&lt;br /&gt;
    const URLparams = new URLSearchParams(search);&lt;br /&gt;
&lt;br /&gt;
    for (const [key, value] of URLparams.entries()) {&lt;br /&gt;
      processUrlParameter(filterName, filterData, key, value);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function main_filter() {&lt;br /&gt;
  const filterForm = document.getElementById(&amp;quot;filter-form&amp;quot;);&lt;br /&gt;
  const filterName = document.getElementById(&amp;quot;filter-name&amp;quot;);&lt;br /&gt;
  const cardsContainer = document.getElementById(&amp;quot;cards-container&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  const dataExtractionMapping = {&lt;br /&gt;
    level: extractLevelData,&lt;br /&gt;
    elem: extractElementData,&lt;br /&gt;
    type: extractTypeData,&lt;br /&gt;
    damage: extractDamageData,&lt;br /&gt;
    loc: extractLocData&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  const filterData = filterInitialization(filterForm);&lt;br /&gt;
  const cardsData = getCardsData(&lt;br /&gt;
    cardsContainer,&lt;br /&gt;
    filterData,&lt;br /&gt;
    dataExtractionMapping&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  observeLanguageChange(filterName, cardsData);&lt;br /&gt;
  openFilter();&lt;br /&gt;
  filterWithUrl(filterName, filterData);&lt;br /&gt;
  filterCards(cardsContainer, filterData, cardsData);&lt;br /&gt;
  handleFormEvents(cardsContainer, filterForm, filterData, cardsData);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
main_filter();&lt;/div&gt;</summary>
		<author><name>Dexter</name></author>
		
	</entry>
	<entry>
		<id>https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Script/Modal.js&amp;diff=105492</id>
		<title>MediaWiki:Script/Modal.js</title>
		<link rel="alternate" type="text/html" href="https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Script/Modal.js&amp;diff=105492"/>
		<updated>2024-12-06T07:11:16Z</updated>

		<summary type="html">&lt;p&gt;Dexter : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;mainModal();&lt;br /&gt;
&lt;br /&gt;
function mainModal() {&lt;br /&gt;
  const modalButtons = document.querySelectorAll(&amp;quot;.modal-trigger&amp;quot;);&lt;br /&gt;
  modalButtons.forEach(handleModal);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleModal(button) {&lt;br /&gt;
  const modalName = button.dataset.modal;&lt;br /&gt;
  let modalContainer;&lt;br /&gt;
&lt;br /&gt;
  if (modalName) {&lt;br /&gt;
    modalContainer = document.querySelector(&lt;br /&gt;
      `.modal[data-modal=&amp;quot;${modalName}&amp;quot;]`&lt;br /&gt;
    );&lt;br /&gt;
  } else {&lt;br /&gt;
    modalContainer = button.nextElementSibling;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  const closeButton = modalContainer.querySelector(&amp;quot;.close-button&amp;quot;);&lt;br /&gt;
  const autoClose = modalContainer.dataset.autoClose === &amp;quot;1&amp;quot;;&lt;br /&gt;
  const addEvent = modalContainer.dataset.addEvent === &amp;quot;1&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  button.addEventListener(&amp;quot;click&amp;quot;, openModal);&lt;br /&gt;
  closeButton.addEventListener(&amp;quot;click&amp;quot;, closeModal);&lt;br /&gt;
&lt;br /&gt;
  if (autoClose) {&lt;br /&gt;
    modalContainer.addEventListener(&amp;quot;change&amp;quot;, closeModal);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function openModal() {&lt;br /&gt;
    button.classList.add(&amp;quot;tabber-active&amp;quot;);&lt;br /&gt;
    modalContainer.classList.add(&amp;quot;show-modal&amp;quot;);&lt;br /&gt;
    window.addEventListener(&amp;quot;click&amp;quot;, handleClickOutside);&lt;br /&gt;
    window.addEventListener(&amp;quot;keydown&amp;quot;, handleEscape);&lt;br /&gt;
&lt;br /&gt;
    if (addEvent) {&lt;br /&gt;
      const modalOpenEvent = new CustomEvent('modalOpen', {&lt;br /&gt;
        bubbles: true,&lt;br /&gt;
        detail: { modal: modalContainer, name: modalName }&lt;br /&gt;
      });&lt;br /&gt;
      button.dispatchEvent(modalOpenEvent);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function closeModal() {&lt;br /&gt;
    button.classList.remove(&amp;quot;tabber-active&amp;quot;);&lt;br /&gt;
    modalContainer.classList.remove(&amp;quot;show-modal&amp;quot;);&lt;br /&gt;
    window.removeEventListener(&amp;quot;click&amp;quot;, handleClickOutside);&lt;br /&gt;
    window.removeEventListener(&amp;quot;keydown&amp;quot;, handleEscape);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function handleClickOutside(event) {&lt;br /&gt;
    if (event.target === modalContainer) {&lt;br /&gt;
      closeModal();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function handleEscape(event) {&lt;br /&gt;
    if (event.key === &amp;quot;Escape&amp;quot;) {&lt;br /&gt;
      closeModal();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;/div&gt;</summary>
		<author><name>Dexter</name></author>
		
	</entry>
	<entry>
		<id>https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Script/Calculator.js&amp;diff=105491</id>
		<title>MediaWiki:Script/Calculator.js</title>
		<link rel="alternate" type="text/html" href="https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Script/Calculator.js&amp;diff=105491"/>
		<updated>2024-12-06T07:10:17Z</updated>

		<summary type="html">&lt;p&gt;Dexter : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;function removeAccent(str) {&lt;br /&gt;
  return str.normalize(&amp;quot;NFD&amp;quot;).replace(/[\u0300-\u036f]/g, &amp;quot;&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function pseudoFormat(str) {&lt;br /&gt;
  return removeAccent(str).replace(/[^A-Za-z0-9 \(\)\+_-]+/g, &amp;quot;&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isValueInArray(value, array) {&lt;br /&gt;
  return array.indexOf(value) !== -1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function copyObject(object) {&lt;br /&gt;
  var copy = {};&lt;br /&gt;
  for (var key in object) {&lt;br /&gt;
    copy[key] = object[key];&lt;br /&gt;
  }&lt;br /&gt;
  return copy;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function compareNumbers(a, b) {&lt;br /&gt;
  return b - a;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isChecked(attribute) {&lt;br /&gt;
  return attribute === &amp;quot;on&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function floorMultiplication(firstFactor, secondFactor) {&lt;br /&gt;
  return Math.floor((firstFactor * secondFactor).toFixed(8));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function truncateNumber(number, precision) {&lt;br /&gt;
  return Math.floor(number * 10 ** precision) / 10 ** precision;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addKeyValue(object, key, value) {&lt;br /&gt;
  if (object.hasOwnProperty(key)) {&lt;br /&gt;
    object[key] += value;&lt;br /&gt;
  } else {&lt;br /&gt;
    object[key] = value;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function editTableResultRow(row, valuesToDisplay, numberFormat) {&lt;br /&gt;
  row.innerHTML = &amp;quot;&amp;quot;;&lt;br /&gt;
  for (var index = 0; index &amp;lt; valuesToDisplay.length; index++) {&lt;br /&gt;
    var cell = row.insertCell();&lt;br /&gt;
    var textContent;&lt;br /&gt;
&lt;br /&gt;
    if (index &amp;gt;= 3) {&lt;br /&gt;
      textContent = numberFormat.format(valuesToDisplay[index]);&lt;br /&gt;
    } else {&lt;br /&gt;
      textContent = valuesToDisplay[index];&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    cell.textContent = textContent;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return row;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addRowToTableResultHistory(&lt;br /&gt;
  tableResultHistory,&lt;br /&gt;
  valuesToDisplay,&lt;br /&gt;
  deleteFightTemplate,&lt;br /&gt;
  numberFormat&lt;br /&gt;
) {&lt;br /&gt;
  var row = tableResultHistory.insertRow();&lt;br /&gt;
  editTableResultRow(row, valuesToDisplay, numberFormat);&lt;br /&gt;
  var cell = row.insertCell();&lt;br /&gt;
  cell.appendChild(deleteFightTemplate.cloneNode(true));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcMeanDamages(damagesWeightedByType, totalCardinal) {&lt;br /&gt;
  var sumDamages = 0;&lt;br /&gt;
&lt;br /&gt;
  for (var damagesTypeName in damagesWeightedByType) {&lt;br /&gt;
    if (damagesTypeName === &amp;quot;miss&amp;quot;) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var damagesWeighted = damagesWeightedByType[damagesTypeName];&lt;br /&gt;
&lt;br /&gt;
    for (var damages in damagesWeighted) {&lt;br /&gt;
      sumDamages += damages * damagesWeighted[damages];&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return sumDamages / totalCardinal;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function prepareDamagesData(&lt;br /&gt;
  damagesWeightedByType,&lt;br /&gt;
  possibleDamagesCountTemp,&lt;br /&gt;
  totalCardinal&lt;br /&gt;
) {&lt;br /&gt;
  var minDamages = Infinity;&lt;br /&gt;
  var maxDamages = 0;&lt;br /&gt;
  var scatterDataByType = {};&lt;br /&gt;
  var sumDamages = 0;&lt;br /&gt;
  var possibleDamagesCount = 0;&lt;br /&gt;
  var uniqueDamagesCount = 0;&lt;br /&gt;
&lt;br /&gt;
  for (var damagesTypeName in damagesWeightedByType) {&lt;br /&gt;
    if (damagesTypeName === &amp;quot;miss&amp;quot;) {&lt;br /&gt;
      scatterDataByType.miss = damagesWeightedByType.miss;&lt;br /&gt;
      possibleDamagesCount++;&lt;br /&gt;
      uniqueDamagesCount++;&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var firstIteration = true;&lt;br /&gt;
    var damagesWeighted = damagesWeightedByType[damagesTypeName];&lt;br /&gt;
    var scatterData = [];&lt;br /&gt;
    scatterDataByType[damagesTypeName] = scatterData;&lt;br /&gt;
&lt;br /&gt;
    for (var damages in damagesWeighted) {&lt;br /&gt;
      damages = +damages;&lt;br /&gt;
&lt;br /&gt;
      if (firstIteration) {&lt;br /&gt;
        if (damages &amp;lt; minDamages) {&lt;br /&gt;
          minDamages = damages;&lt;br /&gt;
        }&lt;br /&gt;
        firstIteration = false;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      var weight = damagesWeighted[damages];&lt;br /&gt;
      var probability = weight / totalCardinal;&lt;br /&gt;
&lt;br /&gt;
      sumDamages += damages * weight;&lt;br /&gt;
      damagesWeighted[damages] = probability;&lt;br /&gt;
      scatterData.push({ x: damages, y: probability });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var scatterDataLength = scatterData.length;&lt;br /&gt;
&lt;br /&gt;
    possibleDamagesCount += possibleDamagesCountTemp;&lt;br /&gt;
    uniqueDamagesCount += scatterDataLength;&lt;br /&gt;
&lt;br /&gt;
    if (damages &amp;gt; maxDamages) {&lt;br /&gt;
      maxDamages = damages;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (minDamages === Infinity) {&lt;br /&gt;
    minDamages = 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return [&lt;br /&gt;
    sumDamages / totalCardinal,&lt;br /&gt;
    minDamages,&lt;br /&gt;
    maxDamages,&lt;br /&gt;
    scatterDataByType,&lt;br /&gt;
    possibleDamagesCount,&lt;br /&gt;
    uniqueDamagesCount,&lt;br /&gt;
  ];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function aggregateDamages(scatterData, maxPoints) {&lt;br /&gt;
  var dataLength = scatterData.length;&lt;br /&gt;
  var remainingData = dataLength;&lt;br /&gt;
  var aggregateScatterData = [];&lt;br /&gt;
&lt;br /&gt;
  for (var groupIndex = 0; groupIndex &amp;lt; maxPoints; groupIndex++) {&lt;br /&gt;
    var groupLength = Math.floor(remainingData / (maxPoints - groupIndex));&lt;br /&gt;
    var startIndex = dataLength - remainingData;&lt;br /&gt;
    var aggregateDamages = 0;&lt;br /&gt;
    var aggregateProbability = 0;&lt;br /&gt;
&lt;br /&gt;
    for (var index = startIndex; index &amp;lt; startIndex + groupLength; index++) {&lt;br /&gt;
      var { x: damages, y: probability } = scatterData[index];&lt;br /&gt;
      aggregateDamages += damages * probability;&lt;br /&gt;
      aggregateProbability += probability;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    aggregateScatterData.push({&lt;br /&gt;
      x: aggregateDamages / aggregateProbability,&lt;br /&gt;
      y: aggregateProbability,&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    remainingData -= groupLength;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return aggregateScatterData;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addToDamagesChart(&lt;br /&gt;
  scatterDataByType,&lt;br /&gt;
  damagesChart,&lt;br /&gt;
  isReducePointsChecked&lt;br /&gt;
) {&lt;br /&gt;
  var { chart, datasetsStyle, maxPoints, reduceChartPointsContainer } =&lt;br /&gt;
    damagesChart;&lt;br /&gt;
  var isFirstDataset = true;&lt;br /&gt;
  var datasets = chart.data.datasets;&lt;br /&gt;
&lt;br /&gt;
  datasets.length = 0;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; datasetsStyle.length; index++) {&lt;br /&gt;
    var dataset = copyObject(datasetsStyle[index]);&lt;br /&gt;
&lt;br /&gt;
    if (!scatterDataByType.hasOwnProperty(dataset.name)) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var scatterData = scatterDataByType[dataset.name];&lt;br /&gt;
    var canBeReduced = scatterData.length &amp;gt; 2 * maxPoints;&lt;br /&gt;
&lt;br /&gt;
    dataset.hidden = !isFirstDataset;&lt;br /&gt;
    dataset.canBeReduced = canBeReduced;&lt;br /&gt;
&lt;br /&gt;
    if (canBeReduced &amp;amp;&amp;amp; isReducePointsChecked) {&lt;br /&gt;
      dataset.data = aggregateDamages(scatterData, maxPoints);&lt;br /&gt;
    } else {&lt;br /&gt;
      dataset.data = scatterData;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isFirstDataset) {&lt;br /&gt;
      isFirstDataset = false;&lt;br /&gt;
&lt;br /&gt;
      if (canBeReduced) {&lt;br /&gt;
        showElement(reduceChartPointsContainer);&lt;br /&gt;
&lt;br /&gt;
        if (!isReducePointsChecked) {&lt;br /&gt;
          handleChartAnimations(chart, false);&lt;br /&gt;
        }&lt;br /&gt;
      } else {&lt;br /&gt;
        hideElement(reduceChartPointsContainer);&lt;br /&gt;
        handleChartAnimations(chart, true);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    datasets.push(dataset);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  chart.data.missPercentage = scatterDataByType.miss;&lt;br /&gt;
  chart.update();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addToBonusVariationChart(&lt;br /&gt;
  damagesByBonus,&lt;br /&gt;
  augmentationByBonus,&lt;br /&gt;
  xLabel,&lt;br /&gt;
  chart&lt;br /&gt;
) {&lt;br /&gt;
  chart.data.datasets[0].data = damagesByBonus;&lt;br /&gt;
  chart.data.datasets[1].data = augmentationByBonus;&lt;br /&gt;
  chart.options.scales.x.title.text = xLabel;&lt;br /&gt;
  chart.update();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleChartAnimations(chart, addAnimations) {&lt;br /&gt;
  chart.options.animation = addAnimations;&lt;br /&gt;
  chart.options.animations.colors = addAnimations;&lt;br /&gt;
  chart.options.animations.x = addAnimations;&lt;br /&gt;
  chart.options.transitions.active.animation.duration = addAnimations * 1000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateDamagesChartDescription(&lt;br /&gt;
  uniqueDamagesCounters,&lt;br /&gt;
  uniqueDamagesCount,&lt;br /&gt;
  formatNumber&lt;br /&gt;
) {&lt;br /&gt;
  uniqueDamagesCounters.forEach(function (element) {&lt;br /&gt;
    if (uniqueDamagesCount &amp;lt;= 1) {&lt;br /&gt;
      hideElement(element.parentElement);&lt;br /&gt;
    } else {&lt;br /&gt;
      showElement(element.parentElement);&lt;br /&gt;
      element.textContent = formatNumber.format(uniqueDamagesCount);&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getMonsterName(monsterVnum) {&lt;br /&gt;
  var monsterAttributes = monsterData[monsterVnum];&lt;br /&gt;
  return monsterAttributes[monsterAttributes.length - 1];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterClass(selectedRace, classChoice, selectValueIsChanged = false) {&lt;br /&gt;
  showElement(classChoice.parentElement);&lt;br /&gt;
&lt;br /&gt;
  for (var option of classChoice.options) {&lt;br /&gt;
    if (option.getAttribute(&amp;quot;data-race&amp;quot;) === selectedRace) {&lt;br /&gt;
      if (!selectValueIsChanged) {&lt;br /&gt;
        classChoice.value = option.value;&lt;br /&gt;
        selectValueIsChanged = true;&lt;br /&gt;
      }&lt;br /&gt;
      showElement(option);&lt;br /&gt;
    } else {&lt;br /&gt;
      hideElement(option);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  if (selectedRace == &amp;quot;lycan&amp;quot;) {&lt;br /&gt;
    hideElement(classChoice.parentElement);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterWeapon(&lt;br /&gt;
  selectedRace,&lt;br /&gt;
  weaponElement,&lt;br /&gt;
  weaponCategory,&lt;br /&gt;
  allowedWeaponsPerRace,&lt;br /&gt;
  selectValueIsChanged = false&lt;br /&gt;
) {&lt;br /&gt;
  var allowedWeapons = allowedWeaponsPerRace[selectedRace];&lt;br /&gt;
&lt;br /&gt;
  if (!selectValueIsChanged) {&lt;br /&gt;
    var weaponType = weaponData[weaponElement.value][1];&lt;br /&gt;
&lt;br /&gt;
    if (!isValueInArray(weaponType, allowedWeapons)) {&lt;br /&gt;
      weaponElement.value = 0;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var children = weaponCategory.children;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; children.length; index++) {&lt;br /&gt;
    var child = children[index];&lt;br /&gt;
&lt;br /&gt;
    if (isValueInArray(index, allowedWeapons)) {&lt;br /&gt;
      showElement(child);&lt;br /&gt;
    } else {&lt;br /&gt;
      hideElement(child);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSelectedWeapon(weaponCategory) {&lt;br /&gt;
  return weaponCategory.querySelector(&amp;quot;input[type='radio']:checked&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleWeaponDisplay(weaponDisplay, newWeapon, weaponVnum) {&lt;br /&gt;
  var newImage = newWeapon.nextElementSibling.cloneNode();&lt;br /&gt;
  var newText = document.createElement(&amp;quot;span&amp;quot;);&lt;br /&gt;
  var oldImage = weaponDisplay.firstChild;&lt;br /&gt;
  var oldText = oldImage.nextElementSibling;&lt;br /&gt;
  var weaponName = createWeapon(weaponVnum).name;&lt;br /&gt;
&lt;br /&gt;
  if (weaponVnum == 0) {&lt;br /&gt;
    newText.textContent = &amp;quot; &amp;quot; + weaponName + &amp;quot; &amp;quot;;&lt;br /&gt;
  } else {&lt;br /&gt;
    var weaponLink = document.createElement(&amp;quot;a&amp;quot;);&lt;br /&gt;
    weaponLink.href = mw.util.getUrl(weaponName);&lt;br /&gt;
    weaponLink.title = weaponName;&lt;br /&gt;
    weaponLink.textContent = weaponName;&lt;br /&gt;
&lt;br /&gt;
    newText.appendChild(document.createTextNode(&amp;quot; &amp;quot;));&lt;br /&gt;
    newText.appendChild(weaponLink);&lt;br /&gt;
    newText.appendChild(document.createTextNode(&amp;quot; &amp;quot;));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  weaponDisplay.replaceChild(newImage, oldImage);&lt;br /&gt;
  weaponDisplay.replaceChild(newText, oldText);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterUpgrade(&lt;br /&gt;
  selectedRace,&lt;br /&gt;
  weaponUpgrade,&lt;br /&gt;
  weaponVnum,&lt;br /&gt;
  randomAttackValue,&lt;br /&gt;
  randomMagicAttackValue,&lt;br /&gt;
  currentUpgrade&lt;br /&gt;
) {&lt;br /&gt;
  var weapon = createWeapon(weaponVnum);&lt;br /&gt;
&lt;br /&gt;
  if (weapon.isSerpent) {&lt;br /&gt;
    showElement(randomAttackValue);&lt;br /&gt;
&lt;br /&gt;
    if (selectedRace === &amp;quot;sura&amp;quot; || selectedRace === &amp;quot;shaman&amp;quot;) {&lt;br /&gt;
      showElement(randomMagicAttackValue);&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    hideElement(randomAttackValue);&lt;br /&gt;
    hideElement(randomMagicAttackValue);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var upgradeNumber = weapon.upgrades.length;&lt;br /&gt;
&lt;br /&gt;
  if (upgradeNumber &amp;lt;= 1) {&lt;br /&gt;
    hideElement(weaponUpgrade.parentElement);&lt;br /&gt;
  } else {&lt;br /&gt;
    showElement(weaponUpgrade.parentElement);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  weaponUpgrade.innerHTML = &amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  for (var upgrade = 0; upgrade &amp;lt; upgradeNumber; upgrade++) {&lt;br /&gt;
    var option = document.createElement(&amp;quot;option&amp;quot;);&lt;br /&gt;
    option.value = upgrade;&lt;br /&gt;
    option.textContent = &amp;quot;+&amp;quot; + upgrade;&lt;br /&gt;
    weaponUpgrade.appendChild(option);&lt;br /&gt;
  }&lt;br /&gt;
  if (currentUpgrade === undefined) {&lt;br /&gt;
    option.selected = true;&lt;br /&gt;
  } else {&lt;br /&gt;
    weaponUpgrade.value = currentUpgrade;&lt;br /&gt;
    currentUpgrade = undefined;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterCheckbox(checkbox, element) {&lt;br /&gt;
  if (checkbox.checked) {&lt;br /&gt;
    showElement(element);&lt;br /&gt;
  } else {&lt;br /&gt;
    hideElement(element);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterSkills(selectedClass, skillElementsToFilter) {&lt;br /&gt;
  for (var element of skillElementsToFilter) {&lt;br /&gt;
    if (isValueInArray(selectedClass, element.dataset.class)) {&lt;br /&gt;
      showElement(element);&lt;br /&gt;
    } else {&lt;br /&gt;
      hideElement(element);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterAttackTypeSelection(attacker, attackTypeSelection) {&lt;br /&gt;
  var attackerClass = attacker.class;&lt;br /&gt;
  var selectedOption =&lt;br /&gt;
    attackTypeSelection.options[attackTypeSelection.selectedIndex];&lt;br /&gt;
  var attackerIsNotPolymorph = !isPolymorph(attacker);&lt;br /&gt;
&lt;br /&gt;
  for (var index = 2; index &amp;lt; attackTypeSelection.options.length; index++) {&lt;br /&gt;
    var option = attackTypeSelection.options[index];&lt;br /&gt;
    var optionClass = option.dataset.class;&lt;br /&gt;
    var optionValue = option.value;&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      attackerIsNotPolymorph &amp;amp;&amp;amp;&lt;br /&gt;
      attacker[optionValue] &amp;amp;&amp;amp;&lt;br /&gt;
      (attackerClass === optionClass ||&lt;br /&gt;
        (optionValue.startsWith(&amp;quot;horseSkill&amp;quot;) &amp;amp;&amp;amp;&lt;br /&gt;
          isRiding(attacker) &amp;amp;&amp;amp;&lt;br /&gt;
          (!optionClass || isValueInArray(attackerClass, optionClass))))&lt;br /&gt;
    ) {&lt;br /&gt;
      showElement(option);&lt;br /&gt;
    } else {&lt;br /&gt;
      hideElement(option);&lt;br /&gt;
&lt;br /&gt;
      if (selectedOption === option) {&lt;br /&gt;
        attackTypeSelection.selectedIndex = 0;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterAttackTypeSelectionMonster(attackTypeSelection) {&lt;br /&gt;
  for (var index = 2; index &amp;lt; attackTypeSelection.options.length; index++) {&lt;br /&gt;
    hideElement(attackTypeSelection.options[index]);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (attackTypeSelection.selectedIndex !== 1) {&lt;br /&gt;
    attackTypeSelection.selectedIndex = 0;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterForm(characters, battle) {&lt;br /&gt;
  var characterCreation = characters.characterCreation;&lt;br /&gt;
  var allowedWeaponsPerRace = battle.constants.allowedWeaponsPerRace;&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;change&amp;quot;, function (event) {&lt;br /&gt;
    var target = event.target;&lt;br /&gt;
    var targetName = target.name;&lt;br /&gt;
&lt;br /&gt;
    switch (targetName) {&lt;br /&gt;
      case &amp;quot;race&amp;quot;:&lt;br /&gt;
        var selectedRace = target.value;&lt;br /&gt;
        var classChoice = characterCreation.class;&lt;br /&gt;
        var weaponElement = characterCreation.weapon;&lt;br /&gt;
&lt;br /&gt;
        filterClass(selectedRace, classChoice);&lt;br /&gt;
        filterWeapon(&lt;br /&gt;
          selectedRace,&lt;br /&gt;
          weaponElement,&lt;br /&gt;
          characters.weaponCategory,&lt;br /&gt;
          allowedWeaponsPerRace&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        var newWeapon = getSelectedWeapon(characters.weaponCategory);&lt;br /&gt;
        handleWeaponDisplay(&lt;br /&gt;
          characters.weaponDisplay,&lt;br /&gt;
          newWeapon,&lt;br /&gt;
          weaponElement.value&lt;br /&gt;
        );&lt;br /&gt;
        filterUpgrade(&lt;br /&gt;
          selectedRace,&lt;br /&gt;
          characterCreation.weaponUpgrade,&lt;br /&gt;
          weaponElement.value,&lt;br /&gt;
          characters.randomAttackValue,&lt;br /&gt;
          characters.randomMagicAttackValue&lt;br /&gt;
        );&lt;br /&gt;
        filterSkills(classChoice.value, characters.skillElementsToFilter);&lt;br /&gt;
&lt;br /&gt;
        if (characterCreation.name.value === battle.attackerSelection.value) {&lt;br /&gt;
          battle.resetAttackType = true;&lt;br /&gt;
        }&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;class&amp;quot;:&lt;br /&gt;
        filterSkills(target.value, characters.skillElementsToFilter);&lt;br /&gt;
&lt;br /&gt;
        if (characterCreation.name.value === battle.attackerSelection.value) {&lt;br /&gt;
          battle.resetAttackType = true;&lt;br /&gt;
        }&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;weapon&amp;quot;:&lt;br /&gt;
        handleWeaponDisplay(&lt;br /&gt;
          characters.weaponDisplay,&lt;br /&gt;
          target,&lt;br /&gt;
          characterCreation.weapon.value&lt;br /&gt;
        );&lt;br /&gt;
        filterUpgrade(&lt;br /&gt;
          characterCreation.race.value,&lt;br /&gt;
          characterCreation.weaponUpgrade,&lt;br /&gt;
          target.value,&lt;br /&gt;
          characters.randomAttackValue,&lt;br /&gt;
          characters.randomMagicAttackValue&lt;br /&gt;
        );&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;isPolymorph&amp;quot;:&lt;br /&gt;
        filterCheckbox(target, characterCreation.polymorphMonster.parentElement);&lt;br /&gt;
        if (characterCreation.name.value === battle.attackerSelection.value) {&lt;br /&gt;
          battle.resetAttackType = true;&lt;br /&gt;
        }&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;lowRank&amp;quot;:&lt;br /&gt;
        filterCheckbox(target, characterCreation.playerRank.parentElement);&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;isBlessed&amp;quot;:&lt;br /&gt;
        filterCheckbox(target, characters.blessingCreation);&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;onYohara&amp;quot;:&lt;br /&gt;
        filterCheckbox(target, characters.yoharaCreation);&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;isMarried&amp;quot;:&lt;br /&gt;
        filterCheckbox(target, characters.marriageCreation);&lt;br /&gt;
        break;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      targetName.startsWith(&amp;quot;attackSkill&amp;quot;) ||&lt;br /&gt;
      targetName.startsWith(&amp;quot;horseSkill&amp;quot;)&lt;br /&gt;
    ) {&lt;br /&gt;
      battle.resetAttackType = true;&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addUniquePseudo(characterDataObject, savedCharactersPseudo) {&lt;br /&gt;
  var characterPseudo = String(characterDataObject.name);&lt;br /&gt;
  var originalPseudo = characterPseudo;&lt;br /&gt;
  var count = 0;&lt;br /&gt;
&lt;br /&gt;
  var regex = /(.*)(\d)$/;&lt;br /&gt;
  var match = characterPseudo.match(regex);&lt;br /&gt;
&lt;br /&gt;
  if (match) {&lt;br /&gt;
    originalPseudo = match[1];&lt;br /&gt;
    count = match[2];&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  while (isValueInArray(characterPseudo, savedCharactersPseudo)) {&lt;br /&gt;
    characterPseudo = originalPseudo + count;&lt;br /&gt;
    count++;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  characterDataObject.name = characterPseudo;&lt;br /&gt;
  return [characterDataObject, characterPseudo];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function convertToNumber(value) {&lt;br /&gt;
  var valueNumber = Number(value);&lt;br /&gt;
  return isNaN(valueNumber) ? value : valueNumber;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getLocalStorageValue(key, defaultValue) {&lt;br /&gt;
  var storedValue = localStorage.getItem(key);&lt;br /&gt;
&lt;br /&gt;
  if (storedValue) {&lt;br /&gt;
    return JSON.parse(storedValue);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return defaultValue;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSavedCharacters() {&lt;br /&gt;
  return getLocalStorageValue(&amp;quot;savedCharactersCalculator&amp;quot;, {});&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSavedMonsters() {&lt;br /&gt;
  var savedMonsters = getLocalStorageValue(&amp;quot;savedMonstersCalculator&amp;quot;, {});&lt;br /&gt;
&lt;br /&gt;
  if (Array.isArray(savedMonsters)) {&lt;br /&gt;
    return {};&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var filteredMonsters = {};&lt;br /&gt;
&lt;br /&gt;
  for (var vnum in savedMonsters) {&lt;br /&gt;
    if (String(Number(vnum)) === vnum) {&lt;br /&gt;
      filteredMonsters[vnum] = savedMonsters[vnum];&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return filteredMonsters;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSavedFights() {&lt;br /&gt;
  return getLocalStorageValue(&amp;quot;savedFightsCalculator&amp;quot;, []);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveToLocalStorage(key, value) {&lt;br /&gt;
  localStorage.setItem(key, JSON.stringify(value));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateSavedCharacters(savedCharacters) {&lt;br /&gt;
  saveToLocalStorage(&amp;quot;savedCharactersCalculator&amp;quot;, savedCharacters);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateSavedMonsters(savedMonsters) {&lt;br /&gt;
  saveToLocalStorage(&amp;quot;savedMonstersCalculator&amp;quot;, savedMonsters);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateSavedFights(savedFights) {&lt;br /&gt;
  saveToLocalStorage(&amp;quot;savedFightsCalculator&amp;quot;, savedFights);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveCharacter(&lt;br /&gt;
  savedCharacters,&lt;br /&gt;
  characterCreation,&lt;br /&gt;
  battle,&lt;br /&gt;
  newCharacter,&lt;br /&gt;
  characterDataObject&lt;br /&gt;
) {&lt;br /&gt;
  if (!characterDataObject) {&lt;br /&gt;
    var characterData = new FormData(characterCreation);&lt;br /&gt;
    var characterDataObject = {};&lt;br /&gt;
&lt;br /&gt;
    characterData.forEach(function (value, key) {&lt;br /&gt;
      characterDataObject[key] = convertToNumber(value);&lt;br /&gt;
    });&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  savedCharacters[characterDataObject.name] = characterDataObject;&lt;br /&gt;
  updateSavedCharacters(savedCharacters);&lt;br /&gt;
&lt;br /&gt;
  if (newCharacter) {&lt;br /&gt;
    addBattleChoice(battle, characterDataObject.name);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (battle.resetAttackType) {&lt;br /&gt;
    filterAttackTypeSelection(characterDataObject, battle.attackTypeSelection);&lt;br /&gt;
    battle.resetAttackType = false;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveButtonGreen(saveButton) {&lt;br /&gt;
  saveButton.classList.remove(&amp;quot;unsaved-character&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveButtonOrange(saveButton) {&lt;br /&gt;
  saveButton.classList.add(&amp;quot;unsaved-character&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function characterCreationListener(characters, battle) {&lt;br /&gt;
  var { characterCreation, saveButton, weaponCategory } = characters;&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;submit&amp;quot;, function (event) {&lt;br /&gt;
    event.preventDefault();&lt;br /&gt;
&lt;br /&gt;
    if (characters.unsavedChanges) {&lt;br /&gt;
      saveCharacter(characters.savedCharacters, characterCreation, battle);&lt;br /&gt;
      saveButtonGreen(saveButton);&lt;br /&gt;
      characters.unsavedChanges = false;&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  document.addEventListener(&amp;quot;keydown&amp;quot;, function (event) {&lt;br /&gt;
    if (event.ctrlKey &amp;amp;&amp;amp; event.key === &amp;quot;s&amp;quot;) {&lt;br /&gt;
      event.preventDefault();&lt;br /&gt;
      saveButton.click();&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  weaponCategory.addEventListener(&amp;quot;mouseover&amp;quot;, function (event) {&lt;br /&gt;
    label = event.target.closest(&amp;quot;label&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (label) {&lt;br /&gt;
      var tooltip = label.lastChild;&lt;br /&gt;
&lt;br /&gt;
      if (tooltip.classList.contains(&amp;quot;popContenu&amp;quot;)) {&lt;br /&gt;
        var tooltipRect = tooltip.getBoundingClientRect();&lt;br /&gt;
        var modalRect = weaponCategory.getBoundingClientRect();&lt;br /&gt;
&lt;br /&gt;
        if (tooltipRect.right &amp;gt; modalRect.right) {&lt;br /&gt;
          tooltip.style.left = &amp;quot;-100%&amp;quot;;&lt;br /&gt;
        } else if (tooltipRect.left &amp;lt; modalRect.left) {&lt;br /&gt;
          tooltip.style.left = &amp;quot;200%&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function downloadData(content, type, filename) {&lt;br /&gt;
  var link = document.createElement(&amp;quot;a&amp;quot;);&lt;br /&gt;
  var blob = new Blob([content], { type: type });&lt;br /&gt;
  var blobURL = URL.createObjectURL(blob);&lt;br /&gt;
&lt;br /&gt;
  link.href = blobURL;&lt;br /&gt;
  link.download = filename;&lt;br /&gt;
  document.body.appendChild(link);&lt;br /&gt;
&lt;br /&gt;
  link.click();&lt;br /&gt;
  document.body.removeChild(link);&lt;br /&gt;
  URL.revokeObjectURL(blobURL);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function uploadCharacter(&lt;br /&gt;
  selectedFiles,&lt;br /&gt;
  characters,&lt;br /&gt;
  characterTemplate,&lt;br /&gt;
  charactersContainer,&lt;br /&gt;
  battle&lt;br /&gt;
) {&lt;br /&gt;
  var selectFilesLength = selectedFiles.length;&lt;br /&gt;
&lt;br /&gt;
  for (var fileIndex = 0; fileIndex &amp;lt; selectFilesLength; fileIndex++) {&lt;br /&gt;
    var selectedFile = selectedFiles[fileIndex];&lt;br /&gt;
&lt;br /&gt;
    if (selectedFile.type === &amp;quot;text/plain&amp;quot;) {&lt;br /&gt;
      var reader = new FileReader();&lt;br /&gt;
      reader.onload = function (e) {&lt;br /&gt;
        var fileContent = e.target.result;&lt;br /&gt;
        try {&lt;br /&gt;
          var characterDataObject = JSON.parse(fileContent);&lt;br /&gt;
&lt;br /&gt;
          if (characterDataObject.hasOwnProperty(&amp;quot;name&amp;quot;)) {&lt;br /&gt;
            var characterPseudo = String(characterDataObject.name);&lt;br /&gt;
&lt;br /&gt;
            hideElement(characters.characterCreation);&lt;br /&gt;
            characterPseudo = validPseudo(characterPseudo);&lt;br /&gt;
&lt;br /&gt;
            [characterDataObject, characterPseudo] = addUniquePseudo(&lt;br /&gt;
              characterDataObject,&lt;br /&gt;
              Object.keys(characters.savedCharacters)&lt;br /&gt;
            );&lt;br /&gt;
            var selectedCharacter = handleNewCharacter(&lt;br /&gt;
              characters,&lt;br /&gt;
              characterTemplate,&lt;br /&gt;
              charactersContainer,&lt;br /&gt;
              battle,&lt;br /&gt;
              characterPseudo&lt;br /&gt;
            )[0];&lt;br /&gt;
&lt;br /&gt;
            if (selectFilesLength === 1) {&lt;br /&gt;
              updateForm(&lt;br /&gt;
                characterDataObject,&lt;br /&gt;
                characters.characterCreation,&lt;br /&gt;
                characters,&lt;br /&gt;
                selectedCharacter,&lt;br /&gt;
                battle&lt;br /&gt;
              );&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            saveCharacter(&lt;br /&gt;
              characters.savedCharacters,&lt;br /&gt;
              characters.characterCreation,&lt;br /&gt;
              battle,&lt;br /&gt;
              true,&lt;br /&gt;
              characterDataObject&lt;br /&gt;
            );&lt;br /&gt;
          }&lt;br /&gt;
        } catch (error) {&lt;br /&gt;
          console.log(error);&lt;br /&gt;
          if (error.name === &amp;quot;TypeError&amp;quot;) {&lt;br /&gt;
            // delete the character&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
      };&lt;br /&gt;
      reader.readAsText(selectedFile);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleUploadCharacter(&lt;br /&gt;
  characters,&lt;br /&gt;
  characterTemplate,&lt;br /&gt;
  charactersContainer,&lt;br /&gt;
  battle&lt;br /&gt;
) {&lt;br /&gt;
  var characterInput = characters.characterInput;&lt;br /&gt;
  var dropZone = characters.dropZone;&lt;br /&gt;
&lt;br /&gt;
  characterInput.accept = &amp;quot;.txt&amp;quot;;&lt;br /&gt;
  characterInput.multiple = true;&lt;br /&gt;
  dropZone.setAttribute(&amp;quot;tabindex&amp;quot;, &amp;quot;0&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  dropZone.addEventListener(&amp;quot;click&amp;quot;, function () {&lt;br /&gt;
    characterInput.click();&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  dropZone.addEventListener(&amp;quot;dragover&amp;quot;, function (event) {&lt;br /&gt;
    event.preventDefault();&lt;br /&gt;
    dropZone.classList.add(&amp;quot;drop-zone--dragover&amp;quot;);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  [&amp;quot;dragleave&amp;quot;, &amp;quot;dragend&amp;quot;].forEach(function (type) {&lt;br /&gt;
    dropZone.addEventListener(type, function () {&lt;br /&gt;
      dropZone.classList.remove(&amp;quot;drop-zone--dragover&amp;quot;);&lt;br /&gt;
    });&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  dropZone.addEventListener(&amp;quot;drop&amp;quot;, function (event) {&lt;br /&gt;
    event.preventDefault();&lt;br /&gt;
    uploadCharacter(&lt;br /&gt;
      event.dataTransfer.files,&lt;br /&gt;
      characters,&lt;br /&gt;
      characterTemplate,&lt;br /&gt;
      charactersContainer,&lt;br /&gt;
      battle&lt;br /&gt;
    );&lt;br /&gt;
    dropZone.classList.remove(&amp;quot;drop-zone--dragover&amp;quot;);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  characterInput.addEventListener(&amp;quot;change&amp;quot;, function (event) {&lt;br /&gt;
    uploadCharacter(&lt;br /&gt;
      event.target.files,&lt;br /&gt;
      characters,&lt;br /&gt;
      characterTemplate,&lt;br /&gt;
      charactersContainer,&lt;br /&gt;
      battle&lt;br /&gt;
    );&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function deleteCharacter(characters, pseudo, element, battle) {&lt;br /&gt;
  battle.battleForm.reset();&lt;br /&gt;
  delete characters.savedCharacters[pseudo];&lt;br /&gt;
  element.remove();&lt;br /&gt;
&lt;br /&gt;
  updateSavedCharacters(characters.savedCharacters);&lt;br /&gt;
  removeBattleChoice(battle, pseudo);&lt;br /&gt;
&lt;br /&gt;
  if (&lt;br /&gt;
    !Object.keys(characters.savedCharacters).length ||&lt;br /&gt;
    characters.characterCreation.name.value === pseudo&lt;br /&gt;
  ) {&lt;br /&gt;
    saveButtonGreen(characters.saveButton);&lt;br /&gt;
    characters.unsavedChanges = false;&lt;br /&gt;
    hideElement(characters.characterCreation);&lt;br /&gt;
    showElement(characters.characterCreation.previousElementSibling);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function deleteMonster(characters, battle, monsterVnum, monsterElement) {&lt;br /&gt;
  var monsterElement =&lt;br /&gt;
    monsterElement ||&lt;br /&gt;
    characters.monstersContainer.querySelector(&lt;br /&gt;
      &amp;quot;[data-monster-id='&amp;quot; + monsterVnum + &amp;quot;']&amp;quot;&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
  if (monsterElement) {&lt;br /&gt;
    monsterElement.remove();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  battle.battleForm.reset();&lt;br /&gt;
  delete characters.savedMonsters[monsterVnum];&lt;br /&gt;
&lt;br /&gt;
  updateSavedMonsters(characters.savedMonsters);&lt;br /&gt;
  removeBattleChoice(battle, monsterVnum);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleStyle(characters, selectedElement) {&lt;br /&gt;
  var currentCharacter = characters.currentCharacter;&lt;br /&gt;
&lt;br /&gt;
  if (currentCharacter) {&lt;br /&gt;
    currentCharacter.classList.remove(&amp;quot;selected-character&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  selectedElement.classList.add(&amp;quot;selected-character&amp;quot;);&lt;br /&gt;
  characters.currentCharacter = selectedElement;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateForm(&lt;br /&gt;
  formData,&lt;br /&gt;
  characterCreation,&lt;br /&gt;
  characters,&lt;br /&gt;
  selectedElement,&lt;br /&gt;
  battle&lt;br /&gt;
) {&lt;br /&gt;
  saveButtonGreen(characters.saveButton);&lt;br /&gt;
  hideElement(characterCreation.previousElementSibling);&lt;br /&gt;
  showElement(characterCreation);&lt;br /&gt;
  handleStyle(characters, selectedElement);&lt;br /&gt;
&lt;br /&gt;
  characterCreation.reset();&lt;br /&gt;
&lt;br /&gt;
  for (var [name, value] of Object.entries(formData)) {&lt;br /&gt;
    var formElement = characterCreation[name];&lt;br /&gt;
&lt;br /&gt;
    if (!formElement) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (formElement.type === &amp;quot;checkbox&amp;quot;) {&lt;br /&gt;
      if (isChecked(value)) {&lt;br /&gt;
        formElement.checked = true;&lt;br /&gt;
      }&lt;br /&gt;
    } else {&lt;br /&gt;
      formElement.value = value;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  var selectedRace = characterCreation.race.value;&lt;br /&gt;
  var classChoice = characterCreation.class;&lt;br /&gt;
  var weaponElement = characterCreation.weapon;&lt;br /&gt;
&lt;br /&gt;
  filterClass(selectedRace, classChoice, true);&lt;br /&gt;
  filterWeapon(&lt;br /&gt;
    selectedRace,&lt;br /&gt;
    weaponElement,&lt;br /&gt;
    characters.weaponCategory,&lt;br /&gt;
    battle.constants.allowedWeaponsPerRace,&lt;br /&gt;
    true&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  var newWeapon = getSelectedWeapon(characters.weaponCategory);&lt;br /&gt;
&lt;br /&gt;
  handleWeaponDisplay(characters.weaponDisplay, newWeapon, weaponElement.value);&lt;br /&gt;
  filterUpgrade(&lt;br /&gt;
    selectedRace,&lt;br /&gt;
    characterCreation.weaponUpgrade,&lt;br /&gt;
    weaponElement.value,&lt;br /&gt;
    characters.randomAttackValue,&lt;br /&gt;
    characters.randomMagicAttackValue,&lt;br /&gt;
    formData.weaponUpgrade&lt;br /&gt;
  );&lt;br /&gt;
  filterCheckbox(&lt;br /&gt;
    characterCreation.isPolymorph,&lt;br /&gt;
    characterCreation.polymorphMonster.parentElement&lt;br /&gt;
  );&lt;br /&gt;
  filterCheckbox(&lt;br /&gt;
    characterCreation.lowRank,&lt;br /&gt;
    characterCreation.playerRank.parentElement&lt;br /&gt;
  );&lt;br /&gt;
  filterCheckbox(characterCreation.onYohara, characters.yoharaCreation);&lt;br /&gt;
  filterCheckbox(characterCreation.isBlessed, characters.blessingCreation);&lt;br /&gt;
  filterCheckbox(characterCreation.isMarried, characters.marriageCreation);&lt;br /&gt;
  filterSkills(classChoice.value, characters.skillElementsToFilter);&lt;br /&gt;
  handleBonusVariationUpdate(characterCreation, characters.bonusVariation);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleClickOnCharacter(&lt;br /&gt;
  spanInput,&lt;br /&gt;
  target,&lt;br /&gt;
  characters,&lt;br /&gt;
  characterElement,&lt;br /&gt;
  battle,&lt;br /&gt;
  edition&lt;br /&gt;
) {&lt;br /&gt;
  var displayedPseudo = characters.characterCreation.name.value;&lt;br /&gt;
  var pseudo = spanInput.dataset.name;&lt;br /&gt;
&lt;br /&gt;
  if (edition) {&lt;br /&gt;
    if (!characters.unsavedChanges) {&lt;br /&gt;
      updateForm(&lt;br /&gt;
        characters.savedCharacters[pseudo],&lt;br /&gt;
        characters.characterCreation,&lt;br /&gt;
        characters,&lt;br /&gt;
        characterElement,&lt;br /&gt;
        battle&lt;br /&gt;
      );&lt;br /&gt;
    } else if (displayedPseudo === pseudo) {&lt;br /&gt;
      // pass&lt;br /&gt;
    } else {&lt;br /&gt;
      var result = confirm(&lt;br /&gt;
        &amp;quot;Voulez-vous continuer ? Les dernières modifications ne seront pas sauvegardées.&amp;quot;&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      if (result) {&lt;br /&gt;
        updateForm(&lt;br /&gt;
          characters.savedCharacters[pseudo],&lt;br /&gt;
          characters.characterCreation,&lt;br /&gt;
          characters,&lt;br /&gt;
          characterElement,&lt;br /&gt;
          battle&lt;br /&gt;
        );&lt;br /&gt;
        characters.unsavedChanges = false;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    if (target.tagName === &amp;quot;path&amp;quot;) {&lt;br /&gt;
      target = target.parentElement;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    switch (target.dataset.icon) {&lt;br /&gt;
      case &amp;quot;duplicate&amp;quot;:&lt;br /&gt;
        if (!characters.unsavedChanges) {&lt;br /&gt;
          addNewCharacter(&lt;br /&gt;
            characters,&lt;br /&gt;
            characters.newCharacterTemplate,&lt;br /&gt;
            characters.charactersContainer,&lt;br /&gt;
            battle,&lt;br /&gt;
            pseudo&lt;br /&gt;
          );&lt;br /&gt;
        } else {&lt;br /&gt;
          var result = confirm(&lt;br /&gt;
            &amp;quot;Voulez-vous continuer ? Les dernières modifications ne seront pas sauvegardées.&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
&lt;br /&gt;
          if (result) {&lt;br /&gt;
            addNewCharacter(&lt;br /&gt;
              characters,&lt;br /&gt;
              characters.newCharacterTemplate,&lt;br /&gt;
              characters.charactersContainer,&lt;br /&gt;
              battle,&lt;br /&gt;
              pseudo&lt;br /&gt;
            );&lt;br /&gt;
            saveButtonGreen(characters.saveButton);&lt;br /&gt;
            characters.unsavedChanges = false;&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
        break;&lt;br /&gt;
&lt;br /&gt;
      case &amp;quot;download&amp;quot;:&lt;br /&gt;
        var character = characters.savedCharacters[pseudo];&lt;br /&gt;
        downloadData(&lt;br /&gt;
          JSON.stringify(character),&lt;br /&gt;
          &amp;quot;text/plain&amp;quot;,&lt;br /&gt;
          character.name + &amp;quot;.txt&amp;quot;&lt;br /&gt;
        );&lt;br /&gt;
        break;&lt;br /&gt;
&lt;br /&gt;
      case &amp;quot;delete&amp;quot;:&lt;br /&gt;
        var result = confirm(&lt;br /&gt;
          &amp;quot;Voulez-vous vraiment supprimer définitivement le personnage &amp;quot; +&lt;br /&gt;
            pseudo +&lt;br /&gt;
            &amp;quot; ?&amp;quot;&lt;br /&gt;
        );&lt;br /&gt;
        if (result) {&lt;br /&gt;
          deleteCharacter(characters, pseudo, characterElement, battle);&lt;br /&gt;
        }&lt;br /&gt;
        break;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleNewCharacter(&lt;br /&gt;
  characters,&lt;br /&gt;
  characterTemplate,&lt;br /&gt;
  charactersContainer,&lt;br /&gt;
  battle,&lt;br /&gt;
  pseudo&lt;br /&gt;
) {&lt;br /&gt;
  var newCharacterTemplate = characterTemplate.cloneNode(true);&lt;br /&gt;
  var spanInput = newCharacterTemplate.querySelector(&amp;quot;span.input&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  newCharacterTemplate.setAttribute(&amp;quot;tabindex&amp;quot;, &amp;quot;0&amp;quot;);&lt;br /&gt;
  charactersContainer.appendChild(newCharacterTemplate);&lt;br /&gt;
&lt;br /&gt;
  if (pseudo) {&lt;br /&gt;
    spanInput.textContent = pseudo;&lt;br /&gt;
    spanInput.setAttribute(&amp;quot;data-name&amp;quot;, pseudo);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  newCharacterTemplate.addEventListener(&amp;quot;click&amp;quot;, function (event) {&lt;br /&gt;
    var target = event.target;&lt;br /&gt;
&lt;br /&gt;
    if (target.tagName === &amp;quot;path&amp;quot; || target.tagName === &amp;quot;svg&amp;quot;) {&lt;br /&gt;
      handleClickOnCharacter(&lt;br /&gt;
        spanInput,&lt;br /&gt;
        target,&lt;br /&gt;
        characters,&lt;br /&gt;
        newCharacterTemplate,&lt;br /&gt;
        battle&lt;br /&gt;
      );&lt;br /&gt;
    } else {&lt;br /&gt;
      handleClickOnCharacter(&lt;br /&gt;
        spanInput,&lt;br /&gt;
        null,&lt;br /&gt;
        characters,&lt;br /&gt;
        newCharacterTemplate,&lt;br /&gt;
        battle,&lt;br /&gt;
        true&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  newCharacterTemplate.addEventListener(&amp;quot;keydown&amp;quot;, function (event) {&lt;br /&gt;
    if (event.keyCode === 13) {&lt;br /&gt;
      event.target.click();&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  return [newCharacterTemplate, spanInput];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function validPseudo(pseudo) {&lt;br /&gt;
  var newPseudo = pseudoFormat(pseudo);&lt;br /&gt;
&lt;br /&gt;
  if (!newPseudo) {&lt;br /&gt;
    return &amp;quot;Pseudo&amp;quot;;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return newPseudo;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addNewCharacter(&lt;br /&gt;
  characters,&lt;br /&gt;
  characterTemplate,&lt;br /&gt;
  charactersContainer,&lt;br /&gt;
  battle,&lt;br /&gt;
  pseudoToDuplicate&lt;br /&gt;
) {&lt;br /&gt;
  function editAndSetCharacterPseudoInput(selectedCharacter, spanInput) {&lt;br /&gt;
    var maxPseudoLength = 20;&lt;br /&gt;
&lt;br /&gt;
    var selection = window.getSelection();&lt;br /&gt;
    var range = document.createRange();&lt;br /&gt;
&lt;br /&gt;
    if (pseudoToDuplicate) {&lt;br /&gt;
      spanInput.textContent = pseudoToDuplicate;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    spanInput.contentEditable = true;&lt;br /&gt;
    spanInput.focus();&lt;br /&gt;
    range.selectNodeContents(spanInput);&lt;br /&gt;
    selection.removeAllRanges();&lt;br /&gt;
    selection.addRange(range);&lt;br /&gt;
&lt;br /&gt;
    function pseudoValidation() {&lt;br /&gt;
      var characterPseudo = validPseudo(spanInput.textContent);&lt;br /&gt;
      var characterDataObject = { name: characterPseudo };&lt;br /&gt;
&lt;br /&gt;
      if (pseudoToDuplicate) {&lt;br /&gt;
        characterDataObject = copyObject(&lt;br /&gt;
          characters.savedCharacters[pseudoToDuplicate]&lt;br /&gt;
        );&lt;br /&gt;
        characterDataObject.name = characterPseudo;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      [characterDataObject, characterPseudo] = addUniquePseudo(&lt;br /&gt;
        characterDataObject,&lt;br /&gt;
        Object.keys(characters.savedCharacters)&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      selection.removeAllRanges();&lt;br /&gt;
      spanInput.contentEditable = false;&lt;br /&gt;
      spanInput.textContent = characterPseudo;&lt;br /&gt;
      spanInput.setAttribute(&amp;quot;data-name&amp;quot;, characterPseudo);&lt;br /&gt;
&lt;br /&gt;
      updateForm(&lt;br /&gt;
        characterDataObject,&lt;br /&gt;
        characters.characterCreation,&lt;br /&gt;
        characters,&lt;br /&gt;
        selectedCharacter,&lt;br /&gt;
        battle&lt;br /&gt;
      );&lt;br /&gt;
      saveCharacter(&lt;br /&gt;
        characters.savedCharacters,&lt;br /&gt;
        characters.characterCreation,&lt;br /&gt;
        battle,&lt;br /&gt;
        true&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handleMaxLength(event) {&lt;br /&gt;
      if (spanInput.textContent.length &amp;gt; maxPseudoLength) {&lt;br /&gt;
        spanInput.textContent = spanInput.textContent.slice(0, maxPseudoLength);&lt;br /&gt;
        range.setStart(spanInput.childNodes[0], maxPseudoLength);&lt;br /&gt;
        selection.removeAllRanges();&lt;br /&gt;
        selection.addRange(range);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handleBlur() {&lt;br /&gt;
      spanInput.removeEventListener(&amp;quot;blur&amp;quot;, handleBlur);&lt;br /&gt;
      spanInput.removeEventListener(&amp;quot;input&amp;quot;, handleMaxLength);&lt;br /&gt;
      pseudoValidation();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handleKeyDown(event) {&lt;br /&gt;
      if (event.key === &amp;quot;Enter&amp;quot;) {&lt;br /&gt;
        event.preventDefault();&lt;br /&gt;
&lt;br /&gt;
        spanInput.removeEventListener(&amp;quot;keydown&amp;quot;, handleKeyDown);&lt;br /&gt;
        spanInput.removeEventListener(&amp;quot;blur&amp;quot;, handleBlur);&lt;br /&gt;
        spanInput.removeEventListener(&amp;quot;input&amp;quot;, handleMaxLength);&lt;br /&gt;
&lt;br /&gt;
        pseudoValidation();&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    spanInput.addEventListener(&amp;quot;input&amp;quot;, handleMaxLength);&lt;br /&gt;
    spanInput.addEventListener(&amp;quot;keydown&amp;quot;, handleKeyDown);&lt;br /&gt;
    spanInput.addEventListener(&amp;quot;blur&amp;quot;, handleBlur);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  hideElement(characters.characterCreation);&lt;br /&gt;
  var [selectedCharacter, spanInput] = handleNewCharacter(&lt;br /&gt;
    characters,&lt;br /&gt;
    characterTemplate,&lt;br /&gt;
    charactersContainer,&lt;br /&gt;
    battle&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  editAndSetCharacterPseudoInput(selectedCharacter, spanInput);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleFocus() {&lt;br /&gt;
  var tooltipLinks = document.querySelectorAll(&amp;quot;div.tooltip a&amp;quot;);&lt;br /&gt;
  tooltipLinks.forEach(function (link) {&lt;br /&gt;
    link.setAttribute(&amp;quot;tabindex&amp;quot;, -1);&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleBonusVariationUpdate(characterCreation, bonusVariation) {&lt;br /&gt;
  var selectedBonus = characterCreation.bonusVariation.value;&lt;br /&gt;
&lt;br /&gt;
  if (characterCreation.hasOwnProperty(selectedBonus)) {&lt;br /&gt;
    handleBonusVariation(characterCreation[selectedBonus], bonusVariation);&lt;br /&gt;
  } else {&lt;br /&gt;
    var { minValue, maxValue } = bonusVariation;&lt;br /&gt;
&lt;br /&gt;
    minValue.removeAttribute(&amp;quot;min&amp;quot;);&lt;br /&gt;
    minValue.removeAttribute(&amp;quot;max&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    maxValue.removeAttribute(&amp;quot;min&amp;quot;);&lt;br /&gt;
    maxValue.removeAttribute(&amp;quot;max&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    hideElement(bonusVariation.container);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getTargetContent(targetParent, targetName, isSkill) {&lt;br /&gt;
  var targetContent = &amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  if (targetParent.children.length &amp;lt;= 1) {&lt;br /&gt;
    targetContent = targetParent.textContent;&lt;br /&gt;
  } else if (targetName === &amp;quot;weaponUpgrade&amp;quot;) {&lt;br /&gt;
    targetContent = targetParent.children[1].textContent;&lt;br /&gt;
  } else if (isSkill) {&lt;br /&gt;
    var container = targetParent.children[1];&lt;br /&gt;
&lt;br /&gt;
    for (var index = 1; index &amp;lt; container.children.length; index++) {&lt;br /&gt;
      var element = container.children[index];&lt;br /&gt;
&lt;br /&gt;
      if (element.checkVisibility()) {&lt;br /&gt;
        targetContent += element.textContent;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    for (var index = 1; index &amp;lt; targetParent.children.length; index++) {&lt;br /&gt;
      var element = targetParent.children[index];&lt;br /&gt;
&lt;br /&gt;
      if (element.checkVisibility()) {&lt;br /&gt;
        targetContent += element.textContent;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return targetContent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleBonusVariation(target, bonusVariation, isSelectedByUser) {&lt;br /&gt;
  var { activation, inputDisplay, minValue, maxValue, container } =&lt;br /&gt;
    bonusVariation;&lt;br /&gt;
&lt;br /&gt;
  var {&lt;br /&gt;
    min: targetMin,&lt;br /&gt;
    max: targetMax,&lt;br /&gt;
    name: targetName,&lt;br /&gt;
    value: targetValue,&lt;br /&gt;
    parentElement: targetParent,&lt;br /&gt;
    tagName,&lt;br /&gt;
  } = target;&lt;br /&gt;
&lt;br /&gt;
  targetMin = Number(targetMin);&lt;br /&gt;
  targetMax = Number(targetMax);&lt;br /&gt;
  targetValue = Number(targetValue);&lt;br /&gt;
&lt;br /&gt;
  var isSkill = tagName === &amp;quot;SELECT&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  if (container.contains(target) || targetName == 0) {&lt;br /&gt;
    if (!isSelectedByUser) {&lt;br /&gt;
      hideElement(container);&lt;br /&gt;
    }&lt;br /&gt;
    return;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (isSkill) {&lt;br /&gt;
    var options = target.options;&lt;br /&gt;
&lt;br /&gt;
    targetMin = options[0].value;&lt;br /&gt;
    targetMax = options[options.length - 1].value;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  minValue.min = targetMin;&lt;br /&gt;
  minValue.max = targetMax;&lt;br /&gt;
&lt;br /&gt;
  maxValue.min = targetMin;&lt;br /&gt;
  maxValue.max = targetMax;&lt;br /&gt;
&lt;br /&gt;
  if (isSelectedByUser) {&lt;br /&gt;
    var { input, tab } = bonusVariation;&lt;br /&gt;
&lt;br /&gt;
    inputDisplay.value = getTargetContent(targetParent, targetName, isSkill);&lt;br /&gt;
&lt;br /&gt;
    input.value = targetName;&lt;br /&gt;
    minValue.value = Math.max(targetValue - 10, targetMin);&lt;br /&gt;
    maxValue.value = Math.min(targetValue + 10, targetMax);&lt;br /&gt;
&lt;br /&gt;
    activation.checked = true;&lt;br /&gt;
&lt;br /&gt;
    tab.click();&lt;br /&gt;
    tab.scrollIntoView(true);&lt;br /&gt;
&lt;br /&gt;
    input.dispatchEvent(new Event(&amp;quot;change&amp;quot;, { bubbles: true }));&lt;br /&gt;
  } else {&lt;br /&gt;
    if (minValue.value &amp;lt; targetMin) {&lt;br /&gt;
      minValue.value = targetMin;&lt;br /&gt;
      minValue.dispatchEvent(new Event(&amp;quot;change&amp;quot;, { bubbles: true }));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (maxValue.value &amp;gt; targetMax) {&lt;br /&gt;
      maxValue.value = targetMax;&lt;br /&gt;
      maxValue.dispatchEvent(new Event(&amp;quot;change&amp;quot;, { bubbles: true }));&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  inputDisplay.style.width = inputDisplay.value.length * 0.55 + &amp;quot;em&amp;quot;;&lt;br /&gt;
  showElement(container);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function characterManagement(characters, battle) {&lt;br /&gt;
  var {&lt;br /&gt;
    newCharacterTemplate: characterTemplate,&lt;br /&gt;
    charactersContainer,&lt;br /&gt;
    addNewCharacterButton,&lt;br /&gt;
    saveButton,&lt;br /&gt;
    characterCreation,&lt;br /&gt;
    bonusVariation,&lt;br /&gt;
  } = characters;&lt;br /&gt;
&lt;br /&gt;
  Object.keys(characters.savedCharacters).forEach(function (pseudo) {&lt;br /&gt;
    handleNewCharacter(&lt;br /&gt;
      characters,&lt;br /&gt;
      characterTemplate,&lt;br /&gt;
      charactersContainer,&lt;br /&gt;
      battle,&lt;br /&gt;
      pseudo&lt;br /&gt;
    );&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  addNewCharacterButton.addEventListener(&amp;quot;click&amp;quot;, function (event) {&lt;br /&gt;
    if (!characters.unsavedChanges) {&lt;br /&gt;
      addNewCharacter(&lt;br /&gt;
        characters,&lt;br /&gt;
        characterTemplate,&lt;br /&gt;
        charactersContainer,&lt;br /&gt;
        battle&lt;br /&gt;
      );&lt;br /&gt;
    } else {&lt;br /&gt;
      var result = confirm(&lt;br /&gt;
        &amp;quot;Voulez-vous continuer ? Les dernières modifications ne seront pas sauvegardées.&amp;quot;&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      if (result) {&lt;br /&gt;
        addNewCharacter(&lt;br /&gt;
          characters,&lt;br /&gt;
          characterTemplate,&lt;br /&gt;
          charactersContainer,&lt;br /&gt;
          battle&lt;br /&gt;
        );&lt;br /&gt;
        saveButtonGreen(saveButton);&lt;br /&gt;
        characters.unsavedChanges = false;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  handleUploadCharacter(&lt;br /&gt;
    characters,&lt;br /&gt;
    characterTemplate,&lt;br /&gt;
    charactersContainer,&lt;br /&gt;
    battle&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;change&amp;quot;, function () {&lt;br /&gt;
    saveButtonOrange(saveButton);&lt;br /&gt;
    characters.unsavedChanges = true;&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  function handleLongPress(target) {&lt;br /&gt;
    if (target.tagName !== &amp;quot;INPUT&amp;quot; &amp;amp;&amp;amp; target.tagName !== &amp;quot;SELECT&amp;quot;) {&lt;br /&gt;
      target = target.querySelector(&amp;quot;input&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      !target ||&lt;br /&gt;
      (target.type !== &amp;quot;number&amp;quot; &amp;amp;&amp;amp;&lt;br /&gt;
        !target.classList.contains(&amp;quot;skill-select&amp;quot;) &amp;amp;&amp;amp;&lt;br /&gt;
        target.name !== &amp;quot;weaponUpgrade&amp;quot;)&lt;br /&gt;
    ) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    handleBonusVariation(target, bonusVariation, true);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;click&amp;quot;, function (event) {&lt;br /&gt;
    if (event.shiftKey || event.ctrlKey) {&lt;br /&gt;
      handleLongPress(event.target);&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  var longPressTimer;&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;touchstart&amp;quot;, function (event) {&lt;br /&gt;
    longPressTimer = setTimeout(function () {&lt;br /&gt;
      handleLongPress(event.target);&lt;br /&gt;
    }, 800);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;touchend&amp;quot;, function () {&lt;br /&gt;
    clearTimeout(longPressTimer);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;touchmove&amp;quot;, function () {&lt;br /&gt;
    clearTimeout(longPressTimer);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  filterForm(characters, battle);&lt;br /&gt;
  characterCreationListener(characters, battle);&lt;br /&gt;
  handleFocus();&lt;br /&gt;
&lt;br /&gt;
  window.addEventListener(&amp;quot;beforeunload&amp;quot;, function (event) {&lt;br /&gt;
    if (characters.unsavedChanges) {&lt;br /&gt;
      event.preventDefault();&lt;br /&gt;
      return &amp;quot;&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function removeFromIframe(iframe, monsterVnum, addButton) {&lt;br /&gt;
  var iframeDoc = iframe.contentDocument || iframe.contentWindow.document;&lt;br /&gt;
  var removeButton = iframeDoc.querySelector(&lt;br /&gt;
    &amp;quot;.handle-monster[data-monster-id='&amp;quot; + monsterVnum + &amp;quot;']&amp;quot;&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  if (removeButton) {&lt;br /&gt;
    replaceMonsterButton(removeButton, addButton, monsterVnum);&lt;br /&gt;
    return true;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return false;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addMonsterElement(characters, battle, monsterVnum) {&lt;br /&gt;
  var { monsteriFrame, stoneiFrame, monsterTemplate, monstersContainer, monsterButtonTemplates } =&lt;br /&gt;
    characters;&lt;br /&gt;
  var addButton = monsterButtonTemplates.children[0];&lt;br /&gt;
  var monsterElement = monsterTemplate.cloneNode(true);&lt;br /&gt;
&lt;br /&gt;
  var spanInput = monsterElement.querySelector(&amp;quot;span.input&amp;quot;);&lt;br /&gt;
  var deleteSvg = monsterElement.querySelector(&amp;quot;svg&amp;quot;);&lt;br /&gt;
  var monsterName = getMonsterName(monsterVnum);&lt;br /&gt;
&lt;br /&gt;
  var link = document.createElement(&amp;quot;a&amp;quot;);&lt;br /&gt;
  link.href = mw.util.getUrl(monsterName);&lt;br /&gt;
  link.title = monsterName;&lt;br /&gt;
  link.textContent = monsterName;&lt;br /&gt;
&lt;br /&gt;
  spanInput.appendChild(link);&lt;br /&gt;
&lt;br /&gt;
  monsterElement.setAttribute(&amp;quot;tabindex&amp;quot;, &amp;quot;0&amp;quot;);&lt;br /&gt;
  monsterElement.setAttribute(&amp;quot;data-monster-id&amp;quot;, monsterVnum);&lt;br /&gt;
&lt;br /&gt;
  monstersContainer.appendChild(monsterElement);&lt;br /&gt;
&lt;br /&gt;
  deleteSvg.addEventListener(&amp;quot;click&amp;quot;, function () {&lt;br /&gt;
    deleteMonster(characters, battle, monsterVnum, monsterElement);&lt;br /&gt;
    var isRemoved = removeFromIframe(monsteriFrame, monsterVnum, addButton);&lt;br /&gt;
    if (!isRemoved) {&lt;br /&gt;
      removeFromIframe(stoneiFrame, monsterVnum, addButton);&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addNewMonster(characters, battle, monsterVnum, monsterImage) {&lt;br /&gt;
  if (isValueInArray(monsterVnum, Object.keys(characters.savedMonsters))) return;&lt;br /&gt;
&lt;br /&gt;
  characters.savedMonsters[monsterVnum] = {image: monsterImage};&lt;br /&gt;
  addMonsterElement(characters, battle, monsterVnum);&lt;br /&gt;
  updateSavedMonsters(characters.savedMonsters);&lt;br /&gt;
  addBattleChoice(battle, monsterVnum, true);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function replaceMonsterButton(currentButton, newButton, monsterVnum) {&lt;br /&gt;
  var newButtonClone = newButton.cloneNode(true);&lt;br /&gt;
  newButtonClone.dataset.monsterId = monsterVnum;&lt;br /&gt;
  currentButton.replaceWith(newButtonClone);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addButtonsToCards(&lt;br /&gt;
  iframeDoc,&lt;br /&gt;
  nameToVnum,&lt;br /&gt;
  addButton,&lt;br /&gt;
  removeButton,&lt;br /&gt;
  characters&lt;br /&gt;
) {&lt;br /&gt;
  var cardToEdit = iframeDoc.getElementById(&amp;quot;list-to-filter&amp;quot;).children;&lt;br /&gt;
  var addedMonsters = Object.keys(characters.savedMonsters);&lt;br /&gt;
&lt;br /&gt;
  for (var cardIndex = 0; cardIndex &amp;lt; cardToEdit.length; cardIndex++) {&lt;br /&gt;
    var card = cardToEdit[cardIndex];&lt;br /&gt;
    var cardName = card.querySelector(&amp;quot;[data-name]&amp;quot;).firstChild.title;&lt;br /&gt;
&lt;br /&gt;
    if (!nameToVnum.hasOwnProperty(cardName)) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var monsterVnum = nameToVnum[cardName];&lt;br /&gt;
    var buttonClone;&lt;br /&gt;
&lt;br /&gt;
    if (isValueInArray(monsterVnum, addedMonsters)) {&lt;br /&gt;
      buttonClone = removeButton.cloneNode(true);&lt;br /&gt;
    } else {&lt;br /&gt;
      buttonClone = addButton.cloneNode(true);&lt;br /&gt;
    }&lt;br /&gt;
    buttonClone.dataset.monsterId = monsterVnum;&lt;br /&gt;
    card.lastElementChild.appendChild(buttonClone);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getMonsterImage(addButton) {&lt;br /&gt;
  var elder = addButton.parentElement.firstElementChild;&lt;br /&gt;
  var image = elder.querySelector(&amp;quot;img&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (image) {&lt;br /&gt;
    return image.getAttribute(&amp;quot;src&amp;quot;) || &amp;quot;&amp;quot;;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return &amp;quot;&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleiFrame(category, iframe, nameToVnum, characters, battle) {&lt;br /&gt;
  var [addButton, removeButton] = characters.monsterButtonTemplates.children;&lt;br /&gt;
&lt;br /&gt;
  iframe.src = mw.util.getUrl(category);&lt;br /&gt;
&lt;br /&gt;
  iframe.addEventListener(&amp;quot;load&amp;quot;, function () {&lt;br /&gt;
    var iframeDoc = this.contentDocument || this.contentWindow.document;&lt;br /&gt;
    var iframeBody = iframeDoc.body;&lt;br /&gt;
&lt;br /&gt;
    content = iframeDoc.getElementById(&amp;quot;show-after-loading&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    iframeBody.firstElementChild.replaceWith(content);&lt;br /&gt;
&lt;br /&gt;
    iframeBody.style.background = &amp;quot;transparent&amp;quot;;&lt;br /&gt;
    iframeBody.style.paddingRight = &amp;quot;10px&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    addButtonsToCards(&lt;br /&gt;
      iframeDoc,&lt;br /&gt;
      nameToVnum,&lt;br /&gt;
      addButton,&lt;br /&gt;
      removeButton,&lt;br /&gt;
      characters&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    iframeDoc.addEventListener(&amp;quot;click&amp;quot;, function (event) {&lt;br /&gt;
      var target = event.target;&lt;br /&gt;
      var link = target.closest(&amp;quot;a&amp;quot;);&lt;br /&gt;
      var currentButton = target.closest(&amp;quot;.handle-monster&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
      if (link) {&lt;br /&gt;
        event.preventDefault();&lt;br /&gt;
        window.open(link.href, &amp;quot;_blank&amp;quot;);&lt;br /&gt;
      } else if (currentButton) {&lt;br /&gt;
        var { monsterId: monsterVnum, action } = currentButton.dataset;&lt;br /&gt;
        var newButton;&lt;br /&gt;
&lt;br /&gt;
        if (action === &amp;quot;add&amp;quot;) {&lt;br /&gt;
          var monsterImage = getMonsterImage(currentButton);&lt;br /&gt;
          addNewMonster(characters, battle, monsterVnum, monsterImage);&lt;br /&gt;
          newButton = removeButton;&lt;br /&gt;
        } else if (action === &amp;quot;remove&amp;quot;) {&lt;br /&gt;
          deleteMonster(characters, battle, monsterVnum);&lt;br /&gt;
          newButton = addButton;&lt;br /&gt;
        }&lt;br /&gt;
        replaceMonsterButton(currentButton, newButton, monsterVnum);&lt;br /&gt;
      }&lt;br /&gt;
    });&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getNameToVnumMapping() {&lt;br /&gt;
  var nameToVnum = {};&lt;br /&gt;
&lt;br /&gt;
  for (var monsterVnum in monsterData) {&lt;br /&gt;
    nameToVnum[monsterData[monsterVnum][monsterData[monsterVnum].length - 1]] =&lt;br /&gt;
      monsterVnum;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return nameToVnum;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function monsterManagement(characters, battle) {&lt;br /&gt;
  var { monsteriFrame, stoneiFrame } = characters;&lt;br /&gt;
  var nameToVnum = getNameToVnumMapping();&lt;br /&gt;
  var monsterVnums = Object.keys(monsterData);&lt;br /&gt;
&lt;br /&gt;
  var iframeLoaded = { monster: false, stone: false };&lt;br /&gt;
&lt;br /&gt;
  document.addEventListener(&amp;quot;modalOpen&amp;quot;, function (event) {&lt;br /&gt;
    var modalName = event.detail.name;&lt;br /&gt;
&lt;br /&gt;
    if (modalName === &amp;quot;monster&amp;quot; &amp;amp;&amp;amp; !iframeLoaded.monster) {&lt;br /&gt;
      handleiFrame(&amp;quot;Monstres&amp;quot;, monsteriFrame, nameToVnum, characters, battle);&lt;br /&gt;
      iframeLoaded.monster = true;&lt;br /&gt;
    } else if (modalName === &amp;quot;stone&amp;quot; &amp;amp;&amp;amp; !iframeLoaded.stone) {&lt;br /&gt;
      handleiFrame(&lt;br /&gt;
        &amp;quot;Pierres Metin&amp;quot;,&lt;br /&gt;
        stoneiFrame,&lt;br /&gt;
        nameToVnum,&lt;br /&gt;
        characters,&lt;br /&gt;
        battle&lt;br /&gt;
      );&lt;br /&gt;
      iframeLoaded.stone = true;&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  Object.keys(characters.savedMonsters).slice().forEach(function (monsterVnum) {&lt;br /&gt;
    if (isValueInArray(monsterVnum, monsterVnums)) {&lt;br /&gt;
      addMonsterElement(characters, battle, monsterVnum);&lt;br /&gt;
    } else {&lt;br /&gt;
      deleteMonster(characters, battle, monsterVnum);&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function removeBattleChoice(battle, name) {&lt;br /&gt;
  var battleSelects = [battle.attackerSelection, battle.victimSelection];&lt;br /&gt;
&lt;br /&gt;
  battleSelects.forEach(function (battleSelect) {&lt;br /&gt;
    for (&lt;br /&gt;
      var optionIndex = 0;&lt;br /&gt;
      optionIndex &amp;lt; battleSelect.options.length;&lt;br /&gt;
      optionIndex++&lt;br /&gt;
    ) {&lt;br /&gt;
      if (battleSelect.options[optionIndex].value === name) {&lt;br /&gt;
        battleSelect.remove(optionIndex);&lt;br /&gt;
        break;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addBattleChoice(battle, name, isMonster = false) {&lt;br /&gt;
  function createOption(text, vnum) {&lt;br /&gt;
    var option = document.createElement(&amp;quot;option&amp;quot;);&lt;br /&gt;
    option.textContent = text;&lt;br /&gt;
    option.value = vnum;&lt;br /&gt;
&lt;br /&gt;
    if (!isMonster) {&lt;br /&gt;
      option.classList.add(&amp;quot;notranslate&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return option;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var vnum = name;&lt;br /&gt;
&lt;br /&gt;
  if (isMonster) {&lt;br /&gt;
    name = getMonsterName(name);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (isMonster &amp;amp;&amp;amp; monsterData[vnum][1]) {&lt;br /&gt;
    // pass&lt;br /&gt;
  } else {&lt;br /&gt;
    battle.attackerSelection.appendChild(createOption(name, vnum));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  battle.victimSelection.appendChild(createOption(name, vnum));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateBattleChoice(characters, battle) {&lt;br /&gt;
  function addChoices(names, isMonster) {&lt;br /&gt;
    for (var index = 0; index &amp;lt; names.length; index++) {&lt;br /&gt;
      addBattleChoice(battle, names[index], isMonster);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var characterNames = Object.keys(characters.savedCharacters);&lt;br /&gt;
  var monsterNames = Object.keys(characters.savedMonsters);&lt;br /&gt;
&lt;br /&gt;
  addChoices(characterNames, false);&lt;br /&gt;
  addChoices(monsterNames, true);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function isPC(character) {&lt;br /&gt;
  if (character.race === 0 || character.race === 1) {&lt;br /&gt;
    return false;&lt;br /&gt;
  }&lt;br /&gt;
  return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isBoss(character) {&lt;br /&gt;
  return character.race === 0 &amp;amp;&amp;amp; character.rank &amp;gt;= 5;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isStone(character) {&lt;br /&gt;
  return character.race === 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isMeleeAttacker(monster) {&lt;br /&gt;
  return monster.attack == 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isRangeAttacker(monster) {&lt;br /&gt;
  return monster.attack == 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isMagicAttacker(monster) {&lt;br /&gt;
  return monster.attack == 2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isMagicClass(character) {&lt;br /&gt;
  return character.race === &amp;quot;shaman&amp;quot; || character.class === &amp;quot;black_magic&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isDispell(character, skillId) {&lt;br /&gt;
  return character.class === &amp;quot;weaponary&amp;quot; &amp;amp;&amp;amp; skillId === 6;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isPolymorph(character) {&lt;br /&gt;
  return isChecked(character.isPolymorph);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isRiding(character) {&lt;br /&gt;
  return isChecked(character.isRiding);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isBow(weapon) {&lt;br /&gt;
  return weapon.type === 2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcAttackFactor(attacker, victim) {&lt;br /&gt;
  function calcCoeffK(dex, level) {&lt;br /&gt;
    return Math.min(90, Math.floor((2 * dex + level) / 3));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var K1 = calcCoeffK(attacker.polymorphDex, attacker.level);&lt;br /&gt;
  var K2 = calcCoeffK(victim.polymorphDex, attacker.level);&lt;br /&gt;
&lt;br /&gt;
  var AR = (K1 + 210) / 300;&lt;br /&gt;
  var ER = (((2 * K2 + 5) / (K2 + 95)) * 3) / 10;&lt;br /&gt;
&lt;br /&gt;
  return truncateNumber(AR - ER, 8);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcMainAttackValue(attacker) {&lt;br /&gt;
  var leadership = 0;&lt;br /&gt;
  var rawWeaponAttackValue = 0;&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker)) {&lt;br /&gt;
    var weaponUpgrades = attacker.weapon.upgrades;&lt;br /&gt;
    var maxUpgrade = weaponUpgrades.length - 1;&lt;br /&gt;
&lt;br /&gt;
    if (attacker.hasOwnProperty(&amp;quot;weaponUpgrade&amp;quot;)) {&lt;br /&gt;
      rawWeaponAttackValue =&lt;br /&gt;
        weaponUpgrades[Math.min(attacker.weaponUpgrade, maxUpgrade)];&lt;br /&gt;
&lt;br /&gt;
      // rare bug when weaponUpgrade is deleted&lt;br /&gt;
    } else {&lt;br /&gt;
      console.log(&amp;quot;Warming: weaponUpgrade is missing.&amp;quot;);&lt;br /&gt;
      rawWeaponAttackValue = weaponUpgrades[maxUpgrade];&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    leadership = attacker.leadership;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return 2 * (attacker.level + rawWeaponAttackValue) + leadership;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcStatAttackValue(character) {&lt;br /&gt;
  switch (character.race) {&lt;br /&gt;
    case &amp;quot;warrior&amp;quot;:&lt;br /&gt;
    case &amp;quot;sura&amp;quot;:&lt;br /&gt;
      return 2 * character.str;&lt;br /&gt;
    case &amp;quot;ninja&amp;quot;:&lt;br /&gt;
      return Math.floor((1 / 4) * (character.str + 7 * character.dex));&lt;br /&gt;
    case &amp;quot;shaman&amp;quot;:&lt;br /&gt;
      return Math.floor((1 / 3) * (5 * character.int + character.dex));&lt;br /&gt;
    case &amp;quot;lycan&amp;quot;:&lt;br /&gt;
      return character.vit + 2 * character.dex;&lt;br /&gt;
    default:&lt;br /&gt;
      return 2 * character.str;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcSecondaryAttackValue(attacker) {&lt;br /&gt;
  var attackValueOther = 0;&lt;br /&gt;
&lt;br /&gt;
  var minAttackValue = 0;&lt;br /&gt;
  var maxAttackValue = 0;&lt;br /&gt;
&lt;br /&gt;
  var minAttackValueSlash = 0;&lt;br /&gt;
  var maxAttackValueSlash = 0;&lt;br /&gt;
&lt;br /&gt;
  var attackerWeapon = attacker.weapon;&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker)) {&lt;br /&gt;
    if (attackerWeapon.isSerpent) {&lt;br /&gt;
      var rawAttackValue = attackerWeapon.upgrades[attacker.weaponUpgrade];&lt;br /&gt;
&lt;br /&gt;
      minAttackValue = attacker.minAttackValueRandom - rawAttackValue;&lt;br /&gt;
      maxAttackValue = attacker.maxAttackValueRandom - rawAttackValue;&lt;br /&gt;
&lt;br /&gt;
      minAttackValue = Math.max(0, minAttackValue);&lt;br /&gt;
      maxAttackValue = Math.max(minAttackValue, maxAttackValue);&lt;br /&gt;
    } else {&lt;br /&gt;
      minAttackValue = attackerWeapon.minAttackValue;&lt;br /&gt;
      maxAttackValue = attackerWeapon.maxAttackValue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    minAttackValueSlash = Math.min(&lt;br /&gt;
      attacker.minAttackValueSlash,&lt;br /&gt;
      attacker.maxAttackValueSlash&lt;br /&gt;
    );&lt;br /&gt;
    maxAttackValueSlash = Math.max(&lt;br /&gt;
      attacker.minAttackValueSlash,&lt;br /&gt;
      attacker.maxAttackValueSlash&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    attackValueOther += attacker.attackValue;&lt;br /&gt;
&lt;br /&gt;
    if (isBow(attackerWeapon) &amp;amp;&amp;amp; !isPolymorph(attacker)) {&lt;br /&gt;
      attackValueOther += 25;&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    minAttackValue = attacker.minAttackValue;&lt;br /&gt;
    maxAttackValue = attacker.maxAttackValue;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  minAttackValue += attacker.minAttackValuePolymorph;&lt;br /&gt;
  maxAttackValue += attacker.maxAttackValuePolymorph;&lt;br /&gt;
&lt;br /&gt;
  attackValueOther += attacker.statAttackValue;&lt;br /&gt;
  attackValueOther += attacker.horseAttackValue;&lt;br /&gt;
&lt;br /&gt;
  var weaponInterval = maxAttackValue - minAttackValue + 1;&lt;br /&gt;
  var slashInterval = maxAttackValueSlash - minAttackValueSlash + 1;&lt;br /&gt;
&lt;br /&gt;
  var totalCardinal = weaponInterval * slashInterval * 1_000_000;&lt;br /&gt;
  var minInterval = Math.min(weaponInterval, slashInterval);&lt;br /&gt;
&lt;br /&gt;
  minAttackValue += minAttackValueSlash;&lt;br /&gt;
  maxAttackValue += maxAttackValueSlash;&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    minAttackValue: minAttackValue,&lt;br /&gt;
    maxAttackValue: maxAttackValue,&lt;br /&gt;
    attackValueOther: attackValueOther,&lt;br /&gt;
    totalCardinal: totalCardinal,&lt;br /&gt;
    weights: calcWeights(minAttackValue, maxAttackValue, minInterval),&lt;br /&gt;
    possibleDamagesCount: maxAttackValue - minAttackValue + 1,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcMagicAttackValue(attacker) {&lt;br /&gt;
  var minMagicAttackValue = 0;&lt;br /&gt;
  var maxMagicAttackValue = 0;&lt;br /&gt;
&lt;br /&gt;
  var minMagicAttackValueSlash = 0;&lt;br /&gt;
  var maxMagicAttackValueSlash = 0;&lt;br /&gt;
&lt;br /&gt;
  var attackerWeapon = attacker.weapon;&lt;br /&gt;
&lt;br /&gt;
  if (attackerWeapon.isSerpent) {&lt;br /&gt;
    minMagicAttackValue = attacker.minMagicAttackValueRandom;&lt;br /&gt;
    maxMagicAttackValue = attacker.maxMagicAttackValueRandom;&lt;br /&gt;
&lt;br /&gt;
    maxMagicAttackValue = Math.max(minMagicAttackValue, maxMagicAttackValue);&lt;br /&gt;
  } else {&lt;br /&gt;
    var rawWeaponAttackValue = attackerWeapon.upgrades[attacker.weaponUpgrade];&lt;br /&gt;
&lt;br /&gt;
    if (!rawWeaponAttackValue) {&lt;br /&gt;
      rawWeaponAttackValue = 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    minMagicAttackValue =&lt;br /&gt;
      attackerWeapon.minMagicAttackValue + rawWeaponAttackValue;&lt;br /&gt;
    maxMagicAttackValue =&lt;br /&gt;
      attackerWeapon.maxMagicAttackValue + rawWeaponAttackValue;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  minMagicAttackValueSlash = Math.min(&lt;br /&gt;
    attacker.minMagicAttackValueSlash,&lt;br /&gt;
    attacker.maxMagicAttackValueSlash&lt;br /&gt;
  );&lt;br /&gt;
  maxMagicAttackValueSlash = Math.max(&lt;br /&gt;
    attacker.minMagicAttackValueSlash,&lt;br /&gt;
    attacker.maxMagicAttackValueSlash&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  var weaponInterval = maxMagicAttackValue - minMagicAttackValue + 1;&lt;br /&gt;
  var slashInterval = maxMagicAttackValueSlash - minMagicAttackValueSlash + 1;&lt;br /&gt;
&lt;br /&gt;
  var totalCardinal = weaponInterval * slashInterval * 1_000_000;&lt;br /&gt;
  var minInterval = Math.min(weaponInterval, slashInterval);&lt;br /&gt;
&lt;br /&gt;
  minMagicAttackValue += minMagicAttackValueSlash;&lt;br /&gt;
  maxMagicAttackValue += maxMagicAttackValueSlash;&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    minMagicAttackValue: minMagicAttackValue,&lt;br /&gt;
    maxMagicAttackValue: maxMagicAttackValue,&lt;br /&gt;
    magicAttackValueAugmentation: getMagicAttackValueAugmentation(&lt;br /&gt;
      minMagicAttackValue,&lt;br /&gt;
      maxMagicAttackValue,&lt;br /&gt;
      attacker.magicAttackValue&lt;br /&gt;
    ),&lt;br /&gt;
    totalCardinal: totalCardinal,&lt;br /&gt;
    weights: calcWeights(minMagicAttackValue, maxMagicAttackValue, minInterval),&lt;br /&gt;
    possibleDamagesCount: maxMagicAttackValue - minMagicAttackValue + 1,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getPolymorphPower(polymorphPoint, polymorphPowerTable) {&lt;br /&gt;
  return polymorphPowerTable[polymorphPoint];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSkillPower(skillPoint, skillPowerTable) {&lt;br /&gt;
  return skillPowerTable[skillPoint];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getMarriageBonusValue(character, marriageTable, itemName) {&lt;br /&gt;
  var index;&lt;br /&gt;
  var lovePoint = character.lovePoint;&lt;br /&gt;
&lt;br /&gt;
  if (lovePoint &amp;lt; 65) {&lt;br /&gt;
    index = 0;&lt;br /&gt;
  } else if (lovePoint &amp;lt; 80) {&lt;br /&gt;
    index = 1;&lt;br /&gt;
  } else if (lovePoint &amp;lt; 100) {&lt;br /&gt;
    index = 2;&lt;br /&gt;
  } else {&lt;br /&gt;
    index = 3;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return marriageTable[itemName][index];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcDamageWithPrimaryBonuses(damages, bonusValues) {&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.attackValueCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  damages += bonusValues.attackValueMarriage;&lt;br /&gt;
&lt;br /&gt;
  damages = Math.floor(&lt;br /&gt;
    (damages * bonusValues.monsterResistanceMarriageCoeff) / 100&lt;br /&gt;
  );&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.monsterResistanceCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  damages += Math.floor((damages * bonusValues.typeBonusCoeff) / 100);&lt;br /&gt;
  damages +=&lt;br /&gt;
    Math.floor((damages * bonusValues.raceBonusCoeff) / 100) -&lt;br /&gt;
    Math.floor((damages * bonusValues.raceResistanceCoeff) / 100);&lt;br /&gt;
  damages += Math.floor((damages * bonusValues.stoneBonusCoeff) / 100);&lt;br /&gt;
  damages += Math.floor((damages * bonusValues.monsterBonusCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  var elementBonusCoeff = bonusValues.elementBonusCoeff;&lt;br /&gt;
&lt;br /&gt;
  damages +=&lt;br /&gt;
    Math.trunc((damages * elementBonusCoeff[0]) / 10000) +&lt;br /&gt;
    Math.trunc((damages * elementBonusCoeff[1]) / 10000) +&lt;br /&gt;
    Math.trunc((damages * elementBonusCoeff[2]) / 10000) +&lt;br /&gt;
    Math.trunc((damages * elementBonusCoeff[3]) / 10000) +&lt;br /&gt;
    Math.trunc((damages * elementBonusCoeff[4]) / 10000) +&lt;br /&gt;
    Math.trunc((damages * elementBonusCoeff[5]) / 10000);&lt;br /&gt;
&lt;br /&gt;
  damages = Math.floor(damages * bonusValues.damageMultiplier);&lt;br /&gt;
&lt;br /&gt;
  return damages;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcDamageWithSecondaryBonuses(&lt;br /&gt;
  damages,&lt;br /&gt;
  bonusValues,&lt;br /&gt;
  damagesType,&lt;br /&gt;
  minPiercingDamages,&lt;br /&gt;
  damagesWithPrimaryBonuses&lt;br /&gt;
) {&lt;br /&gt;
  damages = Math.floor(damages * bonusValues.magicResistanceCoeff);&lt;br /&gt;
  damages = Math.trunc((damages * bonusValues.weaponDefenseCoeff) / 100);&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.tigerStrengthCoeff) / 100);&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.blessingBonusCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  if (damagesType.criticalHit) {&lt;br /&gt;
    damages *= 2;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (damagesType.piercingHit) {&lt;br /&gt;
    damages += bonusValues.defenseBoost + Math.min(0, minPiercingDamages);&lt;br /&gt;
    damages += Math.floor(&lt;br /&gt;
      (damagesWithPrimaryBonuses * bonusValues.extraPiercingHitCoeff) / 1000&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.averageDamageCoeff) / 100);&lt;br /&gt;
  damages = Math.floor(&lt;br /&gt;
    (damages * bonusValues.averageDamageResistanceCoeff) / 100&lt;br /&gt;
  );&lt;br /&gt;
  damages = Math.floor(&lt;br /&gt;
    (damages * bonusValues.skillDamageResistanceCoeff) / 100&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.rankBonusCoeff) / 100);&lt;br /&gt;
  damages = Math.max(0, damages + bonusValues.defensePercent);&lt;br /&gt;
  damages += Math.min(&lt;br /&gt;
    300,&lt;br /&gt;
    Math.floor((damages * bonusValues.damageBonusCoeff) / 100)&lt;br /&gt;
  );&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.empireMalusCoeff) / 10);&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.sungMaStrBonusCoeff) / 10000);&lt;br /&gt;
  damages -= Math.floor(damages * bonusValues.sungmaStrMalusCoeff);&lt;br /&gt;
&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.whiteDragonElixirCoeff) / 100);&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.steelDragonElixirCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  return damages;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcSkillDamageWithSecondaryBonuses(&lt;br /&gt;
  damages,&lt;br /&gt;
  bonusValues,&lt;br /&gt;
  damagesType,&lt;br /&gt;
  minPiercingDamages&lt;br /&gt;
) {&lt;br /&gt;
  damages = Math.floor(damages * bonusValues.magicResistanceCoeff);&lt;br /&gt;
  damages = Math.trunc((damages * bonusValues.weaponDefenseCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  damages -= bonusValues.defense;&lt;br /&gt;
&lt;br /&gt;
  damages = floorMultiplication(damages, bonusValues.skillWardCoeff);&lt;br /&gt;
  damages = floorMultiplication(damages, bonusValues.skillBonusCoeff);&lt;br /&gt;
&lt;br /&gt;
  var tempDamages = Math.floor(&lt;br /&gt;
    (damages * bonusValues.skillBonusByBonusCoeff) / 100&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  damages = Math.floor(&lt;br /&gt;
    (tempDamages * bonusValues.magicAttackValueCoeff) / 100 + 0.5&lt;br /&gt;
  );&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.tigerStrengthCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  if (damagesType.criticalHit) {&lt;br /&gt;
    damages *= 2;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (damagesType.piercingHit) {&lt;br /&gt;
    damages += bonusValues.defenseBoost + Math.min(0, minPiercingDamages);&lt;br /&gt;
    damages += Math.floor(&lt;br /&gt;
      (tempDamages * bonusValues.extraPiercingHitCoeff) / 1000&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.skillDamageCoeff) / 100);&lt;br /&gt;
  damages = Math.floor(&lt;br /&gt;
    (damages * bonusValues.skillDamageResistanceCoeff) / 100&lt;br /&gt;
  );&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.rankBonusCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  damages = Math.max(0, damages + bonusValues.defensePercent);&lt;br /&gt;
  damages += Math.min(&lt;br /&gt;
    300,&lt;br /&gt;
    Math.floor((damages * bonusValues.damageBonusCoeff) / 100)&lt;br /&gt;
  );&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.empireMalusCoeff) / 10);&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.sungMaStrBonusCoeff) / 10000);&lt;br /&gt;
  damages -= Math.floor(damages * bonusValues.sungmaStrMalusCoeff);&lt;br /&gt;
&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.whiteDragonElixirCoeff) / 100);&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.steelDragonElixirCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  return damages;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function computePolymorphPoint(attacker, victim, polymorphPowerTable) {&lt;br /&gt;
  attacker.statAttackValue = 0;&lt;br /&gt;
&lt;br /&gt;
  attacker.polymorphDex = attacker.dex;&lt;br /&gt;
  victim.polymorphDex = victim.dex;&lt;br /&gt;
&lt;br /&gt;
  attacker.minAttackValuePolymorph = 0;&lt;br /&gt;
  attacker.maxAttackValuePolymorph = 0;&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker) &amp;amp;&amp;amp; isPolymorph(attacker)) {&lt;br /&gt;
    var polymorphPowerPct =&lt;br /&gt;
      getPolymorphPower(attacker.polymorphPoint, polymorphPowerTable) / 100;&lt;br /&gt;
    var polymorphMonster = createMonster(attacker.polymorphMonster);&lt;br /&gt;
&lt;br /&gt;
    var polymorphStr = floorMultiplication(&lt;br /&gt;
      polymorphPowerPct,&lt;br /&gt;
      polymorphMonster.str&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    attacker.polymorphDex += floorMultiplication(&lt;br /&gt;
      polymorphPowerPct,&lt;br /&gt;
      polymorphMonster.dex&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    attacker.minAttackValuePolymorph = floorMultiplication(&lt;br /&gt;
      polymorphPowerPct,&lt;br /&gt;
      polymorphMonster.minAttackValue&lt;br /&gt;
    );&lt;br /&gt;
    attacker.maxAttackValuePolymorph = floorMultiplication(&lt;br /&gt;
      polymorphPowerPct,&lt;br /&gt;
      polymorphMonster.maxAttackValue&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    if (!attacker.weapon) {&lt;br /&gt;
      attacker.maxAttackValuePolymorph += 1;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    attacker.attackValue = 0;&lt;br /&gt;
&lt;br /&gt;
    if (isMagicClass(attacker)) {&lt;br /&gt;
      attacker.statAttackValue = 2 * (polymorphStr + attacker.int);&lt;br /&gt;
    } else {&lt;br /&gt;
      attacker.statAttackValue = 2 * (polymorphStr + attacker.str);&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    attacker.statAttackValue = calcStatAttackValue(attacker);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function computeHorse(attacker) {&lt;br /&gt;
  attacker.horseAttackValue = 0;&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker) &amp;amp;&amp;amp; isRiding(attacker)) {&lt;br /&gt;
    var horseConstant = 30;&lt;br /&gt;
&lt;br /&gt;
    if (attacker.class === &amp;quot;weaponary&amp;quot;) {&lt;br /&gt;
      horseConstant = 60;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    attacker.horseAttackValue = floorMultiplication(&lt;br /&gt;
      2 * attacker.level + attacker.statAttackValue,&lt;br /&gt;
      attacker.horsePoint / horseConstant&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getRankBonus(attacker) {&lt;br /&gt;
  if (!isChecked(attacker.lowRank)) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  switch (attacker.playerRank) {&lt;br /&gt;
    case &amp;quot;aggressive&amp;quot;:&lt;br /&gt;
      return 1;&lt;br /&gt;
    case &amp;quot;fraudulent&amp;quot;:&lt;br /&gt;
      return 2;&lt;br /&gt;
    case &amp;quot;malicious&amp;quot;:&lt;br /&gt;
      return 3;&lt;br /&gt;
    case &amp;quot;cruel&amp;quot;:&lt;br /&gt;
      return 5;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcElementCoeffPvP(elementBonus, mapping, attacker, victim) {&lt;br /&gt;
  var minElementMalus = 0;&lt;br /&gt;
  var maxDifference = 0;&lt;br /&gt;
  var savedElementDifferences = [];&lt;br /&gt;
  var elementBonusIndex = 0;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; elementBonus.length; index++) {&lt;br /&gt;
    if (!attacker[mapping.elementBonus[index]]) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var elementDifference =&lt;br /&gt;
      attacker[mapping.elementBonus[index]] -&lt;br /&gt;
      victim[mapping.elementResistance[index]];&lt;br /&gt;
&lt;br /&gt;
    if (elementDifference &amp;gt;= 0) {&lt;br /&gt;
      elementBonus[elementBonusIndex] = 10 * elementDifference;&lt;br /&gt;
      minElementMalus -= elementDifference;&lt;br /&gt;
      maxDifference = Math.max(maxDifference, elementDifference);&lt;br /&gt;
      elementBonusIndex++;&lt;br /&gt;
    } else {&lt;br /&gt;
      savedElementDifferences.push(elementDifference);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (!savedElementDifferences.length) {&lt;br /&gt;
    return;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  minElementMalus += maxDifference;&lt;br /&gt;
  savedElementDifferences.sort(compareNumbers);&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; savedElementDifferences.length; index++) {&lt;br /&gt;
    var elementDifference = savedElementDifferences[index];&lt;br /&gt;
&lt;br /&gt;
    elementBonus[elementBonusIndex + index] =&lt;br /&gt;
      10 * Math.max(minElementMalus, elementDifference);&lt;br /&gt;
&lt;br /&gt;
    minElementMalus = Math.min(&lt;br /&gt;
      0,&lt;br /&gt;
      Math.max(minElementMalus, minElementMalus - elementDifference)&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function skillChanceReduction(value) {&lt;br /&gt;
  if (value &amp;lt;= 9) {&lt;br /&gt;
    return Math.floor(value / 2);&lt;br /&gt;
  }&lt;br /&gt;
  return 5 + Math.floor((value - 10) / 4);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function magicResistanceToCoeff(magicResistance) {&lt;br /&gt;
  if (magicResistance) {&lt;br /&gt;
    return 2000 / (6 * magicResistance + 1000) - 1;&lt;br /&gt;
  }&lt;br /&gt;
  return 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createBattleValues(attacker, victim, battle, skillType) {&lt;br /&gt;
  var { mapping, constants } = battle;&lt;br /&gt;
  var calcAttackValues;&lt;br /&gt;
&lt;br /&gt;
  var missPercentage = 0;&lt;br /&gt;
  var attackValueMeleeMagic = 0;&lt;br /&gt;
  var attackValueMarriage = 0;&lt;br /&gt;
  var monsterResistanceMarriage = 0;&lt;br /&gt;
  var monsterResistance = 0;&lt;br /&gt;
  var typeBonus = 0;&lt;br /&gt;
  var raceBonus = 0;&lt;br /&gt;
  var raceResistance = 0;&lt;br /&gt;
  var stoneBonus = 0;&lt;br /&gt;
  var monsterBonus = 0;&lt;br /&gt;
  var elementBonus = [0, 0, 0, 0, 0, 0]; // fire, ice, lightning, earth, darkness, wind, order doesn't matter&lt;br /&gt;
  var defenseMarriage = 0;&lt;br /&gt;
  var damageMultiplier = 1;&lt;br /&gt;
  var useDamages = 1;&lt;br /&gt;
  var defense = victim.defense;&lt;br /&gt;
  var defenseBoost = defense;&lt;br /&gt;
  var magicResistance = 0;&lt;br /&gt;
  var weaponDefense = 0;&lt;br /&gt;
  var tigerStrength = 0;&lt;br /&gt;
  var blessingBonus = 0;&lt;br /&gt;
  var magicAttackValueMeleeMagic = 0;&lt;br /&gt;
  var criticalHitPercentage = attacker.criticalHit;&lt;br /&gt;
  var piercingHitPercentage = attacker.piercingHit;&lt;br /&gt;
  var extraPiercingHitPercentage = Math.max(0, piercingHitPercentage - 100);&lt;br /&gt;
  var averageDamage = 0;&lt;br /&gt;
  var averageDamageResistance = 0;&lt;br /&gt;
  var skillDamage = 0;&lt;br /&gt;
  var skillDamageResistance = 0;&lt;br /&gt;
  var rankBonus = 0;&lt;br /&gt;
  var defensePercent = 0;&lt;br /&gt;
  var damageBonus = 0;&lt;br /&gt;
  var empireMalus = 0;&lt;br /&gt;
  var sungMaStrBonus = 0;&lt;br /&gt;
  var sungmaStrMalus = 0;&lt;br /&gt;
  var whiteDragonElixir = 0;&lt;br /&gt;
  var steelDragonElixir = 0;&lt;br /&gt;
&lt;br /&gt;
  computePolymorphPoint(attacker, victim, constants.polymorphPowerTable);&lt;br /&gt;
  computeHorse(attacker);&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker)) {&lt;br /&gt;
    if (weaponData.hasOwnProperty(attacker.weapon)) {&lt;br /&gt;
      attacker.weapon = createWeapon(attacker.weapon);&lt;br /&gt;
    } else {&lt;br /&gt;
      attacker.weapon = createWeapon(0);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    attackValueMeleeMagic =&lt;br /&gt;
      attacker.attackValuePercent + Math.min(100, attacker.attackMeleeMagic);&lt;br /&gt;
&lt;br /&gt;
    var weaponType = attacker.weapon.type;&lt;br /&gt;
&lt;br /&gt;
    if (skillType &amp;amp;&amp;amp; attacker.class === &amp;quot;archery&amp;quot;) {&lt;br /&gt;
      if (weaponType !== 2) {&lt;br /&gt;
        useDamages = 0;&lt;br /&gt;
        weaponType = 2;&lt;br /&gt;
      }&lt;br /&gt;
      defense = 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var weaponDefenseName = mapping.defenseWeapon[weaponType];&lt;br /&gt;
    var weaponDefenseBreakName = mapping.breakWeapon[weaponType];&lt;br /&gt;
&lt;br /&gt;
    if (victim.hasOwnProperty(weaponDefenseName)) {&lt;br /&gt;
      weaponDefense = victim[weaponDefenseName];&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isChecked(attacker.whiteDragonElixir)) {&lt;br /&gt;
      whiteDragonElixir = 10;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isPC(victim)) {&lt;br /&gt;
      if (!skillType) {&lt;br /&gt;
        if (weaponType === 2 &amp;amp;&amp;amp; !isPolymorph(attacker)) {&lt;br /&gt;
          missPercentage = victim.arrowBlock;&lt;br /&gt;
        } else {&lt;br /&gt;
          missPercentage = victim.meleeBlock;&lt;br /&gt;
        }&lt;br /&gt;
        missPercentage +=&lt;br /&gt;
          victim.meleeArrowBlock -&lt;br /&gt;
          (missPercentage * victim.meleeArrowBlock) / 100;&lt;br /&gt;
&lt;br /&gt;
        blessingBonus = calcBlessingBonus(constants.skillPowerTable, victim);&lt;br /&gt;
        averageDamageResistance = victim.averageDamageResistance;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      typeBonus = Math.max(1, attacker.humanBonus - victim.humanResistance);&lt;br /&gt;
      raceBonus = attacker[mapping.raceBonus[victim.race]];&lt;br /&gt;
      raceResistance = victim[mapping.raceResistance[attacker.race]];&lt;br /&gt;
&lt;br /&gt;
      calcElementCoeffPvP(elementBonus, mapping, attacker, victim);&lt;br /&gt;
&lt;br /&gt;
      if (weaponType !== 2 &amp;amp;&amp;amp; attacker.hasOwnProperty(weaponDefenseBreakName)) {&lt;br /&gt;
        weaponDefense -= attacker[weaponDefenseBreakName];&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      criticalHitPercentage = 0;&lt;br /&gt;
    } else {&lt;br /&gt;
      if (isChecked(attacker.isMarried)) {&lt;br /&gt;
        if (isChecked(attacker.loveNecklace)) {&lt;br /&gt;
          attackValueMarriage = getMarriageBonusValue(&lt;br /&gt;
            attacker,&lt;br /&gt;
            constants.marriageTable,&lt;br /&gt;
            &amp;quot;loveNecklace&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isChecked(attacker.loveEarrings)) {&lt;br /&gt;
          criticalHitPercentage += getMarriageBonusValue(&lt;br /&gt;
            attacker,&lt;br /&gt;
            constants.marriageTable,&lt;br /&gt;
            &amp;quot;loveEarrings&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isChecked(attacker.harmonyEarrings)) {&lt;br /&gt;
          piercingHitPercentage += getMarriageBonusValue(&lt;br /&gt;
            attacker,&lt;br /&gt;
            constants.marriageTable,&lt;br /&gt;
            &amp;quot;harmonyEarrings&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (isChecked(attacker.tigerStrength)) {&lt;br /&gt;
        tigerStrength = 40;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      for (var index = 0; index &amp;lt; elementBonus.length; index++) {&lt;br /&gt;
        var elementBonusName = mapping.elementBonus[index];&lt;br /&gt;
        var elementResistanceName = mapping.elementResistance[index];&lt;br /&gt;
&lt;br /&gt;
        if (attacker[elementBonusName] &amp;amp;&amp;amp; victim[elementBonusName]) {&lt;br /&gt;
          elementBonus[index] =&lt;br /&gt;
            50 * (attacker[elementBonusName] - victim[elementResistanceName]);&lt;br /&gt;
        } else {&lt;br /&gt;
          elementBonus[index] = 5 * attacker[elementBonusName];&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      var victimType = victim.type;&lt;br /&gt;
&lt;br /&gt;
      if (victimType !== -1) {&lt;br /&gt;
        typeBonus = attacker[mapping.typeFlag[victimType]];&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      monsterBonus = attacker.monsterBonus;&lt;br /&gt;
&lt;br /&gt;
      if (isStone(victim)) {&lt;br /&gt;
        stoneBonus = attacker.stoneBonus;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (isBoss(victim)) {&lt;br /&gt;
        if (skillType) {&lt;br /&gt;
          skillDamage += attacker.skillBossDamage;&lt;br /&gt;
        } else {&lt;br /&gt;
          averageDamage += attacker.bossDamage;&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (isChecked(attacker.onYohara)) {&lt;br /&gt;
        var sungmaStrDifference = attacker.sungmaStr - attacker.sungmaStrMalus;&lt;br /&gt;
&lt;br /&gt;
        if (sungmaStrDifference &amp;gt;= 0) {&lt;br /&gt;
          sungMaStrBonus = sungmaStrDifference;&lt;br /&gt;
        } else {&lt;br /&gt;
          sungmaStrMalus = 0.5;&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (skillType) {&lt;br /&gt;
      skillDamage += attacker.skillDamage;&lt;br /&gt;
    } else {&lt;br /&gt;
      averageDamage += attacker.averageDamage;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    rankBonus = getRankBonus(attacker);&lt;br /&gt;
    damageBonus = attacker.damageBonus;&lt;br /&gt;
&lt;br /&gt;
    if (isChecked(attacker.empireMalus)) {&lt;br /&gt;
      empireMalus = 1;&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    if (isPC(victim)) {&lt;br /&gt;
      if (isChecked(victim.isMarried)) {&lt;br /&gt;
        if (isChecked(victim.harmonyBracelet)) {&lt;br /&gt;
          monsterResistanceMarriage = getMarriageBonusValue(&lt;br /&gt;
            victim,&lt;br /&gt;
            constants.marriageTable,&lt;br /&gt;
            &amp;quot;harmonyBracelet&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isChecked(victim.harmonyNecklace) &amp;amp;&amp;amp; !skillType) {&lt;br /&gt;
          defenseMarriage = getMarriageBonusValue(&lt;br /&gt;
            victim,&lt;br /&gt;
            constants.marriageTable,&lt;br /&gt;
            &amp;quot;harmonyNecklace&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      monsterResistance = victim.monsterResistance;&lt;br /&gt;
&lt;br /&gt;
      for (var index = 0; index &amp;lt; elementBonus.length; index++) {&lt;br /&gt;
        var elementBonusName = mapping.elementBonus[index];&lt;br /&gt;
        var elementResistanceName = mapping.elementResistance[index];&lt;br /&gt;
&lt;br /&gt;
        if (attacker[elementBonusName]) {&lt;br /&gt;
          elementBonus[index] =&lt;br /&gt;
            80 * (attacker[elementBonusName] - victim[elementResistanceName]);&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (!skillType) {&lt;br /&gt;
        if (isMeleeAttacker(attacker)) {&lt;br /&gt;
          missPercentage = victim.meleeBlock;&lt;br /&gt;
          averageDamageResistance = victim.averageDamageResistance;&lt;br /&gt;
          blessingBonus = calcBlessingBonus(constants.skillPowerTable, victim);&lt;br /&gt;
        } else if (isRangeAttacker(attacker)) {&lt;br /&gt;
          missPercentage = victim.arrowBlock;&lt;br /&gt;
          weaponDefense = victim.arrowDefense;&lt;br /&gt;
          averageDamageResistance = victim.averageDamageResistance;&lt;br /&gt;
          blessingBonus = calcBlessingBonus(constants.skillPowerTable, victim);&lt;br /&gt;
        } else if (isMagicAttacker(attacker)) {&lt;br /&gt;
          missPercentage = victim.arrowBlock;&lt;br /&gt;
          skillDamageResistance = victim.skillDamageResistance;&lt;br /&gt;
          magicResistance = victim.magicResistance;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        missPercentage +=&lt;br /&gt;
          victim.meleeArrowBlock -&lt;br /&gt;
          (missPercentage * victim.meleeArrowBlock) / 100;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    typeBonus = 1;&lt;br /&gt;
    damageMultiplier = attacker.damageMultiplier;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillType) {&lt;br /&gt;
    criticalHitPercentage = skillChanceReduction(criticalHitPercentage);&lt;br /&gt;
    piercingHitPercentage = skillChanceReduction(piercingHitPercentage);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (isPC(victim)) {&lt;br /&gt;
    if (!skillType &amp;amp;&amp;amp; isChecked(victim.biologist70)) {&lt;br /&gt;
      defenseBoost = Math.floor((defenseBoost * 110) / 100);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    criticalHitPercentage = Math.max(&lt;br /&gt;
      0,&lt;br /&gt;
      criticalHitPercentage - victim.criticalHitResistance&lt;br /&gt;
    );&lt;br /&gt;
    piercingHitPercentage = Math.max(&lt;br /&gt;
      0,&lt;br /&gt;
      piercingHitPercentage - victim.piercingHitResistance&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    if (skillType) {&lt;br /&gt;
      skillDamageResistance = victim.skillDamageResistance;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isMagicClass(victim)) {&lt;br /&gt;
      defensePercent = (-2 * victim.magicDefense * victim.defensePercent) / 100;&lt;br /&gt;
    } else {&lt;br /&gt;
      defensePercent = (-2 * defenseBoost * victim.defensePercent) / 100;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isChecked(victim.steelDragonElixir)) {&lt;br /&gt;
      steelDragonElixir = 10;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillType === &amp;quot;magic&amp;quot;) {&lt;br /&gt;
    attackValueMeleeMagic = 0;&lt;br /&gt;
    magicAttackValueMeleeMagic =&lt;br /&gt;
      attacker.attackMagic + Math.min(100, attacker.attackMeleeMagic);&lt;br /&gt;
    attackValueMarriage = 0;&lt;br /&gt;
    defense = 0;&lt;br /&gt;
    if (!isDispell(attacker, 6)) {&lt;br /&gt;
      magicResistance = victim.magicResistance;&lt;br /&gt;
    }&lt;br /&gt;
    weaponDefense = 0;&lt;br /&gt;
    calcAttackValues = calcMagicAttackValue;&lt;br /&gt;
  } else {&lt;br /&gt;
    calcAttackValues = calcSecondaryAttackValue;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  missPercentage = Math.min(100, missPercentage);&lt;br /&gt;
&lt;br /&gt;
  var bonusValues = {&lt;br /&gt;
    missPercentage: missPercentage,&lt;br /&gt;
    weaponBonusCoeff: 1,&lt;br /&gt;
    attackValueCoeff: 100 + attackValueMeleeMagic,&lt;br /&gt;
    attackValueMarriage: attackValueMarriage,&lt;br /&gt;
    monsterResistanceMarriageCoeff: 100 - monsterResistanceMarriage,&lt;br /&gt;
    monsterResistanceCoeff: 100 - monsterResistance,&lt;br /&gt;
    typeBonusCoeff: typeBonus,&lt;br /&gt;
    raceBonusCoeff: raceBonus,&lt;br /&gt;
    raceResistanceCoeff: raceResistance,&lt;br /&gt;
    stoneBonusCoeff: stoneBonus,&lt;br /&gt;
    monsterBonusCoeff: monsterBonus,&lt;br /&gt;
    elementBonusCoeff: elementBonus,&lt;br /&gt;
    damageMultiplier: damageMultiplier,&lt;br /&gt;
    useDamages: useDamages,&lt;br /&gt;
    defense: defense,&lt;br /&gt;
    defenseBoost: defenseBoost,&lt;br /&gt;
    defenseMarriage: defenseMarriage,&lt;br /&gt;
    tigerStrengthCoeff: 100 + tigerStrength,&lt;br /&gt;
    magicResistanceCoeff: magicResistanceToCoeff(magicResistance),&lt;br /&gt;
    weaponDefenseCoeff: 100 - weaponDefense,&lt;br /&gt;
    blessingBonusCoeff: 100 - blessingBonus,&lt;br /&gt;
    magicAttackValueCoeff: 100 + magicAttackValueMeleeMagic,&lt;br /&gt;
    extraPiercingHitCoeff: 5 * extraPiercingHitPercentage,&lt;br /&gt;
    averageDamageCoeff: 100 + averageDamage,&lt;br /&gt;
    averageDamageResistanceCoeff: 100 - Math.min(99, averageDamageResistance),&lt;br /&gt;
    skillDamageCoeff: 100 + skillDamage,&lt;br /&gt;
    skillDamageResistanceCoeff: 100 - Math.min(99, skillDamageResistance),&lt;br /&gt;
    rankBonusCoeff: 100 + rankBonus,&lt;br /&gt;
    defensePercent: Math.floor(defensePercent),&lt;br /&gt;
    damageBonusCoeff: damageBonus,&lt;br /&gt;
    empireMalusCoeff: 10 - empireMalus,&lt;br /&gt;
    sungMaStrBonusCoeff: 10000 + sungMaStrBonus,&lt;br /&gt;
    sungmaStrMalusCoeff: sungmaStrMalus,&lt;br /&gt;
    whiteDragonElixirCoeff: 100 + whiteDragonElixir,&lt;br /&gt;
    steelDragonElixirCoeff: 100 - steelDragonElixir,&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  criticalHitPercentage = Math.min(criticalHitPercentage, 100);&lt;br /&gt;
  piercingHitPercentage = Math.min(piercingHitPercentage, 100);&lt;br /&gt;
&lt;br /&gt;
  var damagesTypeCombinaison = [&lt;br /&gt;
    {&lt;br /&gt;
      criticalHit: false,&lt;br /&gt;
      piercingHit: false,&lt;br /&gt;
      weight:&lt;br /&gt;
        (100 - criticalHitPercentage) *&lt;br /&gt;
        (100 - piercingHitPercentage) *&lt;br /&gt;
        (100 - missPercentage),&lt;br /&gt;
      name: &amp;quot;normalHit&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      criticalHit: true,&lt;br /&gt;
      piercingHit: false,&lt;br /&gt;
      weight:&lt;br /&gt;
        criticalHitPercentage *&lt;br /&gt;
        (100 - piercingHitPercentage) *&lt;br /&gt;
        (100 - missPercentage),&lt;br /&gt;
      name: &amp;quot;criticalHit&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      criticalHit: false,&lt;br /&gt;
      piercingHit: true,&lt;br /&gt;
      weight:&lt;br /&gt;
        (100 - criticalHitPercentage) *&lt;br /&gt;
        piercingHitPercentage *&lt;br /&gt;
        (100 - missPercentage),&lt;br /&gt;
      name: &amp;quot;piercingHit&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      criticalHit: true,&lt;br /&gt;
      piercingHit: true,&lt;br /&gt;
      weight:&lt;br /&gt;
        criticalHitPercentage * piercingHitPercentage * (100 - missPercentage),&lt;br /&gt;
      name: &amp;quot;criticalPiercingHit&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
  ];&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    attacker: attacker,&lt;br /&gt;
    victim: victim,&lt;br /&gt;
    attackFactor: calcAttackFactor(attacker, victim),&lt;br /&gt;
    mainAttackValue: calcMainAttackValue(attacker),&lt;br /&gt;
    attackValues: calcAttackValues(attacker),&lt;br /&gt;
    bonusValues: bonusValues,&lt;br /&gt;
    damagesTypeCombinaison: damagesTypeCombinaison,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateBattleValues(battleValues, skillFormula, skillInfo) {&lt;br /&gt;
  var weaponBonus = 0;&lt;br /&gt;
  var skillWard = 0;&lt;br /&gt;
  var skillBonus = 0;&lt;br /&gt;
  var skillBonusByBonus = 0;&lt;br /&gt;
  var { attacker: attacker, bonusValues: bonusValues } = battleValues;&lt;br /&gt;
  var {&lt;br /&gt;
    range: [minVariation, maxVariation],&lt;br /&gt;
  } = skillInfo;&lt;br /&gt;
  var variationLength = maxVariation - minVariation + 1;&lt;br /&gt;
&lt;br /&gt;
  if (skillInfo.hasOwnProperty(&amp;quot;weaponBonus&amp;quot;)) {&lt;br /&gt;
    var [weaponType, weaponBonusValue] = skillInfo.weaponBonus;&lt;br /&gt;
&lt;br /&gt;
    if (weaponType === attacker.weapon.type) {&lt;br /&gt;
      weaponBonus = weaponBonusValue;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillInfo.skillBonus) {&lt;br /&gt;
    skillBonus = skillInfo.skillBonus;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillInfo.skillWard) {&lt;br /&gt;
    skillWard = skillInfo.skillWard;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillInfo.skillBonusByBonus) {&lt;br /&gt;
    skillBonusByBonus = skillInfo.skillBonusByBonus;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillInfo.removeWeaponReduction) {&lt;br /&gt;
    bonusValues.weaponDefenseCoeff = 100;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  bonusValues.weaponBonusCoeff = 100 + weaponBonus;&lt;br /&gt;
  bonusValues.skillWardCoeff = 1 - skillWard / 100;&lt;br /&gt;
  bonusValues.skillBonusCoeff = 1 + skillBonus / 100;&lt;br /&gt;
  bonusValues.skillBonusByBonusCoeff = 100 + skillBonusByBonus;&lt;br /&gt;
&lt;br /&gt;
  battleValues.skillFormula = skillFormula;&lt;br /&gt;
  battleValues.skillRange = skillInfo.range;&lt;br /&gt;
  battleValues.attackValues.totalCardinal *= variationLength;&lt;br /&gt;
  battleValues.attackValues.possibleDamagesCount *= variationLength;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcWeights(minValue, maxValue, minInterval) {&lt;br /&gt;
  var firstWeightLimit = minValue + minInterval - 1;&lt;br /&gt;
  var lastWeightsLimit = maxValue - minInterval + 1;&lt;br /&gt;
  var weights = [];&lt;br /&gt;
&lt;br /&gt;
  for (var value = minValue; value &amp;lt; firstWeightLimit; value++) {&lt;br /&gt;
    weights.push(value - minValue + 1);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (var value = firstWeightLimit; value &amp;lt;= lastWeightsLimit; value++) {&lt;br /&gt;
    weights.push(minInterval);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (var value = lastWeightsLimit + 1; value &amp;lt;= maxValue; value++) {&lt;br /&gt;
    weights.push(maxValue - value + 1);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return weights;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcBlessingBonus(skillPowerTable, victim) {&lt;br /&gt;
  if (!isChecked(victim.isBlessed)) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var int = victim.intBlessing;&lt;br /&gt;
  var dex = victim.dexBlessing;&lt;br /&gt;
  var skillPower = getSkillPower(victim[&amp;quot;skillBlessing&amp;quot;], skillPowerTable);&lt;br /&gt;
&lt;br /&gt;
  if (!skillPower) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var blessingBonus = floorMultiplication(&lt;br /&gt;
    ((int * 0.3 + 5) * (2 * skillPower + 0.5) + 0.3 * dex) / (skillPower + 2.3),&lt;br /&gt;
    1&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  if (victim.class === &amp;quot;dragon&amp;quot; &amp;amp;&amp;amp; isChecked(ictim.blessingOnself)) {&lt;br /&gt;
    blessingBonus = floorMultiplication(blessingBonus, 1.1);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return blessingBonus;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSkillFormula(battle, skillId, battleValues, removeSkillVariation) {&lt;br /&gt;
  var { attacker, victim, attackFactor } = battleValues;&lt;br /&gt;
  var skillPowerTable = battle.constants.skillPowerTable;&lt;br /&gt;
&lt;br /&gt;
  var skillFormula;&lt;br /&gt;
  var skillInfo = { range: [0, 0] };&lt;br /&gt;
&lt;br /&gt;
  var { class: attackerClass, level: lv, vit, str, int, dex } = attacker;&lt;br /&gt;
&lt;br /&gt;
  if (skillId &amp;lt;= 9) {&lt;br /&gt;
    var skillPower = getSkillPower(&lt;br /&gt;
      attacker[&amp;quot;attackSkill&amp;quot; + skillId],&lt;br /&gt;
      skillPowerTable&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    var improvedBySkillBonus = false;&lt;br /&gt;
    var improvedByBonus = false;&lt;br /&gt;
&lt;br /&gt;
    if (attackerClass === &amp;quot;body&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Triple lacération&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.1 * atk + (0.5 * atk + 1.5 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Moulinet à l'épée&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              3 * atk + (0.8 * atk + 5 * str + 3 * dex + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Accélération&lt;br /&gt;
        case 5:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * atk + (atk + dex * 3 + str * 7 + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Volonté de vivre&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              (3 * atk + (atk + 1.5 * str) * skillPower) * 1.07,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          break;&lt;br /&gt;
        // Tremblement de terre&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              3 * atk +&lt;br /&gt;
                (0.9 * atk + variation + 5 * str + 3 * dex + lv) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;mental&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Attaque de l'esprit&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2.3 * atk + (4 * atk + 4 * str + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Attaque de la paume&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2.3 * atk + (3 * atk + 4 * str + 3 * vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Charge&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * atk + (2 * atk + 2 * dex + 2 * vit + 4 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          break;&lt;br /&gt;
        // Coup d'épée&lt;br /&gt;
        case 5:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * atk + (atk + 3 * dex + 5 * str + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Orbe de l'épée&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              (2 * atk + (2 * atk + 2 * dex + 2 * vit + 4 * str) * skillPower) *&lt;br /&gt;
                1.1,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          break;&lt;br /&gt;
        // Tremblement de terre&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              3 * atk +&lt;br /&gt;
                (0.9 * atk + variation + 5 * str + 3 * dex + lv) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;blade_fight&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Embuscade&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk + (1.2 * atk + variation + 4 * dex + 4 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [1, 50];&lt;br /&gt;
          skillInfo.range = [500, 700];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Attaque rapide&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk + (1.6 * atk + variation + 7 * dex + 7 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [1, 35];&lt;br /&gt;
          skillInfo.range = [200, 300];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Dague filante&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * atk + (0.5 * atk + 9 * dex + 7 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Brume empoisonnée&lt;br /&gt;
        case 5:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * lv + (atk + 3 * str + 18 * dex) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Poison insidieux&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              (2 * lv + (atk + 3 * str + 18 * dex) * skillPower) * 1.1,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          break;&lt;br /&gt;
        // Étoiles brillantes&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk + (1.7 * atk + variation + 6 * dex + 5 * lv) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;archery&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Tir à répétition&lt;br /&gt;
        // case 1:&lt;br /&gt;
        //   skillFormula = function (atk) {&lt;br /&gt;
        //     return floorMultiplication(&lt;br /&gt;
        //       atk + 0.2 * atk * Math.floor(2 + 6 * skillPower) + (0.8 * atk + 8 * dex * attackFactor + 2 * int) * skillPower,&lt;br /&gt;
        //       1&lt;br /&gt;
        //     );&lt;br /&gt;
        //   };&lt;br /&gt;
        //   improvedByBonus = true;&lt;br /&gt;
        //   break;&lt;br /&gt;
        // Pluie de flèches&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk + (1.7 * atk + 5 * dex + str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Flèche de feu&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.5 * atk + (2.6 * atk + 0.9 * int + variation) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [100, 300];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Foulée de plume&lt;br /&gt;
        case 4:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              (3 * dex + 200 + 2 * str + 2 * int) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.removeWeaponReduction = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Flèche empoisonnée&lt;br /&gt;
        case 5:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk +&lt;br /&gt;
                (1.4 * atk + variation + 7 * dex + 4 * str + 4 * int) *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [100, 200];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Coup étincelant&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              (atk +&lt;br /&gt;
                (1.2 * atk + variation + 6 * dex + 3 * str + 3 * int) *&lt;br /&gt;
                  skillPower) *&lt;br /&gt;
                1.2,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [100, 200];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Tir tempête&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.9 * atk + (2.6 * atk + variation) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;weaponary&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Toucher brûlant&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk +&lt;br /&gt;
                2 * lv +&lt;br /&gt;
                2 * int +&lt;br /&gt;
                (2 * atk + 4 * str + 14 * int) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Tourbillon du dragon&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.1 * atk +&lt;br /&gt;
                2 * lv +&lt;br /&gt;
                2 * int +&lt;br /&gt;
                (1.5 * atk + str + 12 * int) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Contre-sort&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              40 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                2 * int +&lt;br /&gt;
                (10 * int + 7 * mav + variation) * attackFactor * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [50, 100];&lt;br /&gt;
          break;&lt;br /&gt;
        // Coup démoniaque&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.9 * atk + (2.6 * atk + variation) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;black_magic&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Attaque des ténèbres&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              40 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                2 * int +&lt;br /&gt;
                (13 * int + 6 * mav + variation) * attackFactor * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [50, 100];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Attaque de flammes&lt;br /&gt;
        // case 2:&lt;br /&gt;
        //   skillFormula = function (mav, variation) {&lt;br /&gt;
        //     return floorMultiplication(&lt;br /&gt;
        //       5 * lv + 2 * int + (7 * int + 8 * mav + 4 * str + 2 * vit + variation) * skillPower,&lt;br /&gt;
        //       1&lt;br /&gt;
        //     );&lt;br /&gt;
        //   };&lt;br /&gt;
        //   skillInfo.range = [180, 100];&lt;br /&gt;
        //   improvedByBonus = true;&lt;br /&gt;
        //   break;&lt;br /&gt;
        // Esprit de flammes&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              30 +&lt;br /&gt;
                2 * lv +&lt;br /&gt;
                2 * int +&lt;br /&gt;
                (7 * int + 6 * mav + variation) * attackFactor * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [200, 500];&lt;br /&gt;
          break;&lt;br /&gt;
        // Frappe de l'esprit&lt;br /&gt;
        // case 5:&lt;br /&gt;
        //   skillFormula = function (mav, variation) {&lt;br /&gt;
        //     return floorMultiplication(&lt;br /&gt;
        //       40 + 2 * lv + 2 * int + (2 * vit + 2 * dex + 13 * int + 6 * mav + variation) * attackFactor * skillPower,&lt;br /&gt;
        //       1&lt;br /&gt;
        //     );&lt;br /&gt;
        //   };&lt;br /&gt;
        //   skillInfo.range = [180, 200];&lt;br /&gt;
        //   break;&lt;br /&gt;
        // Orbe des ténèbres&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (mav) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              120 +&lt;br /&gt;
                6 * lv +&lt;br /&gt;
                (5 * vit + 5 * dex + 29 * int + 9 * mav) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Vague mortelle&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              120 +&lt;br /&gt;
                6 * lv +&lt;br /&gt;
                (5 * vit + 5 * dex + 30 * int + variation + 9 * mav) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;dragon&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Talisman volant&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (mav) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              70 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                (18 * int + 7 * str + 5 * mav + 50) * attackFactor * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [4, 10];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Dragon chassant&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (mav) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              60 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                (16 * int + 6 * dex + 6 * mav + 120) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [4, 10];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Rugissement du dragon&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (mav) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              70 +&lt;br /&gt;
                3 * lv +&lt;br /&gt;
                (20 * int + 3 * str + 10 * mav + 100) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [4, 10];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Météore&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              120 +&lt;br /&gt;
                6 * lv +&lt;br /&gt;
                (5 * vit + 5 * dex + 30 * int + variation + 9 * mav) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;heal&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Jet de foudre&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              60 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                (8 * int + 2 * dex + 8 * mav + variation) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [6, 10];&lt;br /&gt;
          skillInfo.range = [5 * int, 15 * int];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Invocation de foudre&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              40 +&lt;br /&gt;
                4 * lv +&lt;br /&gt;
                (13 * int + 2 * str + 10 * mav + variation) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [6, 10];&lt;br /&gt;
          skillInfo.range = [5 * int, 16 * int];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Griffe de foudre&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              50 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                (8 * int + 2 * str + 8 * mav + variation) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 800];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;lycan&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Déchiqueter&lt;br /&gt;
        // case 1:&lt;br /&gt;
        //   skillFormula = function (atk) {&lt;br /&gt;
        //     return floorMultiplication(&lt;br /&gt;
        //       1.1 * atk + (0.3 * atk + 1.5 * str) * skillPower,&lt;br /&gt;
        //       1&lt;br /&gt;
        //     );&lt;br /&gt;
        //   };&lt;br /&gt;
        //   skillInfo.weaponBonus = [5, 54];&lt;br /&gt;
        //   improvedByBonus = true;&lt;br /&gt;
        //   break;&lt;br /&gt;
        // Souffle de loup&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * atk + (atk + 3 * dex + 5 * str + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [5, 35];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Bond de loup&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk + (1.6 * atk + 200 + 7 * dex + 7 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [5, 35];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Griffe de loup&lt;br /&gt;
        case 4:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              3 * atk + (0.8 * atk + 6 * str + 2 * dex + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Tempête cinglante&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.8 * atk +&lt;br /&gt;
                (atk + 6 * dex + variation + 3 * str + lv) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
    if (improvedBySkillBonus) {&lt;br /&gt;
      skillInfo.skillBonus =&lt;br /&gt;
        16 * getSkillPower(attacker.skillBonus, skillPowerTable);&lt;br /&gt;
&lt;br /&gt;
      var skillWardChoice = victim.skillWardChoice;&lt;br /&gt;
&lt;br /&gt;
      if (skillWardChoice &amp;amp;&amp;amp; skillWardChoice === attackerClass) {&lt;br /&gt;
        skillInfo.skillWard =&lt;br /&gt;
          24 * getSkillPower(victim.skillWard, skillPowerTable);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (improvedByBonus) {&lt;br /&gt;
      skillInfo.skillBonusByBonus = attacker[&amp;quot;skillBonus&amp;quot; + skillId];&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (removeSkillVariation) {&lt;br /&gt;
      var averageVariation = (skillInfo.range[0] + skillInfo.range[0]) / 2;&lt;br /&gt;
      skillInfo.range = [averageVariation, averageVariation];&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    var skillPower = getSkillPower(&lt;br /&gt;
      attacker[&amp;quot;horseSkill&amp;quot; + skillId],&lt;br /&gt;
      skillPowerTable&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    switch (skillId) {&lt;br /&gt;
      // Combat équestre&lt;br /&gt;
      case 137:&lt;br /&gt;
        skillFormula = function (atk) {&lt;br /&gt;
          return floorMultiplication(atk + 2 * atk * skillPower, 1);&lt;br /&gt;
        };&lt;br /&gt;
        break;&lt;br /&gt;
      // Charge à cheval&lt;br /&gt;
      case 138:&lt;br /&gt;
        skillFormula = function (atk) {&lt;br /&gt;
          return floorMultiplication(&lt;br /&gt;
            2.4 * (200 + 1.5 * lv) + 600 * skillPower,&lt;br /&gt;
            1&lt;br /&gt;
          );&lt;br /&gt;
        };&lt;br /&gt;
        break;&lt;br /&gt;
      // Vague de Pouvoir&lt;br /&gt;
      case 139:&lt;br /&gt;
        skillFormula = function (atk) {&lt;br /&gt;
          return floorMultiplication(&lt;br /&gt;
            2 * (200 + 1.5 * lv) + 600 * skillPower,&lt;br /&gt;
            1&lt;br /&gt;
          );&lt;br /&gt;
        };&lt;br /&gt;
        break;&lt;br /&gt;
      // Grêle de flèches&lt;br /&gt;
      case 140:&lt;br /&gt;
        skillFormula = function (atk) {&lt;br /&gt;
          return floorMultiplication(atk + 2 * atk * skillPower, 1);&lt;br /&gt;
        };&lt;br /&gt;
        break;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  updateBattleValues(battleValues, skillFormula, skillInfo);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcMagicAttackValueAugmentation(&lt;br /&gt;
  magicAttackValueWeapon,&lt;br /&gt;
  magicAttackValueBonus&lt;br /&gt;
) {&lt;br /&gt;
  if (magicAttackValueBonus) {&lt;br /&gt;
    return Math.max(&lt;br /&gt;
      1,&lt;br /&gt;
      0.0025056 *&lt;br /&gt;
        magicAttackValueBonus ** 0.602338 *&lt;br /&gt;
        magicAttackValueWeapon ** 1.20476&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
  return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getMagicAttackValueAugmentation(&lt;br /&gt;
  minMagicAttackValue,&lt;br /&gt;
  maxMagicAttackValue,&lt;br /&gt;
  magicAttackValueBonus&lt;br /&gt;
) {&lt;br /&gt;
  var magicAttackValueAugmentation = [];&lt;br /&gt;
&lt;br /&gt;
  for (&lt;br /&gt;
    var magicAttackValue = minMagicAttackValue;&lt;br /&gt;
    magicAttackValue &amp;lt;= maxMagicAttackValue;&lt;br /&gt;
    magicAttackValue++&lt;br /&gt;
  ) {&lt;br /&gt;
    magicAttackValueAugmentation.push(&lt;br /&gt;
      calcMagicAttackValueAugmentation(magicAttackValue, magicAttackValueBonus)&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return magicAttackValueAugmentation;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcPhysicalDamages(battleValues) {&lt;br /&gt;
  var {&lt;br /&gt;
    attackFactor,&lt;br /&gt;
    mainAttackValue,&lt;br /&gt;
    attackValues: { minAttackValue, maxAttackValue, attackValueOther, weights },&lt;br /&gt;
    bonusValues,&lt;br /&gt;
    damagesTypeCombinaison,&lt;br /&gt;
  } = battleValues;&lt;br /&gt;
&lt;br /&gt;
  var damagesWeightedByType = {};&lt;br /&gt;
&lt;br /&gt;
  if (bonusValues.missPercentage) {&lt;br /&gt;
    damagesWeightedByType.miss = bonusValues.missPercentage / 100;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (var damagesType of damagesTypeCombinaison) {&lt;br /&gt;
    if (!damagesType.weight) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var damagesWeighted = {};&lt;br /&gt;
    damagesWeightedByType[damagesType.name] = damagesWeighted;&lt;br /&gt;
&lt;br /&gt;
    for (&lt;br /&gt;
      var attackValue = minAttackValue;&lt;br /&gt;
      attackValue &amp;lt;= maxAttackValue;&lt;br /&gt;
      attackValue++&lt;br /&gt;
    ) {&lt;br /&gt;
      var weight = weights[attackValue - minAttackValue] * damagesType.weight;&lt;br /&gt;
&lt;br /&gt;
      var secondaryAttackValue = 2 * attackValue + attackValueOther;&lt;br /&gt;
      var rawDamages =&lt;br /&gt;
        mainAttackValue +&lt;br /&gt;
        floorMultiplication(attackFactor, secondaryAttackValue);&lt;br /&gt;
&lt;br /&gt;
      var damagesWithPrimaryBonuses = calcDamageWithPrimaryBonuses(&lt;br /&gt;
        rawDamages,&lt;br /&gt;
        bonusValues&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      var minPiercingDamages =&lt;br /&gt;
        damagesWithPrimaryBonuses -&lt;br /&gt;
        bonusValues.defenseBoost +&lt;br /&gt;
        bonusValues.defenseMarriage;&lt;br /&gt;
&lt;br /&gt;
      if (minPiercingDamages &amp;lt;= 2) {&lt;br /&gt;
        for (var damages = 1; damages &amp;lt;= 5; damages++) {&lt;br /&gt;
          var finalDamages = calcDamageWithSecondaryBonuses(&lt;br /&gt;
            damages,&lt;br /&gt;
            bonusValues,&lt;br /&gt;
            damagesType,&lt;br /&gt;
            minPiercingDamages,&lt;br /&gt;
            damagesWithPrimaryBonuses&lt;br /&gt;
          );&lt;br /&gt;
&lt;br /&gt;
          addKeyValue(damagesWeighted, finalDamages, weight / 5);&lt;br /&gt;
        }&lt;br /&gt;
      } else {&lt;br /&gt;
        var finalDamages = calcDamageWithSecondaryBonuses(&lt;br /&gt;
          minPiercingDamages,&lt;br /&gt;
          bonusValues,&lt;br /&gt;
          damagesType,&lt;br /&gt;
          minPiercingDamages,&lt;br /&gt;
          damagesWithPrimaryBonuses&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        addKeyValue(damagesWeighted, finalDamages, weight);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return damagesWeightedByType;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcPhysicalSkillDamages(battleValues) {&lt;br /&gt;
  var {&lt;br /&gt;
    attackFactor,&lt;br /&gt;
    mainAttackValue,&lt;br /&gt;
    attackValues: { minAttackValue, maxAttackValue, attackValueOther, weights },&lt;br /&gt;
    bonusValues,&lt;br /&gt;
    damagesTypeCombinaison,&lt;br /&gt;
    skillFormula,&lt;br /&gt;
    skillRange: [minVariation, maxVariation],&lt;br /&gt;
  } = battleValues;&lt;br /&gt;
&lt;br /&gt;
  var damagesWeightedByType = {};&lt;br /&gt;
&lt;br /&gt;
  for (var damagesType of damagesTypeCombinaison) {&lt;br /&gt;
    if (!damagesType.weight) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var damagesWeighted = {};&lt;br /&gt;
    var savedDamages = {};&lt;br /&gt;
&lt;br /&gt;
    damagesWeightedByType[damagesType.name] = damagesWeighted;&lt;br /&gt;
&lt;br /&gt;
    for (&lt;br /&gt;
      var attackValue = minAttackValue;&lt;br /&gt;
      attackValue &amp;lt;= maxAttackValue;&lt;br /&gt;
      attackValue++&lt;br /&gt;
    ) {&lt;br /&gt;
      var weight = weights[attackValue - minAttackValue] * damagesType.weight;&lt;br /&gt;
&lt;br /&gt;
      var secondaryAttackValue = 2 * attackValue + attackValueOther;&lt;br /&gt;
      var rawDamages =&lt;br /&gt;
        mainAttackValue +&lt;br /&gt;
        floorMultiplication(attackFactor, secondaryAttackValue);&lt;br /&gt;
&lt;br /&gt;
      var damagesWithPrimaryBonuses = calcDamageWithPrimaryBonuses(&lt;br /&gt;
        rawDamages,&lt;br /&gt;
        bonusValues&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      for (&lt;br /&gt;
        var variation = minVariation;&lt;br /&gt;
        variation &amp;lt;= maxVariation;&lt;br /&gt;
        variation++&lt;br /&gt;
      ) {&lt;br /&gt;
        if (damagesWithPrimaryBonuses &amp;lt;= 2) {&lt;br /&gt;
          for (var damages = 1; damages &amp;lt;= 5; damages++) {&lt;br /&gt;
            damages *= bonusValues.useDamages;&lt;br /&gt;
&lt;br /&gt;
            var damagesWithFormula = skillFormula(damages, variation);&lt;br /&gt;
&lt;br /&gt;
            damagesWithFormula = Math.floor(&lt;br /&gt;
              (damagesWithFormula * bonusValues.weaponBonusCoeff) / 100&lt;br /&gt;
            );&lt;br /&gt;
&lt;br /&gt;
            var finalDamages = calcSkillDamageWithSecondaryBonuses(&lt;br /&gt;
              damagesWithFormula,&lt;br /&gt;
              bonusValues,&lt;br /&gt;
              damagesType,&lt;br /&gt;
              damagesWithPrimaryBonuses&lt;br /&gt;
            );&lt;br /&gt;
&lt;br /&gt;
            addKeyValue(damagesWeighted, finalDamages, weight / 5);&lt;br /&gt;
          }&lt;br /&gt;
        } else {&lt;br /&gt;
          damagesWithPrimaryBonuses *= bonusValues.useDamages;&lt;br /&gt;
&lt;br /&gt;
          var damagesWithFormula = skillFormula(&lt;br /&gt;
            damagesWithPrimaryBonuses,&lt;br /&gt;
            variation&lt;br /&gt;
          );&lt;br /&gt;
&lt;br /&gt;
          if (savedDamages.hasOwnProperty(damagesWithFormula)) {&lt;br /&gt;
            var finalDamages = savedDamages[damagesWithFormula];&lt;br /&gt;
            damagesWeighted[finalDamages] += weight;&lt;br /&gt;
            continue;&lt;br /&gt;
          }&lt;br /&gt;
&lt;br /&gt;
          var finalDamages = Math.floor(&lt;br /&gt;
            (damagesWithFormula * bonusValues.weaponBonusCoeff) / 100&lt;br /&gt;
          );&lt;br /&gt;
&lt;br /&gt;
          finalDamages = calcSkillDamageWithSecondaryBonuses(&lt;br /&gt;
            finalDamages,&lt;br /&gt;
            bonusValues,&lt;br /&gt;
            damagesType,&lt;br /&gt;
            damagesWithPrimaryBonuses&lt;br /&gt;
          );&lt;br /&gt;
&lt;br /&gt;
          savedDamages[damagesWithFormula] = finalDamages;&lt;br /&gt;
          addKeyValue(damagesWeighted, finalDamages, weight);&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return damagesWeightedByType;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcMagicSkillDamages(battleValues) {&lt;br /&gt;
  var {&lt;br /&gt;
    attackValues: {&lt;br /&gt;
      minMagicAttackValue,&lt;br /&gt;
      maxMagicAttackValue,&lt;br /&gt;
      magicAttackValueAugmentation,&lt;br /&gt;
      weights,&lt;br /&gt;
    },&lt;br /&gt;
    bonusValues,&lt;br /&gt;
    damagesTypeCombinaison,&lt;br /&gt;
    skillFormula,&lt;br /&gt;
    skillRange: [minVariation, maxVariation],&lt;br /&gt;
  } = battleValues;&lt;br /&gt;
&lt;br /&gt;
  var damagesWeightedByType = {};&lt;br /&gt;
&lt;br /&gt;
  for (var damagesType of damagesTypeCombinaison) {&lt;br /&gt;
    if (!damagesType.weight) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var damagesWeighted = {};&lt;br /&gt;
    var savedDamages = {};&lt;br /&gt;
&lt;br /&gt;
    damagesWeightedByType[damagesType.name] = damagesWeighted;&lt;br /&gt;
&lt;br /&gt;
    for (&lt;br /&gt;
      var magicAttackValue = minMagicAttackValue;&lt;br /&gt;
      magicAttackValue &amp;lt;= maxMagicAttackValue;&lt;br /&gt;
      magicAttackValue++&lt;br /&gt;
    ) {&lt;br /&gt;
      var index = magicAttackValue - minMagicAttackValue;&lt;br /&gt;
      var weight = weights[index] * damagesType.weight;&lt;br /&gt;
&lt;br /&gt;
      for (&lt;br /&gt;
        var variation = minVariation;&lt;br /&gt;
        variation &amp;lt;= maxVariation;&lt;br /&gt;
        variation++&lt;br /&gt;
      ) {&lt;br /&gt;
        var rawDamages = skillFormula(&lt;br /&gt;
          magicAttackValue + magicAttackValueAugmentation[index],&lt;br /&gt;
          variation&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        if (savedDamages.hasOwnProperty(rawDamages)) {&lt;br /&gt;
          var finalDamages = savedDamages[rawDamages];&lt;br /&gt;
          damagesWeighted[finalDamages] += weight;&lt;br /&gt;
          continue;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var damagesWithPrimaryBonuses = Math.floor(&lt;br /&gt;
          (rawDamages * bonusValues.weaponBonusCoeff) / 100&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        damagesWithPrimaryBonuses = calcDamageWithPrimaryBonuses(&lt;br /&gt;
          damagesWithPrimaryBonuses,&lt;br /&gt;
          bonusValues&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        if (damagesWithPrimaryBonuses &amp;lt;= 2) {&lt;br /&gt;
          for (var damages = 1; damages &amp;lt;= 5; damages++) {&lt;br /&gt;
            var finalDamages = calcSkillDamageWithSecondaryBonuses(&lt;br /&gt;
              damages,&lt;br /&gt;
              bonusValues,&lt;br /&gt;
              damagesType,&lt;br /&gt;
              damagesWithPrimaryBonuses&lt;br /&gt;
            );&lt;br /&gt;
            addKeyValue(damagesWeighted, finalDamages, weight / 5);&lt;br /&gt;
          }&lt;br /&gt;
        } else {&lt;br /&gt;
          var finalDamages = calcSkillDamageWithSecondaryBonuses(&lt;br /&gt;
            damagesWithPrimaryBonuses,&lt;br /&gt;
            bonusValues,&lt;br /&gt;
            damagesType,&lt;br /&gt;
            damagesWithPrimaryBonuses&lt;br /&gt;
          );&lt;br /&gt;
&lt;br /&gt;
          savedDamages[rawDamages] = finalDamages;&lt;br /&gt;
          addKeyValue(damagesWeighted, finalDamages, weight);&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return damagesWeightedByType;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcDamages(&lt;br /&gt;
  attacker,&lt;br /&gt;
  victim,&lt;br /&gt;
  attackType,&lt;br /&gt;
  battle,&lt;br /&gt;
  removeSkillVariation&lt;br /&gt;
) {&lt;br /&gt;
  var damagesCalculator, skillId, skillType;&lt;br /&gt;
&lt;br /&gt;
  if (attackType === &amp;quot;physical&amp;quot;) {&lt;br /&gt;
    damagesCalculator = calcPhysicalDamages;&lt;br /&gt;
  } else if (attackType.startsWith(&amp;quot;attackSkill&amp;quot;)) {&lt;br /&gt;
    skillId = Number(attackType.split(&amp;quot;attackSkill&amp;quot;)[1]);&lt;br /&gt;
&lt;br /&gt;
    if (isMagicClass(attacker) || isDispell(attacker, skillId)) {&lt;br /&gt;
      skillType = &amp;quot;magic&amp;quot;;&lt;br /&gt;
      damagesCalculator = calcMagicSkillDamages;&lt;br /&gt;
    } else {&lt;br /&gt;
      skillType = &amp;quot;physical&amp;quot;;&lt;br /&gt;
      damagesCalculator = calcPhysicalSkillDamages;&lt;br /&gt;
    }&lt;br /&gt;
  } else if (attackType.startsWith(&amp;quot;horseSkill&amp;quot;)) {&lt;br /&gt;
    skillType = &amp;quot;physical&amp;quot;;&lt;br /&gt;
    skillId = Number(attackType.split(&amp;quot;horseSkill&amp;quot;)[1]);&lt;br /&gt;
    damagesCalculator = calcPhysicalSkillDamages;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var battleValues = createBattleValues(attacker, victim, battle, skillType);&lt;br /&gt;
&lt;br /&gt;
  if (skillId) {&lt;br /&gt;
    getSkillFormula(battle, skillId, battleValues, removeSkillVariation);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var {&lt;br /&gt;
    attackValues: { totalCardinal, possibleDamagesCount },&lt;br /&gt;
  } = battleValues;&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    damagesWeightedByType: damagesCalculator(battleValues),&lt;br /&gt;
    totalCardinal: totalCardinal,&lt;br /&gt;
    possibleDamagesCount: possibleDamagesCount,&lt;br /&gt;
    skillType: skillType,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function damagesWithoutVariation(&lt;br /&gt;
  attacker,&lt;br /&gt;
  victim,&lt;br /&gt;
  attackType,&lt;br /&gt;
  battle,&lt;br /&gt;
  characters&lt;br /&gt;
) {&lt;br /&gt;
  startDamagesTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
  var {&lt;br /&gt;
    damagesWeightedByType,&lt;br /&gt;
    totalCardinal,&lt;br /&gt;
    possibleDamagesCount,&lt;br /&gt;
    skillType,&lt;br /&gt;
  } = calcDamages(attacker, victim, attackType, battle);&lt;br /&gt;
&lt;br /&gt;
  endDamagesTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
  possibleDamagesCount = displayResults(&lt;br /&gt;
    possibleDamagesCount,&lt;br /&gt;
    totalCardinal,&lt;br /&gt;
    damagesWeightedByType,&lt;br /&gt;
    battle,&lt;br /&gt;
    attacker.name,&lt;br /&gt;
    victim.name&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  endDisplayTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
  displayFightInfo(&lt;br /&gt;
    possibleDamagesCount,&lt;br /&gt;
    endDamagesTime - startDamagesTime,&lt;br /&gt;
    endDisplayTime - endDamagesTime,&lt;br /&gt;
    battle&lt;br /&gt;
  );&lt;br /&gt;
  addPotentialErrorInformation(&lt;br /&gt;
    battle.errorInformation,&lt;br /&gt;
    attacker,&lt;br /&gt;
    victim,&lt;br /&gt;
    skillType,&lt;br /&gt;
    characters&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  hideElement(battle.bonusVariationResultContainer);&lt;br /&gt;
  showElement(battle.fightResultContainer);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function damagesWithVariation(&lt;br /&gt;
  attacker,&lt;br /&gt;
  victim,&lt;br /&gt;
  attackType,&lt;br /&gt;
  battle,&lt;br /&gt;
  entity,&lt;br /&gt;
  entityVariation&lt;br /&gt;
) {&lt;br /&gt;
  startTime = performance.now();&lt;br /&gt;
  var damagesByBonus = [];&lt;br /&gt;
  var augmentationByBonus = [];&lt;br /&gt;
  var {&lt;br /&gt;
    bonusVariationMinValue: minVariation,&lt;br /&gt;
    bonusVariationMaxValue: maxVariation,&lt;br /&gt;
  } = entity;&lt;br /&gt;
  var step = Math.ceil((maxVariation - minVariation + 1) / 500);&lt;br /&gt;
  var simulationCount = 0;&lt;br /&gt;
  var simulationTime;&lt;br /&gt;
&lt;br /&gt;
  for (&lt;br /&gt;
    var bonusValue = minVariation;&lt;br /&gt;
    bonusValue &amp;lt;= maxVariation;&lt;br /&gt;
    bonusValue += step&lt;br /&gt;
  ) {&lt;br /&gt;
    entity[entityVariation] = bonusValue;&lt;br /&gt;
&lt;br /&gt;
    var { damagesWeightedByType, totalCardinal } = calcDamages(&lt;br /&gt;
      copyObject(attacker),&lt;br /&gt;
      copyObject(victim),&lt;br /&gt;
      attackType,&lt;br /&gt;
      battle,&lt;br /&gt;
      true&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    var meanDamages = calcMeanDamages(damagesWeightedByType, totalCardinal);&lt;br /&gt;
&lt;br /&gt;
    if (bonusValue === minVariation) {&lt;br /&gt;
      var firstDamages = Math.max(meanDamages, 1e-3);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    damagesByBonus.push({ x: bonusValue, y: meanDamages });&lt;br /&gt;
    augmentationByBonus.push({&lt;br /&gt;
      x: bonusValue,&lt;br /&gt;
      y: meanDamages / firstDamages - 1,&lt;br /&gt;
    });&lt;br /&gt;
    simulationCount++;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  endTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
  battle.damagesByBonus = damagesByBonus.concat(entityVariation);&lt;br /&gt;
&lt;br /&gt;
  addToBonusVariationChart(&lt;br /&gt;
    damagesByBonus,&lt;br /&gt;
    augmentationByBonus,&lt;br /&gt;
    entity.bonusVariationDisplay,&lt;br /&gt;
    battle.bonusVariationChart&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  simulationCount = battle.numberFormats.default.format(simulationCount);&lt;br /&gt;
  simulationTime = battle.numberFormats.second.format(&lt;br /&gt;
    (endTime - startTime) / 1000&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  battle.simulationCounter.textContent = simulationCount;&lt;br /&gt;
  battle.simulationTime.textContent = simulationTime;&lt;br /&gt;
&lt;br /&gt;
  hideElement(battle.fightResultContainer);&lt;br /&gt;
  showElement(battle.bonusVariationResultContainer);&lt;br /&gt;
&lt;br /&gt;
  if (&lt;br /&gt;
    isChecked(attacker.bonusVariationActivation) &amp;amp;&amp;amp;&lt;br /&gt;
    isChecked(victim.bonusVariationActivation)&lt;br /&gt;
  ) {&lt;br /&gt;
    showElement(battle.errorInformation[&amp;quot;attacker-victim-variation&amp;quot;]);&lt;br /&gt;
  } else {&lt;br /&gt;
    hideElement(battle.errorInformation[&amp;quot;attacker-victim-variation&amp;quot;]);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function changeMonsterValues(monster, instance, attacker) {&lt;br /&gt;
  switch (instance) {&lt;br /&gt;
    case &amp;quot;SungMahiTower&amp;quot;:&lt;br /&gt;
      var sungMahiFloor = 1;&lt;br /&gt;
      var sungMahiStep = 1;&lt;br /&gt;
      var rawDefense = 120;&lt;br /&gt;
&lt;br /&gt;
      if (isPC(attacker)) {&lt;br /&gt;
        sungMahiFloor = attacker.sungMahiFloor;&lt;br /&gt;
        sungMahiStep = attacker.sungMahiStep;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (monster.rank === 5) {&lt;br /&gt;
        monster.level = 121;&lt;br /&gt;
        monster.dex = 75;&lt;br /&gt;
        rawDefense += 1;&lt;br /&gt;
      } else if (monster.rank === 6) {&lt;br /&gt;
        monster.level = 123;&lt;br /&gt;
        monster.dex = 75;&lt;br /&gt;
        rawDefense += 1;&lt;br /&gt;
      } else {&lt;br /&gt;
        monster.level = 120;&lt;br /&gt;
        monster.dex = 68;&lt;br /&gt;
      }&lt;br /&gt;
      monster.vit = 100;&lt;br /&gt;
      monster.rawDefense = rawDefense + (sungMahiStep - 1) * 6;&lt;br /&gt;
      monster.fistDefense = 0;&lt;br /&gt;
      monster.swordDefense = 0;&lt;br /&gt;
      monster.twoHandedSwordDefense = 0;&lt;br /&gt;
      monster.daggerDefense = 0;&lt;br /&gt;
      monster.bellDefense = 0;&lt;br /&gt;
      monster.fanDefense = 0;&lt;br /&gt;
      monster.arrowDefense = 0;&lt;br /&gt;
      monster.clawDefense = 0;&lt;br /&gt;
      monster.magicResistance = 0;&lt;br /&gt;
      monster.fireResistance = -20;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  // Alastor&lt;br /&gt;
  if (monster.vnum === 6790) {&lt;br /&gt;
    monster.iceResistance = 0;&lt;br /&gt;
    (monster.iceBonus = 0), (monster.lightningResistance = -10);&lt;br /&gt;
    monster.lightningBonus = 65;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createWeapon(weaponVnum) {&lt;br /&gt;
  var weapon = weaponData[weaponVnum];&lt;br /&gt;
  var weaponName = weapon[0];&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    name: weaponName,&lt;br /&gt;
    type: weapon[1],&lt;br /&gt;
    minAttackValue: weapon[2][2],&lt;br /&gt;
    maxAttackValue: weapon[2][3],&lt;br /&gt;
    minMagicAttackValue: weapon[2][0],&lt;br /&gt;
    maxMagicAttackValue: weapon[2][1],&lt;br /&gt;
    upgrades: weapon[3],&lt;br /&gt;
    isSerpent: isValueInArray(&amp;quot;serpent&amp;quot;, weaponName.toLowerCase()),&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createMonster(monsterVnum, attacker) {&lt;br /&gt;
  var monsterAttributes = monsterData[monsterVnum];&lt;br /&gt;
&lt;br /&gt;
  var monster = {&lt;br /&gt;
    vnum: Number(monsterVnum),&lt;br /&gt;
    name: monsterAttributes[36],&lt;br /&gt;
    rank: monsterAttributes[0],&lt;br /&gt;
    race: monsterAttributes[1],&lt;br /&gt;
    attack: monsterAttributes[2],&lt;br /&gt;
    level: monsterAttributes[3],&lt;br /&gt;
    type: monsterAttributes[4],&lt;br /&gt;
    str: monsterAttributes[5],&lt;br /&gt;
    dex: monsterAttributes[6],&lt;br /&gt;
    vit: monsterAttributes[7],&lt;br /&gt;
    int: monsterAttributes[8],&lt;br /&gt;
    minAttackValue: monsterAttributes[9],&lt;br /&gt;
    maxAttackValue: monsterAttributes[10],&lt;br /&gt;
    rawDefense: monsterAttributes[11],&lt;br /&gt;
    criticalHit: monsterAttributes[12],&lt;br /&gt;
    piercingHit: monsterAttributes[13],&lt;br /&gt;
    fistDefense: monsterAttributes[14],&lt;br /&gt;
    swordDefense: monsterAttributes[15],&lt;br /&gt;
    twoHandedSwordDefense: monsterAttributes[16],&lt;br /&gt;
    daggerDefense: monsterAttributes[17],&lt;br /&gt;
    bellDefense: monsterAttributes[18],&lt;br /&gt;
    fanDefense: monsterAttributes[19],&lt;br /&gt;
    arrowDefense: monsterAttributes[20],&lt;br /&gt;
    clawDefense: monsterAttributes[21],&lt;br /&gt;
    fireResistance: monsterAttributes[22],&lt;br /&gt;
    lightningResistance: monsterAttributes[23],&lt;br /&gt;
    magicResistance: monsterAttributes[24],&lt;br /&gt;
    windResistance: monsterAttributes[25],&lt;br /&gt;
    lightningBonus: monsterAttributes[26],&lt;br /&gt;
    fireBonus: monsterAttributes[27],&lt;br /&gt;
    iceBonus: monsterAttributes[28],&lt;br /&gt;
    windBonus: monsterAttributes[29],&lt;br /&gt;
    earthBonus: monsterAttributes[30],&lt;br /&gt;
    darknessBonus: monsterAttributes[31],&lt;br /&gt;
    darknessResistance: monsterAttributes[32],&lt;br /&gt;
    iceResistance: monsterAttributes[33],&lt;br /&gt;
    earthResistance: monsterAttributes[34],&lt;br /&gt;
    damageMultiplier: monsterAttributes[35],&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  // monster.instance = 0;&lt;br /&gt;
&lt;br /&gt;
  // if (attacker &amp;amp;&amp;amp; monster.instance === 0) {&lt;br /&gt;
  //   changeMonsterValues(monster, &amp;quot;SungMahiTower&amp;quot;, attacker);&lt;br /&gt;
  // }&lt;br /&gt;
&lt;br /&gt;
  changeMonsterValues(monster);&lt;br /&gt;
&lt;br /&gt;
  monster.defense = monster.rawDefense + monster.level + monster.vit;&lt;br /&gt;
&lt;br /&gt;
  return monster;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addPotentialErrorInformation(&lt;br /&gt;
  errorInformation,&lt;br /&gt;
  attacker,&lt;br /&gt;
  victim,&lt;br /&gt;
  skillType,&lt;br /&gt;
  characters&lt;br /&gt;
) {&lt;br /&gt;
  for (var error of Object.values(errorInformation)) {&lt;br /&gt;
    hideElement(error);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker)) {&lt;br /&gt;
    if (isRiding(attacker)) {&lt;br /&gt;
      if (attacker.horsePoint === 0) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;horse-level&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
      showElement(errorInformation[&amp;quot;horse-stat&amp;quot;]);&lt;br /&gt;
    } else if (isPolymorph(attacker)) {&lt;br /&gt;
      if (attacker.polymorphPoint === 0) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;polymorph-level&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (&lt;br /&gt;
        (attacker.polymorphPoint &amp;lt;= 39 &amp;amp;&amp;amp; attacker.attackValuePercent &amp;lt;= 199) ||&lt;br /&gt;
        (attacker.polymorphPoint === 40 &amp;amp;&amp;amp; attacker.attackValuePercent &amp;lt;= 299)&lt;br /&gt;
      ) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;polymorph-bonus&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
    if (skillType === &amp;quot;magic&amp;quot;) {&lt;br /&gt;
      if (attacker.magicAttackValue) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;magic-attack-value-bonus&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
      if (victim.magicResistance) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;magic-resistance&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    showElement(errorInformation[&amp;quot;monster-attacker&amp;quot;]);&lt;br /&gt;
    if (isMagicAttacker(attacker) &amp;amp;&amp;amp; victim.magicResistance) {&lt;br /&gt;
      showElement(errorInformation[&amp;quot;magic-resistance&amp;quot;]);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (isPC(victim)) {&lt;br /&gt;
    if (isRiding(victim)) {&lt;br /&gt;
      showElement(errorInformation[&amp;quot;horse-stat&amp;quot;]);&lt;br /&gt;
    } else if (isPolymorph(victim)) {&lt;br /&gt;
      if (attacker.polymorphPoint === 0) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;polymorph-level&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
      showElement(errorInformation[&amp;quot;polymorph-defense&amp;quot;]);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (characters.unsavedChanges) {&lt;br /&gt;
    showElement(errorInformation[&amp;quot;save&amp;quot;]);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function reduceChartPointsListener(battle) {&lt;br /&gt;
  var {&lt;br /&gt;
    reduceChartPointsContainer,&lt;br /&gt;
    reduceChartPoints,&lt;br /&gt;
    numberFormats: { second: numberFormat },&lt;br /&gt;
    displayTime,&lt;br /&gt;
  } = battle;&lt;br /&gt;
&lt;br /&gt;
  reduceChartPoints.addEventListener(&amp;quot;change&amp;quot;, function () {&lt;br /&gt;
    var startDisplayTime = performance.now();&lt;br /&gt;
    var scatterDataByType = battle.scatterDataByType;&lt;br /&gt;
    var {&lt;br /&gt;
      chart,&lt;br /&gt;
      maxPoints,&lt;br /&gt;
      chart: {&lt;br /&gt;
        data: { datasets },&lt;br /&gt;
      },&lt;br /&gt;
    } = battle.damagesChart;&lt;br /&gt;
    var addAnimations = false;&lt;br /&gt;
&lt;br /&gt;
    for (var index = 0; index &amp;lt; datasets.length; index++) {&lt;br /&gt;
      var dataset = datasets[index];&lt;br /&gt;
      var scatterData = scatterDataByType[dataset.name];&lt;br /&gt;
&lt;br /&gt;
      if (dataset.canBeReduced &amp;amp;&amp;amp; reduceChartPoints.checked) {&lt;br /&gt;
        dataset.data = aggregateDamages(scatterData, maxPoints);&lt;br /&gt;
        addAnimations = true;&lt;br /&gt;
      } else {&lt;br /&gt;
        dataset.data = scatterData;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    handleChartAnimations(chart, addAnimations);&lt;br /&gt;
    chart.update();&lt;br /&gt;
&lt;br /&gt;
    displayTime.textContent = numberFormat.format(&lt;br /&gt;
      (performance.now() - startDisplayTime) / 1000&lt;br /&gt;
    );&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  reduceChartPointsContainer.addEventListener(&amp;quot;pointerup&amp;quot;, function (event) {&lt;br /&gt;
    if (event.pointerType === &amp;quot;mouse&amp;quot;) {&lt;br /&gt;
      reduceChartPoints.click();&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function downloadRawDataListener(battle) {&lt;br /&gt;
  var { downLoadRawData, downLoadRawDataVariation } = battle;&lt;br /&gt;
  var fileType = &amp;quot;text/csv;charset=utf-8;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  downLoadRawData.addEventListener(&amp;quot;click&amp;quot;, function () {&lt;br /&gt;
    var damagesWeightedByType = battle.damagesWeightedByType;&lt;br /&gt;
    var filename = &amp;quot;raw_damages.csv&amp;quot;;&lt;br /&gt;
    var csvContent = &amp;quot;damage,probabilities,damageType\n&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    for (var damagesType in damagesWeightedByType) {&lt;br /&gt;
      var damagesWeighted = damagesWeightedByType[damagesType];&lt;br /&gt;
&lt;br /&gt;
      for (var damages in damagesWeighted) {&lt;br /&gt;
        csvContent +=&lt;br /&gt;
          damages + &amp;quot;,&amp;quot; + damagesWeighted[damages] + &amp;quot;,&amp;quot; + damagesType + &amp;quot;\n&amp;quot;;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    downloadData(csvContent, fileType, filename);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  downLoadRawDataVariation.addEventListener(&amp;quot;click&amp;quot;, function () {&lt;br /&gt;
    var damagesByBonus = battle.damagesByBonus;&lt;br /&gt;
    var damagesByBonusLength = damagesByBonus.length;&lt;br /&gt;
    var filename = &amp;quot;damages_variation.csv&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    if (!damagesByBonusLength) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var csvContent =&lt;br /&gt;
      damagesByBonus[damagesByBonusLength - 1] + &amp;quot;,averageDamage\n&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    for (var index = 0; index &amp;lt; damagesByBonusLength - 1; index++) {&lt;br /&gt;
      var row = damagesByBonus[index];&lt;br /&gt;
&lt;br /&gt;
      csvContent += row.x + &amp;quot;,&amp;quot; + row.y + &amp;quot;\n&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    downloadData(csvContent, fileType, filename);&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function displayResults(&lt;br /&gt;
  possibleDamagesCount,&lt;br /&gt;
  totalCardinal,&lt;br /&gt;
  damagesWeightedByType,&lt;br /&gt;
  battle,&lt;br /&gt;
  attackerName,&lt;br /&gt;
  victimName&lt;br /&gt;
) {&lt;br /&gt;
  var [&lt;br /&gt;
    meanDamages,&lt;br /&gt;
    minDamages,&lt;br /&gt;
    maxDamages,&lt;br /&gt;
    scatterDataByType,&lt;br /&gt;
    possibleDamagesCount,&lt;br /&gt;
    uniqueDamagesCount,&lt;br /&gt;
  ] = prepareDamagesData(&lt;br /&gt;
    damagesWeightedByType,&lt;br /&gt;
    possibleDamagesCount,&lt;br /&gt;
    totalCardinal&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  addToDamagesChart(&lt;br /&gt;
    scatterDataByType,&lt;br /&gt;
    battle.damagesChart,&lt;br /&gt;
    battle.reduceChartPoints.checked&lt;br /&gt;
  );&lt;br /&gt;
  updateDamagesChartDescription(&lt;br /&gt;
    battle.uniqueDamagesCounters,&lt;br /&gt;
    uniqueDamagesCount,&lt;br /&gt;
    battle.numberFormats.default&lt;br /&gt;
  );&lt;br /&gt;
  displayFightResults(&lt;br /&gt;
    battle,&lt;br /&gt;
    attackerName,&lt;br /&gt;
    victimName,&lt;br /&gt;
    meanDamages,&lt;br /&gt;
    minDamages,&lt;br /&gt;
    maxDamages&lt;br /&gt;
  );&lt;br /&gt;
  battle.damagesWeightedByType = damagesWeightedByType;&lt;br /&gt;
  battle.scatterDataByType = scatterDataByType;&lt;br /&gt;
&lt;br /&gt;
  return possibleDamagesCount;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function displayFightResults(&lt;br /&gt;
  battle,&lt;br /&gt;
  attackerName,&lt;br /&gt;
  victimName,&lt;br /&gt;
  meanDamages,&lt;br /&gt;
  minDamages,&lt;br /&gt;
  maxDamages&lt;br /&gt;
) {&lt;br /&gt;
  var {&lt;br /&gt;
    tableResultFight,&lt;br /&gt;
    tableResultHistory,&lt;br /&gt;
    attackTypeSelection,&lt;br /&gt;
    savedFights,&lt;br /&gt;
    numberFormats: { default: numberFormat },&lt;br /&gt;
    deleteFightTemplate,&lt;br /&gt;
  } = battle;&lt;br /&gt;
&lt;br /&gt;
  hideElement(tableResultHistory.rows[1]);&lt;br /&gt;
&lt;br /&gt;
  var valuesToDisplay = [&lt;br /&gt;
    attackerName,&lt;br /&gt;
    victimName,&lt;br /&gt;
    attackTypeSelection.options[attackTypeSelection.selectedIndex].textContent,&lt;br /&gt;
    meanDamages,&lt;br /&gt;
    minDamages,&lt;br /&gt;
    maxDamages,&lt;br /&gt;
  ];&lt;br /&gt;
&lt;br /&gt;
  savedFights.push(valuesToDisplay);&lt;br /&gt;
  updateSavedFights(savedFights);&lt;br /&gt;
&lt;br /&gt;
  editTableResultRow(tableResultFight.rows[1], valuesToDisplay, numberFormat);&lt;br /&gt;
  addRowToTableResultHistory(&lt;br /&gt;
    tableResultHistory,&lt;br /&gt;
    valuesToDisplay,&lt;br /&gt;
    deleteFightTemplate,&lt;br /&gt;
    numberFormat&lt;br /&gt;
  );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function displayFightInfo(&lt;br /&gt;
  possibleDamagesCount,&lt;br /&gt;
  damagesTime,&lt;br /&gt;
  displayTime,&lt;br /&gt;
  battle&lt;br /&gt;
) {&lt;br /&gt;
  var container = battle.possibleDamagesCounter.parentElement;&lt;br /&gt;
&lt;br /&gt;
  if (possibleDamagesCount &amp;lt;= 1) {&lt;br /&gt;
    hideElement(container);&lt;br /&gt;
    return;&lt;br /&gt;
  } else {&lt;br /&gt;
    showElement(container);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  possibleDamagesCount =&lt;br /&gt;
    battle.numberFormats.default.format(possibleDamagesCount);&lt;br /&gt;
  damagesTime = battle.numberFormats.second.format(damagesTime / 1000);&lt;br /&gt;
  displayTime = battle.numberFormats.second.format(displayTime / 1000);&lt;br /&gt;
&lt;br /&gt;
  battle.possibleDamagesCounter.textContent = possibleDamagesCount;&lt;br /&gt;
  battle.damagesTime.textContent = damagesTime;&lt;br /&gt;
  battle.displayTime.textContent = displayTime;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isPseudoSaved(characters, pseudo) {&lt;br /&gt;
  return characters.savedCharacters.hasOwnProperty(pseudo);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createBattle(characters, battle) {&lt;br /&gt;
  battle.battleForm.addEventListener(&amp;quot;submit&amp;quot;, function (event) {&lt;br /&gt;
    event.preventDefault();&lt;br /&gt;
&lt;br /&gt;
    // auto save&lt;br /&gt;
    if (characters.unsavedChanges) {&lt;br /&gt;
      characters.saveButton.click();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var battleInfo = new FormData(event.target);&lt;br /&gt;
    var attackerName = battleInfo.get(&amp;quot;attacker&amp;quot;);&lt;br /&gt;
    var attackType = battleInfo.get(&amp;quot;attackTypeSelection&amp;quot;);&lt;br /&gt;
    var victimName = battleInfo.get(&amp;quot;victim&amp;quot;);&lt;br /&gt;
    var attackerVariation;&lt;br /&gt;
    var victimVariation;&lt;br /&gt;
&lt;br /&gt;
    if (!attackerName &amp;amp;&amp;amp; !attackType &amp;amp;&amp;amp; !victimName) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isPseudoSaved(characters, attackerName)) {&lt;br /&gt;
      var attacker = copyObject(characters.savedCharacters[attackerName]);&lt;br /&gt;
      attackerVariation = attacker.bonusVariation;&lt;br /&gt;
    } else {&lt;br /&gt;
      var attacker = createMonster(attackerName);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isPseudoSaved(characters, victimName)) {&lt;br /&gt;
      var victim = copyObject(characters.savedCharacters[victimName]);&lt;br /&gt;
      victimVariation = victim.bonusVariation;&lt;br /&gt;
    } else {&lt;br /&gt;
      var victim = createMonster(victimName, attacker);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      isChecked(attacker.bonusVariationActivation) &amp;amp;&amp;amp;&lt;br /&gt;
      attacker.hasOwnProperty(attackerVariation) &amp;amp;&amp;amp;&lt;br /&gt;
      attacker.bonusVariationMinValue &amp;lt; attacker.bonusVariationMaxValue&lt;br /&gt;
    ) {&lt;br /&gt;
      damagesWithVariation(&lt;br /&gt;
        attacker,&lt;br /&gt;
        victim,&lt;br /&gt;
        attackType,&lt;br /&gt;
        battle,&lt;br /&gt;
        attacker,&lt;br /&gt;
        attackerVariation&lt;br /&gt;
      );&lt;br /&gt;
    } else if (&lt;br /&gt;
      isChecked(victim.bonusVariationActivation) &amp;amp;&amp;amp;&lt;br /&gt;
      victim.hasOwnProperty(victimVariation) &amp;amp;&amp;amp;&lt;br /&gt;
      victim.bonusVariationMinValue &amp;lt; victim.bonusVariationMaxValue&lt;br /&gt;
    ) {&lt;br /&gt;
      damagesWithVariation(&lt;br /&gt;
        attacker,&lt;br /&gt;
        victim,&lt;br /&gt;
        attackType,&lt;br /&gt;
        battle,&lt;br /&gt;
        victim,&lt;br /&gt;
        victimVariation&lt;br /&gt;
      );&lt;br /&gt;
    } else {&lt;br /&gt;
      damagesWithoutVariation(attacker, victim, attackType, battle, characters);&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createMapping() {&lt;br /&gt;
  mapping = {&lt;br /&gt;
    typeFlag: [&lt;br /&gt;
      &amp;quot;animalBonus&amp;quot;, // 0&lt;br /&gt;
      &amp;quot;humanBonus&amp;quot;, // 1&lt;br /&gt;
      &amp;quot;orcBonus&amp;quot;, // 2&lt;br /&gt;
      &amp;quot;mysticBonus&amp;quot;, // 3&lt;br /&gt;
      &amp;quot;undeadBonus&amp;quot;, // 4&lt;br /&gt;
      &amp;quot;insectBonus&amp;quot;, // 5&lt;br /&gt;
      &amp;quot;desertBonus&amp;quot;, // 6&lt;br /&gt;
      &amp;quot;devilBonus&amp;quot;, // 7&lt;br /&gt;
    ],&lt;br /&gt;
    raceBonus: {&lt;br /&gt;
      warrior: &amp;quot;warriorBonus&amp;quot;,&lt;br /&gt;
      sura: &amp;quot;suraBonus&amp;quot;,&lt;br /&gt;
      ninja: &amp;quot;ninjaBonus&amp;quot;,&lt;br /&gt;
      shaman: &amp;quot;shamanBonus&amp;quot;,&lt;br /&gt;
      lycan: &amp;quot;lycanBonus&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    raceResistance: {&lt;br /&gt;
      warrior: &amp;quot;warriorResistance&amp;quot;,&lt;br /&gt;
      sura: &amp;quot;suraResistance&amp;quot;,&lt;br /&gt;
      ninja: &amp;quot;ninjaResistance&amp;quot;,&lt;br /&gt;
      shaman: &amp;quot;shamanResistance&amp;quot;,&lt;br /&gt;
      lycan: &amp;quot;lycanResistance&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    defenseWeapon: [&lt;br /&gt;
      &amp;quot;swordDefense&amp;quot;, // 0&lt;br /&gt;
      &amp;quot;daggerDefense&amp;quot;, // 1&lt;br /&gt;
      &amp;quot;arrowDefense&amp;quot;, // 2&lt;br /&gt;
      &amp;quot;twoHandedSwordDefense&amp;quot;, // 3&lt;br /&gt;
      &amp;quot;bellDefense&amp;quot;, // 4&lt;br /&gt;
      &amp;quot;clawDefense&amp;quot;, // 5&lt;br /&gt;
      &amp;quot;fanDefense&amp;quot;, // 6&lt;br /&gt;
      &amp;quot;swordDefense&amp;quot;, // 7&lt;br /&gt;
      &amp;quot;fistDefense&amp;quot;, // 8&lt;br /&gt;
    ],&lt;br /&gt;
    breakWeapon: [&lt;br /&gt;
      &amp;quot;breakSwordDefense&amp;quot;, // 0&lt;br /&gt;
      &amp;quot;breakDaggerDefense&amp;quot;, // 1&lt;br /&gt;
      &amp;quot;breakArrowDefense&amp;quot;, // 2&lt;br /&gt;
      &amp;quot;breakTwoHandedSwordDefense&amp;quot;, // 3&lt;br /&gt;
      &amp;quot;breakBellDefense&amp;quot;, // 4&lt;br /&gt;
      &amp;quot;breakClawDefense&amp;quot;, // 5&lt;br /&gt;
      &amp;quot;breakFanDefense&amp;quot;, // 6&lt;br /&gt;
      &amp;quot;breakSwordDefense&amp;quot;, // 7&lt;br /&gt;
    ],&lt;br /&gt;
    elementBonus: [&lt;br /&gt;
      &amp;quot;fireBonus&amp;quot;, // 0&lt;br /&gt;
      &amp;quot;iceBonus&amp;quot;, // 1&lt;br /&gt;
      &amp;quot;windBonus&amp;quot;, // 2&lt;br /&gt;
      &amp;quot;lightningBonus&amp;quot;, // 3&lt;br /&gt;
      &amp;quot;earthBonus&amp;quot;, // 4&lt;br /&gt;
      &amp;quot;darknessBonus&amp;quot;, // 5&lt;br /&gt;
    ],&lt;br /&gt;
    elementResistance: [&lt;br /&gt;
      &amp;quot;fireResistance&amp;quot;, // 0&lt;br /&gt;
      &amp;quot;iceResistance&amp;quot;, // 1&lt;br /&gt;
      &amp;quot;windResistance&amp;quot;, // 2&lt;br /&gt;
      &amp;quot;lightningResistance&amp;quot;, // 3&lt;br /&gt;
      &amp;quot;earthResistance&amp;quot;, // 4&lt;br /&gt;
      &amp;quot;darknessResistance&amp;quot;, // 5&lt;br /&gt;
    ],&lt;br /&gt;
  };&lt;br /&gt;
  return mapping;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createConstants() {&lt;br /&gt;
  var constants = {&lt;br /&gt;
    polymorphPowerTable: [&lt;br /&gt;
      10, 11, 11, 12, 13, 13, 14, 15, 16, 17, 18, 19, 20, 22, 23, 24, 26, 27,&lt;br /&gt;
      29, 31, 33, 35, 37, 39, 41, 44, 46, 49, 52, 55, 59, 62, 66, 70, 74, 79,&lt;br /&gt;
      84, 89, 94, 100, 0,&lt;br /&gt;
    ],&lt;br /&gt;
    skillPowerTable: [&lt;br /&gt;
      0, 0.05, 0.06, 0.08, 0.1, 0.12, 0.14, 0.16, 0.18, 0.2, 0.22, 0.24, 0.26,&lt;br /&gt;
      0.28, 0.3, 0.32, 0.34, 0.36, 0.38, 0.4, 0.5, 0.52, 0.54, 0.56, 0.58, 0.6,&lt;br /&gt;
      0.63, 0.66, 0.69, 0.72, 0.82, 0.85, 0.88, 0.91, 0.94, 0.98, 1.02, 1.06,&lt;br /&gt;
      1.1, 1.15, 1.25,&lt;br /&gt;
    ],&lt;br /&gt;
    marriageTable: {&lt;br /&gt;
      harmonyEarrings: [4, 5, 6, 8],&lt;br /&gt;
      loveEarrings: [4, 5, 6, 8],&lt;br /&gt;
      harmonyBracelet: [4, 5, 6, 8],&lt;br /&gt;
      loveNecklace: [20, 25, 30, 40],&lt;br /&gt;
      harmonyNecklace: [12, 16, 20, 30],&lt;br /&gt;
    },&lt;br /&gt;
    allowedWeaponsPerRace: {&lt;br /&gt;
      warrior: [0, 3, 8],&lt;br /&gt;
      ninja: [0, 1, 2, 8],&lt;br /&gt;
      sura: [0, 7, 8],&lt;br /&gt;
      shaman: [4, 6, 8],&lt;br /&gt;
      lycan: [5, 8],&lt;br /&gt;
    },&lt;br /&gt;
    translation: {&lt;br /&gt;
      fr: {&lt;br /&gt;
        damages: &amp;quot;Dégâts&amp;quot;,&lt;br /&gt;
        percentage: &amp;quot;Pourcentage&amp;quot;,&lt;br /&gt;
        miss: &amp;quot;Miss&amp;quot;,&lt;br /&gt;
        normalHit: &amp;quot;Coup classique&amp;quot;,&lt;br /&gt;
        criticalHit: &amp;quot;Coup critique&amp;quot;,&lt;br /&gt;
        piercingHit: &amp;quot;Coup perçant&amp;quot;,&lt;br /&gt;
        criticalPiercingHit: &amp;quot;Coup critique perçant&amp;quot;,&lt;br /&gt;
        damagesRepartition: &amp;quot;Distribution des dégâts&amp;quot;,&lt;br /&gt;
        averageDamages: &amp;quot;Dégâts moyens&amp;quot;,&lt;br /&gt;
        damagesAugmentation: &amp;quot;Augmentation des dégâts&amp;quot;,&lt;br /&gt;
        bonusVariationTitle: [&lt;br /&gt;
          &amp;quot;Évolution des dégâts moyens&amp;quot;,&lt;br /&gt;
          &amp;quot;par rapport à la valeur d'un bonus&amp;quot;,&lt;br /&gt;
        ],&lt;br /&gt;
      },&lt;br /&gt;
      en: {&lt;br /&gt;
        damages: &amp;quot;Damage&amp;quot;,&lt;br /&gt;
        percentage: &amp;quot;Percentage&amp;quot;,&lt;br /&gt;
        miss: &amp;quot;Miss&amp;quot;,&lt;br /&gt;
        normalHit: &amp;quot;Normal Hit&amp;quot;,&lt;br /&gt;
        criticalHit: &amp;quot;Critical Hit&amp;quot;,&lt;br /&gt;
        piercingHit: &amp;quot;Piercing Hit&amp;quot;,&lt;br /&gt;
        criticalPiercingHit: &amp;quot;Critical Piercing Hit&amp;quot;,&lt;br /&gt;
        damagesRepartition: &amp;quot;Damage Repartition&amp;quot;,&lt;br /&gt;
        averageDamages: &amp;quot;Average Damage&amp;quot;,&lt;br /&gt;
        damagesAugmentation: &amp;quot;Damage Augmentation&amp;quot;,&lt;br /&gt;
        bonusVariationTitle: [&lt;br /&gt;
          &amp;quot;Evolution of Average Damage&amp;quot;,&lt;br /&gt;
          &amp;quot;Relative to a Bonus Value&amp;quot;,&lt;br /&gt;
        ],&lt;br /&gt;
      },&lt;br /&gt;
      tr: {&lt;br /&gt;
        damages: &amp;quot;Hasar&amp;quot;,&lt;br /&gt;
        percentage: &amp;quot;Yüzde&amp;quot;,&lt;br /&gt;
        miss: &amp;quot;Miss Vuruş&amp;quot;,&lt;br /&gt;
        normalHit: &amp;quot;Düz Vuruş&amp;quot;,&lt;br /&gt;
        criticalHit: &amp;quot;Kritik Vuruş&amp;quot;,&lt;br /&gt;
        piercingHit: &amp;quot;Delici Vuruş&amp;quot;,&lt;br /&gt;
        criticalPiercingHit: &amp;quot;Kritikli Delici Vuruş&amp;quot;,&lt;br /&gt;
        damagesRepartition: &amp;quot;Hasar Dağılımı&amp;quot;,&lt;br /&gt;
        averageDamages: &amp;quot;Ortalama Hasar&amp;quot;,&lt;br /&gt;
        damagesAugmentation: &amp;quot;Ortalama Hasar Artışı&amp;quot;,&lt;br /&gt;
        bonusVariationTitle: [&lt;br /&gt;
          &amp;quot;Bir bonusun değerine kıyasla&amp;quot;,&lt;br /&gt;
          &amp;quot;Ortalama Hasar Çizelgesi&amp;quot;,&lt;br /&gt;
        ],&lt;br /&gt;
      },&lt;br /&gt;
      ro: {&lt;br /&gt;
        damages: &amp;quot;Daune&amp;quot;,&lt;br /&gt;
        percentage: &amp;quot;Procent&amp;quot;,&lt;br /&gt;
        miss: &amp;quot;Miss&amp;quot;,&lt;br /&gt;
        normalHit: &amp;quot;Lovitura normala&amp;quot;,&lt;br /&gt;
        criticalHit: &amp;quot;Lovitura critica&amp;quot;,&lt;br /&gt;
        piercingHit: &amp;quot;Lovitura patrunzatoare&amp;quot;,&lt;br /&gt;
        criticalPiercingHit: &amp;quot;Lovitura critica si patrunzatoare&amp;quot;,&lt;br /&gt;
        damagesRepartition: &amp;quot;Distribuția daunelor&amp;quot;,&lt;br /&gt;
        averageDamages: &amp;quot;Media damageului&amp;quot;,&lt;br /&gt;
        damagesAugmentation: &amp;quot;Damage imbunatatit&amp;quot;,&lt;br /&gt;
        bonusVariationTitle: [&lt;br /&gt;
          &amp;quot;Evolutia mediei damageului&amp;quot;,&lt;br /&gt;
          &amp;quot;relativ la o valoare bonus&amp;quot;,&lt;br /&gt;
        ],&lt;br /&gt;
      },&lt;br /&gt;
      de: {&lt;br /&gt;
        damages: &amp;quot;Schäden&amp;quot;,&lt;br /&gt;
        percentage: &amp;quot;Prozentsatz&amp;quot;,&lt;br /&gt;
        miss: &amp;quot;Verfehlen&amp;quot;,&lt;br /&gt;
        normalHit: &amp;quot;Normaler Treffer&amp;quot;,&lt;br /&gt;
        criticalHit: &amp;quot;Kritischer Treffer&amp;quot;,&lt;br /&gt;
        piercingHit: &amp;quot;Durchdringender Treffer&amp;quot;,&lt;br /&gt;
        criticalPiercingHit: &amp;quot;Kritischer durchdringender Treffer&amp;quot;,&lt;br /&gt;
        damagesRepartition: &amp;quot;Schadensverteilung&amp;quot;,&lt;br /&gt;
        averageDamages: &amp;quot;Durchschnittlicher Schaden&amp;quot;,&lt;br /&gt;
        damagesAugmentation: &amp;quot;Schadenserhöhung&amp;quot;,&lt;br /&gt;
        bonusVariationTitle: [&lt;br /&gt;
          &amp;quot;Entwicklung des durchschnittlichen Schadens&amp;quot;,&lt;br /&gt;
          &amp;quot;im Verhältnis zu einem Bonus&amp;quot;,&lt;br /&gt;
        ],&lt;br /&gt;
      },&lt;br /&gt;
      pt: {&lt;br /&gt;
        damages: &amp;quot;Dano&amp;quot;,&lt;br /&gt;
        percentage: &amp;quot;Percentagem&amp;quot;,&lt;br /&gt;
        miss: &amp;quot;Miss&amp;quot;,&lt;br /&gt;
        normalHit: &amp;quot;Dano normal&amp;quot;,&lt;br /&gt;
        criticalHit: &amp;quot;Dano crítico&amp;quot;,&lt;br /&gt;
        piercingHit: &amp;quot;Dano perfurante&amp;quot;,&lt;br /&gt;
        criticalPiercingHit: &amp;quot;Dano crítico perfurante&amp;quot;,&lt;br /&gt;
        damagesRepartition: &amp;quot;Repartição de dano&amp;quot;,&lt;br /&gt;
        averageDamages: &amp;quot;Dano médio&amp;quot;,&lt;br /&gt;
        damagesAugmentation: &amp;quot;Aumento de dano&amp;quot;,&lt;br /&gt;
        bonusVariationTitle: [&amp;quot;Evolução do dano médio&amp;quot;, &amp;quot;relativo a um bónus&amp;quot;],&lt;br /&gt;
      },&lt;br /&gt;
      // es: {&lt;br /&gt;
      //   damages: &amp;quot;Daño&amp;quot;,&lt;br /&gt;
      //   percentage: &amp;quot;Porcentaje&amp;quot;,&lt;br /&gt;
      //   miss: &amp;quot;Miss&amp;quot;,&lt;br /&gt;
      //   normalHit: &amp;quot;Daño normal&amp;quot;,&lt;br /&gt;
      //   criticalHit: &amp;quot;Daño crítico&amp;quot;,&lt;br /&gt;
      //   piercingHit: &amp;quot;Daño perforante&amp;quot;,&lt;br /&gt;
      //   criticalPiercingHit: &amp;quot;Daño crítico perforante&amp;quot;,&lt;br /&gt;
      //   damagesRepartition: &amp;quot;Repartición de daños&amp;quot;,&lt;br /&gt;
      //   averageDamages: &amp;quot;Daño medio&amp;quot;,&lt;br /&gt;
      //   damagesAugmentation: &amp;quot;Aumento de daño&amp;quot;,&lt;br /&gt;
      //   bonusVariationTitle: [&amp;quot;Evolución del daño medio&amp;quot;, &amp;quot;Relativo a una bonificación&amp;quot;]&lt;br /&gt;
      // },&lt;br /&gt;
    },&lt;br /&gt;
  };&lt;br /&gt;
  return constants;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initResultTableHistory(battle) {&lt;br /&gt;
  var {&lt;br /&gt;
    tableResultHistory,&lt;br /&gt;
    savedFights,&lt;br /&gt;
    deleteFightTemplate,&lt;br /&gt;
    numberFormats: { default: numberFormat },&lt;br /&gt;
  } = battle;&lt;br /&gt;
  var startIndex = 3;&lt;br /&gt;
&lt;br /&gt;
  if (savedFights.length) {&lt;br /&gt;
    hideElement(tableResultHistory.rows[1]);&lt;br /&gt;
&lt;br /&gt;
    for (var savedFight of savedFights) {&lt;br /&gt;
      addRowToTableResultHistory(&lt;br /&gt;
        tableResultHistory,&lt;br /&gt;
        savedFight,&lt;br /&gt;
        deleteFightTemplate,&lt;br /&gt;
        numberFormat&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  tableResultHistory.addEventListener(&amp;quot;click&amp;quot;, function (event) {&lt;br /&gt;
    var deleteButton = event.target.closest(&amp;quot;.svg-icon-delete&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (deleteButton) {&lt;br /&gt;
      var row = deleteButton.closest(&amp;quot;tr&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
      if (row) {&lt;br /&gt;
        savedFights.splice(row.rowIndex - startIndex, 1);&lt;br /&gt;
        updateSavedFights(savedFights);&lt;br /&gt;
&lt;br /&gt;
        row.remove();&lt;br /&gt;
&lt;br /&gt;
        if (tableResultHistory.rows.length === startIndex) {&lt;br /&gt;
          showElement(tableResultHistory.rows[1]);&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initDamagesChart(battle) {&lt;br /&gt;
  var { translation, reduceChartPointsContainer, reduceChartPoints } = battle;&lt;br /&gt;
  var percentFormat = battle.numberFormats.percent;&lt;br /&gt;
  var customPlugins = {&lt;br /&gt;
    id: &amp;quot;customPlugins&amp;quot;,&lt;br /&gt;
    afterDraw(chart) {&lt;br /&gt;
      var missPercentage = chart.data.missPercentage;&lt;br /&gt;
&lt;br /&gt;
      if (!missPercentage) {&lt;br /&gt;
        return;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      var {&lt;br /&gt;
        ctx,&lt;br /&gt;
        chartArea: { top, right },&lt;br /&gt;
      } = chart;&lt;br /&gt;
      ctx.save();&lt;br /&gt;
      var text =&lt;br /&gt;
        translation.miss + &amp;quot; : &amp;quot; + percentFormat.format(missPercentage);&lt;br /&gt;
      var padding = 4;&lt;br /&gt;
      var fontSize = 14;&lt;br /&gt;
&lt;br /&gt;
      ctx.font = fontSize + &amp;quot;px Helvetica Neue&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
      var textWidth = ctx.measureText(text).width;&lt;br /&gt;
      var xPosition = right - textWidth - 5;&lt;br /&gt;
      var yPosition = top + 5;&lt;br /&gt;
&lt;br /&gt;
      ctx.fillStyle = &amp;quot;rgba(255, 0, 0, 0.2)&amp;quot;;&lt;br /&gt;
      ctx.fillRect(&lt;br /&gt;
        xPosition - padding,&lt;br /&gt;
        yPosition - padding,&lt;br /&gt;
        textWidth + 2 * padding,&lt;br /&gt;
        fontSize + 2 * padding&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      ctx.strokeStyle = &amp;quot;red&amp;quot;;&lt;br /&gt;
      ctx.strokeRect(&lt;br /&gt;
        xPosition - padding,&lt;br /&gt;
        yPosition - padding,&lt;br /&gt;
        textWidth + 2 * padding,&lt;br /&gt;
        fontSize + 2 * padding&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      ctx.fillStyle = &amp;quot;#666&amp;quot;;&lt;br /&gt;
      ctx.textBaseline = &amp;quot;top&amp;quot;;&lt;br /&gt;
      ctx.fillText(text, xPosition, yPosition + 1);&lt;br /&gt;
&lt;br /&gt;
      ctx.restore();&lt;br /&gt;
    },&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  Chart.register(customPlugins);&lt;br /&gt;
&lt;br /&gt;
  var ctx = battle.plotDamages.getContext(&amp;quot;2d&amp;quot;);&lt;br /&gt;
  var maxLabelsInTooltip = 10;&lt;br /&gt;
  var nullLabelText = &amp;quot; ...&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  var chart = new Chart(ctx, {&lt;br /&gt;
    type: &amp;quot;scatter&amp;quot;,&lt;br /&gt;
    data: {&lt;br /&gt;
      missPercentage: 0,&lt;br /&gt;
      datasets: [],&lt;br /&gt;
    },&lt;br /&gt;
    options: {&lt;br /&gt;
      responsive: true,&lt;br /&gt;
      maintainAspectRatio: false,&lt;br /&gt;
      plugins: {&lt;br /&gt;
        legend: {&lt;br /&gt;
          display: true,&lt;br /&gt;
          onHover: function (e) {&lt;br /&gt;
            e.native.target.style.cursor = &amp;quot;pointer&amp;quot;;&lt;br /&gt;
          },&lt;br /&gt;
          onLeave: function (e) {&lt;br /&gt;
            e.native.target.style.cursor = &amp;quot;default&amp;quot;;&lt;br /&gt;
          },&lt;br /&gt;
          onClick: function (e, legendItem, legend) {&lt;br /&gt;
            var currentIndex = legendItem.datasetIndex;&lt;br /&gt;
            var ci = legend.chart;&lt;br /&gt;
            var isCurrentDatasetVisible = ci.isDatasetVisible(currentIndex);&lt;br /&gt;
            var datasets = ci.data.datasets;&lt;br /&gt;
            var hideReducePoints = true;&lt;br /&gt;
            var isReducePointsChecked = reduceChartPoints.checked;&lt;br /&gt;
&lt;br /&gt;
            datasets[currentIndex].hidden = isCurrentDatasetVisible;&lt;br /&gt;
            legendItem.hidden = isCurrentDatasetVisible;&lt;br /&gt;
&lt;br /&gt;
            for (var index in datasets) {&lt;br /&gt;
              if (ci.isDatasetVisible(index) &amp;amp;&amp;amp; datasets[index].canBeReduced) {&lt;br /&gt;
                showElement(reduceChartPointsContainer);&lt;br /&gt;
                hideReducePoints = false;&lt;br /&gt;
                break;&lt;br /&gt;
              }&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            if (hideReducePoints) {&lt;br /&gt;
              hideElement(reduceChartPointsContainer);&lt;br /&gt;
              handleChartAnimations(ci, true);&lt;br /&gt;
            } else {&lt;br /&gt;
              handleChartAnimations(ci, isReducePointsChecked);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            ci.update();&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        title: {&lt;br /&gt;
          display: true,&lt;br /&gt;
          text: translation.damagesRepartition,&lt;br /&gt;
          font: {&lt;br /&gt;
            size: 20,&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        tooltip: {&lt;br /&gt;
          callbacks: {&lt;br /&gt;
            label: function (context) {&lt;br /&gt;
              if (context.label === null) {&lt;br /&gt;
                return nullLabelText;&lt;br /&gt;
              }&lt;br /&gt;
&lt;br /&gt;
              var xValue = battle.numberFormats.default.format(&lt;br /&gt;
                context.parsed.x&lt;br /&gt;
              );&lt;br /&gt;
              var yValue = battle.numberFormats.percent.format(&lt;br /&gt;
                context.parsed.y&lt;br /&gt;
              );&lt;br /&gt;
&lt;br /&gt;
              label =&lt;br /&gt;
                &amp;quot; &amp;quot; +&lt;br /&gt;
                context.dataset.label +&lt;br /&gt;
                &amp;quot; : (&amp;quot; +&lt;br /&gt;
                xValue +&lt;br /&gt;
                &amp;quot;, &amp;quot; +&lt;br /&gt;
                yValue +&lt;br /&gt;
                &amp;quot;)&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
              return label;&lt;br /&gt;
            },&lt;br /&gt;
            beforeBody: function (tooltipItems) {&lt;br /&gt;
              if (tooltipItems.length &amp;gt; maxLabelsInTooltip + 1) {&lt;br /&gt;
                tooltipItems.splice(maxLabelsInTooltip + 1);&lt;br /&gt;
                tooltipItems[maxLabelsInTooltip].label = null;&lt;br /&gt;
              }&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          caretPadding: 10,&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
      scales: {&lt;br /&gt;
        x: {&lt;br /&gt;
          type: &amp;quot;linear&amp;quot;,&lt;br /&gt;
          position: &amp;quot;bottom&amp;quot;,&lt;br /&gt;
          title: {&lt;br /&gt;
            display: true,&lt;br /&gt;
            text: translation.damages,&lt;br /&gt;
            font: {&lt;br /&gt;
              size: 16,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        y: {&lt;br /&gt;
          title: {&lt;br /&gt;
            display: true,&lt;br /&gt;
            text: translation.percentage,&lt;br /&gt;
            font: {&lt;br /&gt;
              size: 16,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          ticks: {&lt;br /&gt;
            format: {&lt;br /&gt;
              style: &amp;quot;percent&amp;quot;,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
      elements: {&lt;br /&gt;
        point: {&lt;br /&gt;
          borderWidth: 1,&lt;br /&gt;
          radius: 3,&lt;br /&gt;
          hitRadius: 3,&lt;br /&gt;
          hoverRadius: 6,&lt;br /&gt;
          hoverBorderWidth: 2,&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
    },&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  var datasetsStyle = [&lt;br /&gt;
    {&lt;br /&gt;
      name: &amp;quot;normalHit&amp;quot;,&lt;br /&gt;
      canBeReduced: false,&lt;br /&gt;
      label: translation.normalHit,&lt;br /&gt;
      backgroundColor: &amp;quot;rgba(75, 192, 192, 0.2)&amp;quot;,&lt;br /&gt;
      borderColor: &amp;quot;rgba(75, 192, 192, 1)&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      name: &amp;quot;piercingHit&amp;quot;,&lt;br /&gt;
      canBeReduced: false,&lt;br /&gt;
      label: translation.piercingHit,&lt;br /&gt;
      backgroundColor: &amp;quot;rgba(192, 192, 75, 0.2)&amp;quot;,&lt;br /&gt;
      borderColor: &amp;quot;rgba(192, 192, 75, 1)&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      name: &amp;quot;criticalHit&amp;quot;,&lt;br /&gt;
      canBeReduced: false,&lt;br /&gt;
      label: translation.criticalHit,&lt;br /&gt;
      backgroundColor: &amp;quot;rgba(192, 75, 192, 0.2)&amp;quot;,&lt;br /&gt;
      borderColor: &amp;quot;rgba(192, 75, 192, 1)&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      name: &amp;quot;criticalPiercingHit&amp;quot;,&lt;br /&gt;
      canBeReduced: false,&lt;br /&gt;
      label: translation.criticalPiercingHit,&lt;br /&gt;
      backgroundColor: &amp;quot;rgba(75, 75, 192, 0.2)&amp;quot;,&lt;br /&gt;
      borderColor: &amp;quot;rgba(75, 75, 192, 1)&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
  ];&lt;br /&gt;
  battle.damagesChart = {&lt;br /&gt;
    chart: chart,&lt;br /&gt;
    datasetsStyle: datasetsStyle,&lt;br /&gt;
    maxPoints: 500,&lt;br /&gt;
    reduceChartPointsContainer: reduceChartPointsContainer,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initBonusVariationChart(battle) {&lt;br /&gt;
  var translation = battle.translation;&lt;br /&gt;
&lt;br /&gt;
  var ctx = battle.plotBonusVariation.getContext(&amp;quot;2d&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  var chart = new Chart(ctx, {&lt;br /&gt;
    type: &amp;quot;line&amp;quot;,&lt;br /&gt;
    data: {&lt;br /&gt;
      datasets: [&lt;br /&gt;
        {&lt;br /&gt;
          label: translation.averageDamages,&lt;br /&gt;
          backgroundColor: &amp;quot;rgba(75, 192, 192, 0.2)&amp;quot;,&lt;br /&gt;
          borderColor: &amp;quot;rgba(75, 192, 192, 1)&amp;quot;,&lt;br /&gt;
          fill: true,&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          label: translation.damagesAugmentation,&lt;br /&gt;
          backgroundColor: &amp;quot;rgba(192, 192, 75, 0.2)&amp;quot;,&lt;br /&gt;
          borderColor: &amp;quot;rgba(192, 192, 75, 1)&amp;quot;,&lt;br /&gt;
          hidden: true,&lt;br /&gt;
          yTicksFormat: { style: &amp;quot;percent&amp;quot; },&lt;br /&gt;
          fill: true,&lt;br /&gt;
        },&lt;br /&gt;
      ],&lt;br /&gt;
    },&lt;br /&gt;
    options: {&lt;br /&gt;
      responsive: true,&lt;br /&gt;
      maintainAspectRatio: false,&lt;br /&gt;
      plugins: {&lt;br /&gt;
        legend: {&lt;br /&gt;
          display: true,&lt;br /&gt;
          onHover: function (e) {&lt;br /&gt;
            e.native.target.style.cursor = &amp;quot;pointer&amp;quot;;&lt;br /&gt;
          },&lt;br /&gt;
          onLeave: function (e) {&lt;br /&gt;
            e.native.target.style.cursor = &amp;quot;default&amp;quot;;&lt;br /&gt;
          },&lt;br /&gt;
          onClick: function (e, legendItem, legend) {&lt;br /&gt;
            var currentIndex = legendItem.datasetIndex;&lt;br /&gt;
            var ci = legend.chart;&lt;br /&gt;
            var datasets = ci.data.datasets;&lt;br /&gt;
            var isCurrentDatasetVisible = ci.isDatasetVisible(currentIndex);&lt;br /&gt;
            var yAxis = ci.options.scales.y;&lt;br /&gt;
&lt;br /&gt;
            var otherIndex = currentIndex === 0 ? 1 : 0;&lt;br /&gt;
            var visibleDataset = isCurrentDatasetVisible&lt;br /&gt;
              ? datasets[otherIndex]&lt;br /&gt;
              : datasets[currentIndex];&lt;br /&gt;
&lt;br /&gt;
            datasets[currentIndex].hidden = isCurrentDatasetVisible;&lt;br /&gt;
            datasets[otherIndex].hidden = !isCurrentDatasetVisible;&lt;br /&gt;
&lt;br /&gt;
            yAxis.title.text = visibleDataset.label;&lt;br /&gt;
            yAxis.ticks.format = visibleDataset.yTicksFormat;&lt;br /&gt;
&lt;br /&gt;
            ci.update();&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        title: {&lt;br /&gt;
          display: true,&lt;br /&gt;
          text: translation.bonusVariationTitle,&lt;br /&gt;
          font: {&lt;br /&gt;
            size: 18,&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        tooltip: {&lt;br /&gt;
          caretPadding: 10,&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
      scales: {&lt;br /&gt;
        x: {&lt;br /&gt;
          type: &amp;quot;linear&amp;quot;,&lt;br /&gt;
          position: &amp;quot;bottom&amp;quot;,&lt;br /&gt;
          title: {&lt;br /&gt;
            display: true,&lt;br /&gt;
            text: &amp;quot;Bonus&amp;quot;,&lt;br /&gt;
            font: {&lt;br /&gt;
              size: 16,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          ticks: {&lt;br /&gt;
            callback: function (value) {&lt;br /&gt;
              if (Number.isInteger(value)) {&lt;br /&gt;
                return Number(value);&lt;br /&gt;
              }&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        y: {&lt;br /&gt;
          title: {&lt;br /&gt;
            display: true,&lt;br /&gt;
            text: translation.averageDamages,&lt;br /&gt;
            font: {&lt;br /&gt;
              size: 16,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
      elements: {&lt;br /&gt;
        point: {&lt;br /&gt;
          borderWidth: 1,&lt;br /&gt;
          radius: 3,&lt;br /&gt;
          hitRadius: 3,&lt;br /&gt;
          hoverRadius: 6,&lt;br /&gt;
          hoverBorderWidth: 2,&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
    },&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  battle.bonusVariationChart = chart;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function attackSelectonListener(&lt;br /&gt;
  characters,&lt;br /&gt;
  attackerSelection,&lt;br /&gt;
  attackTypeSelection&lt;br /&gt;
) {&lt;br /&gt;
  attackerSelection.addEventListener(&amp;quot;change&amp;quot;, function (event) {&lt;br /&gt;
    var attackerName = event.target.value;&lt;br /&gt;
&lt;br /&gt;
    if (isPseudoSaved(characters, attackerName)) {&lt;br /&gt;
      var attacker = characters.savedCharacters[attackerName];&lt;br /&gt;
      filterAttackTypeSelection(attacker, attackTypeSelection);&lt;br /&gt;
    } else {&lt;br /&gt;
      filterAttackTypeSelectionMonster(attackTypeSelection);&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getTranslation(translation) {&lt;br /&gt;
  var userLanguage = navigator.language;&lt;br /&gt;
  var langToUse = &amp;quot;en&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  for (var lang in translation) {&lt;br /&gt;
    if (userLanguage.startsWith(lang)) {&lt;br /&gt;
      langToUse = lang;&lt;br /&gt;
      break;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return translation[langToUse];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createDamageCalculatorInformation(chartSource) {&lt;br /&gt;
  var characters = {&lt;br /&gt;
    unsavedChanges: false,&lt;br /&gt;
    savedCharacters: {},&lt;br /&gt;
    currentCharacter: null,&lt;br /&gt;
    savedMonsters: getSavedMonsters(),&lt;br /&gt;
    characterCreation: document.getElementById(&amp;quot;character-creation&amp;quot;),&lt;br /&gt;
    addNewCharacterButton: document.getElementById(&amp;quot;add-new-character&amp;quot;),&lt;br /&gt;
    dropZone: document.getElementById(&amp;quot;character-drop-zone&amp;quot;),&lt;br /&gt;
    characterInput: document.getElementById(&amp;quot;character-input&amp;quot;),&lt;br /&gt;
    newCharacterTemplate: document.getElementById(&amp;quot;new-character-template&amp;quot;)&lt;br /&gt;
      .children[0],&lt;br /&gt;
    charactersContainer: document.getElementById(&amp;quot;characters-container&amp;quot;),&lt;br /&gt;
    monsterButtonTemplates: document.getElementById(&amp;quot;monster-button-templates&amp;quot;),&lt;br /&gt;
    monsterTemplate: document.getElementById(&amp;quot;new-monster-template&amp;quot;)&lt;br /&gt;
      .children[0],&lt;br /&gt;
    monstersContainer: document.getElementById(&amp;quot;monsters-container&amp;quot;),&lt;br /&gt;
    monsteriFrame: document.getElementById(&amp;quot;monster-iframe&amp;quot;),&lt;br /&gt;
    stoneiFrame: document.getElementById(&amp;quot;stone-iframe&amp;quot;),&lt;br /&gt;
    saveButton: document.getElementById(&amp;quot;save-character&amp;quot;),&lt;br /&gt;
    weaponCategory: document.getElementById(&amp;quot;weapon-category&amp;quot;),&lt;br /&gt;
    weaponDisplay: document.getElementById(&amp;quot;weapon-display&amp;quot;),&lt;br /&gt;
    randomAttackValue: document.getElementById(&amp;quot;random-attack-value&amp;quot;),&lt;br /&gt;
    randomMagicAttackValue: document.getElementById(&lt;br /&gt;
      &amp;quot;random-magic-attack-value&amp;quot;&lt;br /&gt;
    ),&lt;br /&gt;
    yoharaCreation: document.getElementById(&amp;quot;yohara-creation&amp;quot;),&lt;br /&gt;
    blessingCreation: document.getElementById(&amp;quot;blessing-creation&amp;quot;),&lt;br /&gt;
    marriageCreation: document.getElementById(&amp;quot;marriage-creation&amp;quot;),&lt;br /&gt;
    bonusVariation: {&lt;br /&gt;
      tab: document.getElementById(&amp;quot;Variation&amp;quot;),&lt;br /&gt;
      activation: document.getElementById(&amp;quot;bonus-variation-activation&amp;quot;),&lt;br /&gt;
      input: document.getElementById(&amp;quot;bonus-variation&amp;quot;),&lt;br /&gt;
      inputDisplay: document.getElementById(&amp;quot;bonus-variation-display&amp;quot;),&lt;br /&gt;
      container: document.getElementById(&amp;quot;bonus-variation-range&amp;quot;),&lt;br /&gt;
      minValue: document.getElementById(&amp;quot;bonus-variation-min-value&amp;quot;),&lt;br /&gt;
      maxValue: document.getElementById(&amp;quot;bonus-variation-max-value&amp;quot;),&lt;br /&gt;
    },&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  characters.bonusVariation.inputDisplay.setAttribute(&amp;quot;readonly&amp;quot;, &amp;quot;&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  for (var [pseudo, character] of Object.entries(getSavedCharacters())) {&lt;br /&gt;
    characters.savedCharacters[pseudo] = character;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var skillContainer = document.getElementById(&amp;quot;skill-container&amp;quot;);&lt;br /&gt;
  characters.skillElementsToFilter =&lt;br /&gt;
    skillContainer.querySelectorAll(&amp;quot;[data-class]&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  var mapping = createMapping();&lt;br /&gt;
  var constants = createConstants();&lt;br /&gt;
&lt;br /&gt;
  var battle = {&lt;br /&gt;
    resetAttackType: false,&lt;br /&gt;
    savedFights: getSavedFights(),&lt;br /&gt;
    battleForm: document.getElementById(&amp;quot;create-battle&amp;quot;),&lt;br /&gt;
    attackerSelection: document.getElementById(&amp;quot;attacker-selection&amp;quot;),&lt;br /&gt;
    attackTypeSelection: document.getElementById(&amp;quot;attack-type-selection&amp;quot;),&lt;br /&gt;
    victimSelection: document.getElementById(&amp;quot;victim-selection&amp;quot;),&lt;br /&gt;
    damagesWeightedByType: {},&lt;br /&gt;
    scatterDataByType: {},&lt;br /&gt;
    damagesByBonus: [],&lt;br /&gt;
    tableResultFight: document.getElementById(&amp;quot;result-table-fight&amp;quot;),&lt;br /&gt;
    tableResultHistory: document.getElementById(&amp;quot;result-table-history&amp;quot;),&lt;br /&gt;
    deleteFightTemplate: document.getElementById(&amp;quot;delete-fight-template&amp;quot;)&lt;br /&gt;
      .children[0],&lt;br /&gt;
    errorInformation: {},&lt;br /&gt;
    fightResultContainer: document.getElementById(&amp;quot;fight-result-container&amp;quot;),&lt;br /&gt;
    downLoadRawData: document.getElementById(&amp;quot;download-raw-data&amp;quot;),&lt;br /&gt;
    downLoadRawDataVariation: document.getElementById(&lt;br /&gt;
      &amp;quot;download-raw-data-variation&amp;quot;&lt;br /&gt;
    ),&lt;br /&gt;
    bonusVariationResultContainer: document.getElementById(&lt;br /&gt;
      &amp;quot;bonus-variation-result-container&amp;quot;&lt;br /&gt;
    ),&lt;br /&gt;
    reduceChartPointsContainer: document.getElementById(&lt;br /&gt;
      &amp;quot;reduce-chart-points-container&amp;quot;&lt;br /&gt;
    ),&lt;br /&gt;
    reduceChartPoints: document.getElementById(&amp;quot;reduce-chart-points&amp;quot;),&lt;br /&gt;
    plotDamages: document.getElementById(&amp;quot;plot-damages&amp;quot;),&lt;br /&gt;
    plotBonusVariation: document.getElementById(&amp;quot;plot-bonus-variation&amp;quot;),&lt;br /&gt;
    uniqueDamagesCounters: document.querySelectorAll(&amp;quot;.unique-damages-counter&amp;quot;),&lt;br /&gt;
    possibleDamagesCounter: document.getElementById(&amp;quot;possible-damages-counter&amp;quot;),&lt;br /&gt;
    damagesTime: document.getElementById(&amp;quot;damages-time&amp;quot;),&lt;br /&gt;
    displayTime: document.getElementById(&amp;quot;display-time&amp;quot;),&lt;br /&gt;
    simulationCounter: document.getElementById(&amp;quot;simulation-counter&amp;quot;),&lt;br /&gt;
    simulationTime: document.getElementById(&amp;quot;simulation-time&amp;quot;),&lt;br /&gt;
    numberFormats: {&lt;br /&gt;
      default: new Intl.NumberFormat(undefined, {&lt;br /&gt;
        minimumFractionDigits: 0,&lt;br /&gt;
        maximumFractionDigits: 1,&lt;br /&gt;
      }),&lt;br /&gt;
      percent: new Intl.NumberFormat(undefined, {&lt;br /&gt;
        style: &amp;quot;percent&amp;quot;,&lt;br /&gt;
        maximumFractionDigits: 3,&lt;br /&gt;
      }),&lt;br /&gt;
      second: new Intl.NumberFormat(undefined, {&lt;br /&gt;
        style: &amp;quot;unit&amp;quot;,&lt;br /&gt;
        unit: &amp;quot;second&amp;quot;,&lt;br /&gt;
        unitDisplay: &amp;quot;long&amp;quot;,&lt;br /&gt;
        maximumFractionDigits: 3,&lt;br /&gt;
      }),&lt;br /&gt;
    },&lt;br /&gt;
    mapping: mapping,&lt;br /&gt;
    constants: constants,&lt;br /&gt;
    translation: getTranslation(constants.translation),&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  attackSelectonListener(&lt;br /&gt;
    characters,&lt;br /&gt;
    battle.attackerSelection,&lt;br /&gt;
    battle.attackTypeSelection&lt;br /&gt;
  );&lt;br /&gt;
  initResultTableHistory(battle);&lt;br /&gt;
  addScript(chartSource, function () {&lt;br /&gt;
    initDamagesChart(battle);&lt;br /&gt;
    initBonusVariationChart(battle);&lt;br /&gt;
  });&lt;br /&gt;
  reduceChartPointsListener(battle);&lt;br /&gt;
  downloadRawDataListener(battle);&lt;br /&gt;
&lt;br /&gt;
  var errorElements = document.querySelectorAll(&amp;quot;[data-error]&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; errorElements.length; index++) {&lt;br /&gt;
    var errorElement = errorElements[index];&lt;br /&gt;
    battle.errorInformation[errorElement.dataset.error] = errorElement;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return [characters, battle];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadStyle(src) {&lt;br /&gt;
  var link = document.createElement(&amp;quot;link&amp;quot;);&lt;br /&gt;
  link.href = src;&lt;br /&gt;
  link.rel = &amp;quot;stylesheet&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  document.head.appendChild(link);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
(function () {&lt;br /&gt;
  var javascriptSource =&lt;br /&gt;
    &amp;quot;/index.php?title=Utilisateur:Ankhseram/Calculator.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&amp;quot;;&lt;br /&gt;
  var cssSource =&lt;br /&gt;
    &amp;quot;/index.php?title=Utilisateur:Ankhseram/Style.css&amp;amp;action=raw&amp;amp;ctype=text/css&amp;quot;;&lt;br /&gt;
  var chartSource = &amp;quot;https://cdn.jsdelivr.net/npm/chart.js&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  loadStyle(cssSource);&lt;br /&gt;
&lt;br /&gt;
  function main() {&lt;br /&gt;
    var [characters, battle] = createDamageCalculatorInformation(chartSource);&lt;br /&gt;
&lt;br /&gt;
    characterManagement(characters, battle);&lt;br /&gt;
    monsterManagement(characters, battle);&lt;br /&gt;
&lt;br /&gt;
    updateBattleChoice(characters, battle);&lt;br /&gt;
    createBattle(characters, battle);&lt;br /&gt;
  }&lt;br /&gt;
  addScript(javascriptSource, main);&lt;br /&gt;
})();&lt;/div&gt;</summary>
		<author><name>Dexter</name></author>
		
	</entry>
	<entry>
		<id>https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Script/Element.js&amp;diff=105490</id>
		<title>MediaWiki:Script/Element.js</title>
		<link rel="alternate" type="text/html" href="https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Script/Element.js&amp;diff=105490"/>
		<updated>2024-12-06T07:09:11Z</updated>

		<summary type="html">&lt;p&gt;Dexter : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;function camelToKebab(str) {&lt;br /&gt;
  return str.replace(/([a-z0-9])([A-Z])/g, &amp;quot;$1-$2&amp;quot;).toLowerCase();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function copyProperties(source, target, allowedProps) {&lt;br /&gt;
  var sourceKeys = Object.keys(source);&lt;br /&gt;
&lt;br /&gt;
  for (var keyIndex = 0; keyIndex &amp;lt; sourceKeys.length; keyIndex++) {&lt;br /&gt;
    var property = sourceKeys[keyIndex];&lt;br /&gt;
    var propValue = source[property];&lt;br /&gt;
&lt;br /&gt;
    if (property === &amp;quot;viewBox&amp;quot;) {&lt;br /&gt;
      target.setAttribute(property, propValue);&lt;br /&gt;
    } else if (&lt;br /&gt;
      property.indexOf(&amp;quot;data&amp;quot;) === 0 ||&lt;br /&gt;
      allowedProps.indexOf(property) !== -1&lt;br /&gt;
    ) {&lt;br /&gt;
      target.setAttribute(camelToKebab(property), propValue);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createElement(&lt;br /&gt;
  elementsToReplace,&lt;br /&gt;
  elementsNS,&lt;br /&gt;
  allowedProperties,&lt;br /&gt;
  elementDataset,&lt;br /&gt;
  elementType,&lt;br /&gt;
  skillValues&lt;br /&gt;
) {&lt;br /&gt;
  if (elementsNS.indexOf(elementType) !== -1) {&lt;br /&gt;
    var newElement = document.createElementNS(&lt;br /&gt;
      &amp;quot;http://www.w3.org/2000/svg&amp;quot;,&lt;br /&gt;
      elementType&lt;br /&gt;
    );&lt;br /&gt;
  } else {&lt;br /&gt;
    var newElement = document.createElement(elementType);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var childdNodes = elementsToReplace.childNodes;&lt;br /&gt;
&lt;br /&gt;
  copyProperties(elementDataset, newElement, allowedProperties);&lt;br /&gt;
&lt;br /&gt;
  for (var childIndex = 0; childIndex &amp;lt; childdNodes.length; childIndex++) {&lt;br /&gt;
    newElement.appendChild(childdNodes[childIndex].cloneNode(true));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var addAttribute = newElement.dataset.add;&lt;br /&gt;
&lt;br /&gt;
  if (addAttribute &amp;amp;&amp;amp; addAttribute.startsWith(&amp;quot;skill&amp;quot;)) {&lt;br /&gt;
    var maxLevel = Number(addAttribute.split(&amp;quot;skill&amp;quot;)[1]);&lt;br /&gt;
&lt;br /&gt;
    for (var index = 0; index &amp;lt;= maxLevel; index++) {&lt;br /&gt;
      var option = document.createElement(&amp;quot;option&amp;quot;);&lt;br /&gt;
      option.value = index;&lt;br /&gt;
      option.textContent = skillValues[index];&lt;br /&gt;
      newElement.appendChild(option);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return newElement;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function replaceElement(&lt;br /&gt;
  elementsToReplace,&lt;br /&gt;
  allowedElements,&lt;br /&gt;
  elementsNS,&lt;br /&gt;
  allowedProperties,&lt;br /&gt;
  skillValues&lt;br /&gt;
) {&lt;br /&gt;
  var elementDataset = elementsToReplace.dataset;&lt;br /&gt;
  var elementType = elementDataset.element;&lt;br /&gt;
&lt;br /&gt;
  if (allowedElements.indexOf(elementType) !== -1) {&lt;br /&gt;
    var newElement = createElement(&lt;br /&gt;
      elementsToReplace,&lt;br /&gt;
      elementsNS,&lt;br /&gt;
      allowedProperties,&lt;br /&gt;
      elementDataset,&lt;br /&gt;
      elementType,&lt;br /&gt;
      skillValues&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    elementsToReplace.parentNode.replaceChild(newElement, elementsToReplace);&lt;br /&gt;
  } else {&lt;br /&gt;
    elementsToReplace.remove();&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addCollapsible(collapsibleContainer) {&lt;br /&gt;
  var toggleButton = collapsibleContainer.querySelector(&lt;br /&gt;
    &amp;quot;.mw-collapsible-toggle&amp;quot;&lt;br /&gt;
  );&lt;br /&gt;
  var collapsibleContent = collapsibleContainer.querySelector(&lt;br /&gt;
    &amp;quot;.mw-collapsible-content&amp;quot;&lt;br /&gt;
  );&lt;br /&gt;
  var collapsibleContentChild = collapsibleContent.firstElementChild;&lt;br /&gt;
  var expandedClass = &amp;quot;mw-collapsible-toggle-expanded&amp;quot;;&lt;br /&gt;
  var isCollapsed = false;&lt;br /&gt;
&lt;br /&gt;
  toggleButton.setAttribute(&amp;quot;tabindex&amp;quot;, 0);&lt;br /&gt;
&lt;br /&gt;
  toggleButton.addEventListener(&amp;quot;click&amp;quot;, function (event) {&lt;br /&gt;
    if (isCollapsed) {&lt;br /&gt;
      this.classList.remove(expandedClass);&lt;br /&gt;
      collapsibleContentChild.style.overflow = &amp;quot;hidden&amp;quot;;&lt;br /&gt;
      collapsibleContent.style.gridTemplateRows = &amp;quot;0fr&amp;quot;;&lt;br /&gt;
    } else {&lt;br /&gt;
      collapsibleContentChild.classList.remove(&amp;quot;tabber-noactive&amp;quot;);&lt;br /&gt;
      this.classList.add(expandedClass);&lt;br /&gt;
      collapsibleContent.style.gridTemplateRows = &amp;quot;1fr&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
    isCollapsed = !isCollapsed;&lt;br /&gt;
  });&lt;br /&gt;
  toggleButton.addEventListener(&amp;quot;keyup&amp;quot;, function (event) {&lt;br /&gt;
    if (event.keyCode === 13) {&lt;br /&gt;
      this.click();&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
  collapsibleContent.addEventListener(&amp;quot;transitionend&amp;quot;, function (event) {&lt;br /&gt;
    if (isCollapsed) {&lt;br /&gt;
      collapsibleContentChild.style.overflow = &amp;quot;visible&amp;quot;;&lt;br /&gt;
    } else {&lt;br /&gt;
      collapsibleContentChild.classList.add(&amp;quot;tabber-noactive&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
(function () {&lt;br /&gt;
  var allowedElements = [&lt;br /&gt;
    &amp;quot;input&amp;quot;,&lt;br /&gt;
    &amp;quot;button&amp;quot;,&lt;br /&gt;
    &amp;quot;select&amp;quot;,&lt;br /&gt;
    &amp;quot;option&amp;quot;,&lt;br /&gt;
    &amp;quot;label&amp;quot;,&lt;br /&gt;
    &amp;quot;form&amp;quot;,&lt;br /&gt;
    &amp;quot;svg&amp;quot;,&lt;br /&gt;
    &amp;quot;path&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;,&lt;br /&gt;
    &amp;quot;canvas&amp;quot;,&lt;br /&gt;
    &amp;quot;iframe&amp;quot;,&lt;br /&gt;
  ];&lt;br /&gt;
  var elementsNS = [&amp;quot;svg&amp;quot;, &amp;quot;path&amp;quot;, &amp;quot;title&amp;quot;];&lt;br /&gt;
  var allowedProperties = [&lt;br /&gt;
    &amp;quot;id&amp;quot;,&lt;br /&gt;
    &amp;quot;class&amp;quot;,&lt;br /&gt;
    &amp;quot;type&amp;quot;,&lt;br /&gt;
    &amp;quot;name&amp;quot;,&lt;br /&gt;
    &amp;quot;ariaHaspopup&amp;quot;,&lt;br /&gt;
    &amp;quot;ariaExpanded&amp;quot;,&lt;br /&gt;
    &amp;quot;ariaControls&amp;quot;,&lt;br /&gt;
    &amp;quot;for&amp;quot;,&lt;br /&gt;
    &amp;quot;min&amp;quot;,&lt;br /&gt;
    &amp;quot;max&amp;quot;,&lt;br /&gt;
    &amp;quot;value&amp;quot;,&lt;br /&gt;
    &amp;quot;style&amp;quot;,&lt;br /&gt;
    &amp;quot;pattern&amp;quot;,&lt;br /&gt;
    &amp;quot;required&amp;quot;,&lt;br /&gt;
    &amp;quot;selected&amp;quot;,&lt;br /&gt;
    &amp;quot;disabled&amp;quot;,&lt;br /&gt;
    &amp;quot;checked&amp;quot;,&lt;br /&gt;
    &amp;quot;tabindex&amp;quot;,&lt;br /&gt;
    &amp;quot;placeholder&amp;quot;,&lt;br /&gt;
    &amp;quot;xmlns&amp;quot;,&lt;br /&gt;
    &amp;quot;height&amp;quot;,&lt;br /&gt;
    &amp;quot;viewBox&amp;quot;,&lt;br /&gt;
    &amp;quot;width&amp;quot;,&lt;br /&gt;
    &amp;quot;fill&amp;quot;,&lt;br /&gt;
    &amp;quot;d&amp;quot;,&lt;br /&gt;
    &amp;quot;title&amp;quot;,&lt;br /&gt;
  ];&lt;br /&gt;
&lt;br /&gt;
  var skillValues = [&lt;br /&gt;
    0,&lt;br /&gt;
    1,&lt;br /&gt;
    2,&lt;br /&gt;
    3,&lt;br /&gt;
    4,&lt;br /&gt;
    5,&lt;br /&gt;
    6,&lt;br /&gt;
    7,&lt;br /&gt;
    8,&lt;br /&gt;
    9,&lt;br /&gt;
    10,&lt;br /&gt;
    11,&lt;br /&gt;
    12,&lt;br /&gt;
    13,&lt;br /&gt;
    14,&lt;br /&gt;
    15,&lt;br /&gt;
    16,&lt;br /&gt;
    17,&lt;br /&gt;
    18,&lt;br /&gt;
    19,&lt;br /&gt;
    &amp;quot;M1&amp;quot;,&lt;br /&gt;
    &amp;quot;M2&amp;quot;,&lt;br /&gt;
    &amp;quot;M3&amp;quot;,&lt;br /&gt;
    &amp;quot;M4&amp;quot;,&lt;br /&gt;
    &amp;quot;M5&amp;quot;,&lt;br /&gt;
    &amp;quot;M6&amp;quot;,&lt;br /&gt;
    &amp;quot;M7&amp;quot;,&lt;br /&gt;
    &amp;quot;M8&amp;quot;,&lt;br /&gt;
    &amp;quot;M9&amp;quot;,&lt;br /&gt;
    &amp;quot;M10&amp;quot;,&lt;br /&gt;
    &amp;quot;G1&amp;quot;,&lt;br /&gt;
    &amp;quot;G2&amp;quot;,&lt;br /&gt;
    &amp;quot;G3&amp;quot;,&lt;br /&gt;
    &amp;quot;G4&amp;quot;,&lt;br /&gt;
    &amp;quot;G5&amp;quot;,&lt;br /&gt;
    &amp;quot;G6&amp;quot;,&lt;br /&gt;
    &amp;quot;G7&amp;quot;,&lt;br /&gt;
    &amp;quot;G8&amp;quot;,&lt;br /&gt;
    &amp;quot;G9&amp;quot;,&lt;br /&gt;
    &amp;quot;G10&amp;quot;,&lt;br /&gt;
    &amp;quot;P&amp;quot;,&lt;br /&gt;
  ];&lt;br /&gt;
&lt;br /&gt;
  var elementsToReplace = document.querySelector(&amp;quot;div[data-element]&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  while (elementsToReplace) {&lt;br /&gt;
    replaceElement(&lt;br /&gt;
      elementsToReplace,&lt;br /&gt;
      allowedElements,&lt;br /&gt;
      elementsNS,&lt;br /&gt;
      allowedProperties,&lt;br /&gt;
      skillValues&lt;br /&gt;
    );&lt;br /&gt;
    elementsToReplace = document.querySelector(&amp;quot;div[data-element]&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var collapsibleContainers = document.querySelectorAll(&lt;br /&gt;
    &amp;quot;.improved-collapsible.custom-js&amp;quot;&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  for (var collapsibleContainer of collapsibleContainers) {&lt;br /&gt;
    addCollapsible(collapsibleContainer);&lt;br /&gt;
  }&lt;br /&gt;
})();&lt;/div&gt;</summary>
		<author><name>Dexter</name></author>
		
	</entry>
	<entry>
		<id>https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Common.css&amp;diff=105489</id>
		<title>MediaWiki:Common.css</title>
		<link rel="alternate" type="text/html" href="https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Common.css&amp;diff=105489"/>
		<updated>2024-12-06T07:08:15Z</updated>

		<summary type="html">&lt;p&gt;Dexter : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;/* Le CSS placé ici sera chargé sur toutes les pages */&lt;br /&gt;
&lt;br /&gt;
html {&lt;br /&gt;
  scroll-behavior: smooth;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
body {&lt;br /&gt;
  background-image: url('https://fr-wiki.metin2.gameforge.com/images/b/bf/Fondhalloween.png');&lt;br /&gt;
}&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
body {&lt;br /&gt;
  background-image: url('https://fr-wiki.metin2.gameforge.com/images/1/15/Fond2015.jpg');&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#mw-content ul {&lt;br /&gt;
    margin-bottom: 0.3em;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#mw-content ol {&lt;br /&gt;
  list-style: none;&lt;br /&gt;
  counter-reset: custom-counter;&lt;br /&gt;
  margin: 0.3em 0 0.3em 1.6em;&lt;br /&gt;
  padding: 0;&lt;br /&gt;
}&lt;br /&gt;
ol li {&lt;br /&gt;
  padding: 0;&lt;br /&gt;
  counter-increment: custom-counter;&lt;br /&gt;
}&lt;br /&gt;
ol li::marker {&lt;br /&gt;
  content: counter(custom-counter) &amp;quot;.  &amp;quot;;&lt;br /&gt;
  font-weight: bold;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
td, th {&lt;br /&gt;
  padding: 2px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.map span.mw-collapsible-toggle {&lt;br /&gt;
  padding-right: 10px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
table.map a.mw-collapsible-text,&lt;br /&gt;
.prettytable &amp;gt; span.mw-collapsible-toggle,&lt;br /&gt;
.prettytable &amp;gt; span.mw-collapsible-toggle &amp;gt; a {&lt;br /&gt;
  color: #ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.boxesheaderbackground, .cadre &amp;gt; div:first-child {&lt;br /&gt;
  background: repeat url(&amp;quot;https://fr-wiki.metin2.gameforge.com/images/a/a7/Boxheaderbrown.png&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.cadre {&lt;br /&gt;
  border: 1px solid #2f1d1f;&lt;br /&gt;
  border-radius: 15px 0;&lt;br /&gt;
  width: 100%;&lt;br /&gt;
  box-shadow: 3px 3px 9px 0px #544e41;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.cadre &amp;gt; div:first-child {&lt;br /&gt;
  text-align: center;&lt;br /&gt;
  color: white;&lt;br /&gt;
  line-height: 25px;&lt;br /&gt;
  overflow: hidden;&lt;br /&gt;
  border-top-left-radius: 15px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.fondfenetre,&lt;br /&gt;
.sous-titre,&lt;br /&gt;
table.pretty-table th { &lt;br /&gt;
  background: url(&amp;quot;https://fr-wiki.metin2.gameforge.com/images/8/89/Fondfenetre.png&amp;quot;) repeat;&lt;br /&gt;
  color: white;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
table.pretty-table td {&lt;br /&gt;
  padding: 5px 10px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
table.pretty-table th {&lt;br /&gt;
  padding: 2px 10px;&lt;br /&gt;
  font-weight: normal;&lt;br /&gt;
  font-size: 1.1em;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
table.pretty-table tbody &amp;gt; *:nth-child(2n+1) &amp;gt; td {&lt;br /&gt;
  background: rgba(0, 0, 0, .1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
table.pretty-table tr:hover {&lt;br /&gt;
  background: rgba(0, 0, 0, .05);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
table.pretty-table tr:first-child &amp;gt; th:first-child {&lt;br /&gt;
  border-radius: 8px 0 0 0;&lt;br /&gt;
  overflow: hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
table.pretty-table caption {&lt;br /&gt;
  margin-top: 10px;&lt;br /&gt;
  font-weight: bold;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.fondfenetre a,&lt;br /&gt;
.fondfenetre span,&lt;br /&gt;
table.pretty-table th a,&lt;br /&gt;
table.pretty-table th span {&lt;br /&gt;
  color: white;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
table.sticky-header-row thead tr {&lt;br /&gt;
  position: sticky;&lt;br /&gt;
  top: 0;&lt;br /&gt;
  z-index: 10;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
table.sticky-header-column th:first-child {&lt;br /&gt;
  position: sticky;&lt;br /&gt;
  left: 0;&lt;br /&gt;
  z-index: 20;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sous-titre {&lt;br /&gt;
  max-width: 180px;&lt;br /&gt;
  border: 1px solid black;&lt;br /&gt;
  border-radius: 8px;&lt;br /&gt;
  color: white;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.modeleAnnonce {&lt;br /&gt;
  border-image: url(&amp;quot;https://fr-wiki.metin2.gameforge.com/images/f/fb/Modeleannonce.png&amp;quot;) 17 35 3 fill / auto / 0 repeat;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.container { &lt;br /&gt;
 display: flex;&lt;br /&gt;
 flex-direction: row; &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.monster-card { &lt;br /&gt;
 border: 1px black solid;&lt;br /&gt;
 padding: 5px;&lt;br /&gt;
 max-width: 400px;&lt;br /&gt;
 box-sizing: border-box;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.monster-card &amp;gt; :first-child {&lt;br /&gt;
 display: flex;&lt;br /&gt;
 justify-content: space-between;&lt;br /&gt;
 margin-bottom: 5px;&lt;br /&gt;
 line-height: 25px;&lt;br /&gt;
 padding: 0 5px;&lt;br /&gt;
 background: none;&lt;br /&gt;
 background-color: black;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
button.brown {&lt;br /&gt;
  background: #651e10;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
button.brown-transparent {&lt;br /&gt;
  background: #651e10cc;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
button.brown:hover,&lt;br /&gt;
button.brown:focus {&lt;br /&gt;
  background: #551a0e;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
button.red {&lt;br /&gt;
  background: #ef4444;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
button.red:hover,&lt;br /&gt;
button.red:focus {&lt;br /&gt;
  background: #b91c1c;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
button:active {&lt;br /&gt;
  opacity: 0.8;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.button {&lt;br /&gt;
  border: 2px solid grey;&lt;br /&gt;
  padding: 0 12px;&lt;br /&gt;
  line-height: 25px;&lt;br /&gt;
  border-radius: 16px;&lt;br /&gt;
  background: rgba(234, 234, 234);&lt;br /&gt;
  cursor: pointer;&lt;br /&gt;
  display: inline-block;&lt;br /&gt;
  position: relative;&lt;br /&gt;
  user-select: none;&lt;br /&gt;
  white-space: nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.button:hover {&lt;br /&gt;
  background: transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.modal {&lt;br /&gt;
    opacity: 0;&lt;br /&gt;
    visibility: hidden;&lt;br /&gt;
    transform: scale(1.1);&lt;br /&gt;
    transition: visibility 0s linear 0.25s, opacity 0.25s 0s, transform 0.25s;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.close-button {&lt;br /&gt;
  transition: color .2s linear, background-color .2s linear;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.close-button:hover {&lt;br /&gt;
  background-color: red;&lt;br /&gt;
  color: #ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.show-modal {&lt;br /&gt;
    opacity: 1;&lt;br /&gt;
    visibility: visible;&lt;br /&gt;
    transform: scale(1.0);&lt;br /&gt;
    transition: visibility 0s linear 0s, opacity 0.25s 0s, transform 0.25s;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.cacheOrdi,&lt;br /&gt;
.gen-active {&lt;br /&gt;
  display: block;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.texte-long,&lt;br /&gt;
.texte-long-2 {&lt;br /&gt;
  text-overflow: ellipsis;&lt;br /&gt;
  white-space: nowrap;&lt;br /&gt;
  overflow: hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.texte-long:hover,&lt;br /&gt;
.texte-long-2:hover {&lt;br /&gt;
  white-space: normal;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.shop-img img {&lt;br /&gt;
    height: auto;&lt;br /&gt;
    width: auto;&lt;br /&gt;
    max-height: 130px;&lt;br /&gt;
    max-width: 130px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#mw-content .soulignement &amp;gt; a:link {&lt;br /&gt;
  text-decoration: none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.popContenu {&lt;br /&gt;
  display: inline-block;&lt;br /&gt;
  transition: all 0.4s ease;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.popInfo:hover .popContenu {&lt;br /&gt;
  opacity: 1 !important;&lt;br /&gt;
  transition: all 0.4s ease;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.cadreFenetre {&lt;br /&gt;
  border: solid;&lt;br /&gt;
  border-image: url(&amp;quot;https://fr-wiki.metin2.gameforge.com/images/1/11/Cadrefenetre.png&amp;quot;) 11 fill / auto / 0 repeat;&lt;br /&gt;
  padding: 10px;&lt;br /&gt;
  backdrop-filter: blur(4px);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tabber-active.button {&lt;br /&gt;
  background: rgba(75, 85, 95);&lt;br /&gt;
  color: white;&lt;br /&gt;
  border: 2px solid rgba(75, 85, 95);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
ul.subpage {&lt;br /&gt;
  display: flex;&lt;br /&gt;
  list-style: none;&lt;br /&gt;
  margin: 0 0 10px;&lt;br /&gt;
  padding: 0;&lt;br /&gt;
  background: rgba(81,36,16, 0.3);&lt;br /&gt;
  overflow: hidden;&lt;br /&gt;
  line-height: 30px;&lt;br /&gt;
  white-space: nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.subpage a {&lt;br /&gt;
  padding-left: 20px;&lt;br /&gt;
  background: #512410;&lt;br /&gt;
  display: inline-block;&lt;br /&gt;
  line-height: 30px;&lt;br /&gt;
  position: relative;&lt;br /&gt;
  color: #f1de8e;&lt;br /&gt;
  cursor: pointer;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.subpage a:before,&lt;br /&gt;
.subpage a:after { &lt;br /&gt;
  content: &amp;quot;&amp;quot;;&lt;br /&gt;
  position: absolute;&lt;br /&gt;
  width: 0;&lt;br /&gt;
  height: 0;&lt;br /&gt;
  right: 0;&lt;br /&gt;
  padding: 1px 0;&lt;br /&gt;
  border-top: 14px solid transparent;&lt;br /&gt;
  border-bottom: 14px solid transparent;&lt;br /&gt;
  border-left: 14px solid white;&lt;br /&gt;
  transform: translate(14px);&lt;br /&gt;
  z-index: 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.subpage a:after {&lt;br /&gt;
  border-left: 14px solid #512410;&lt;br /&gt;
  transform: translate(13px);&lt;br /&gt;
  z-index: 2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.subpage &amp;gt; li:last-child {&lt;br /&gt;
  padding-left: 20px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
ul.subpage &amp;gt; li:first-child {&lt;br /&gt;
  flex-shrink: 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
ul.subpage &amp;gt; li:first-child &amp;gt; a {&lt;br /&gt;
  height: 100%;&lt;br /&gt;
  display: flex;&lt;br /&gt;
  align-items: center;&lt;br /&gt;
  padding-left: 10px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
ul.subpage &amp;gt; li &amp;gt; a:hover {&lt;br /&gt;
  background: #9D5B37;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
ul.subpage &amp;gt; li &amp;gt; a:hover:after {&lt;br /&gt;
  border-left-color: #9D5B37; &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.image-sizing img,&lt;br /&gt;
.image-sizing-200 img,&lt;br /&gt;
.image-sizing-none img {&lt;br /&gt;
  height: auto;&lt;br /&gt;
  width: auto;&lt;br /&gt;
  max-height: 300px;&lt;br /&gt;
  max-width: 100%;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.image-sizing-200 img {&lt;br /&gt;
  max-height: 200px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.image-sizing-none img {&lt;br /&gt;
  max-height: none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
div.ul-res ul {&lt;br /&gt;
  margin: 0;&lt;br /&gt;
  list-style: none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tab-glob {&lt;br /&gt;
    display: flex;&lt;br /&gt;
    flex-direction: row;&lt;br /&gt;
    margin: 10px 0;&lt;br /&gt;
    column-gap: 2px;&lt;br /&gt;
    align-items: flex-start;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tab-glob &amp;gt; :first-child {&lt;br /&gt;
    display: grid;&lt;br /&gt;
    grid-template-columns: max-content;&lt;br /&gt;
    row-gap: 2px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tab-glob &amp;gt; :first-child &amp;gt; * {&lt;br /&gt;
    border: 1px black solid;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tab-glob &amp;gt; :first-child &amp;gt; *:not(.fondfenetre) {&lt;br /&gt;
    font-weight: bold;&lt;br /&gt;
    display: flex;&lt;br /&gt;
    justify-content: center;&lt;br /&gt;
    align-items: center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tab-glob &amp;gt; :nth-child(2) {&lt;br /&gt;
    width: 100%;&lt;br /&gt;
    overflow-x: auto;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tab-glob &amp;gt; :nth-child(2) &amp;gt; :first-child {&lt;br /&gt;
    display: grid;&lt;br /&gt;
    grid-template-columns: repeat(10,minmax(75px,1fr));&lt;br /&gt;
    gap: 2px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tab-glob &amp;gt; :nth-child(2) &amp;gt; :first-child &amp;gt; * {&lt;br /&gt;
    border: 1px black solid;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tab-glob &amp;gt; :nth-child(2) &amp;gt; :first-child &amp;gt; :not(.fondfenetre) {&lt;br /&gt;
    display: flex;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tab-glob &amp;gt; :nth-child(2) &amp;gt; :first-child &amp;gt; :not(.fondfenetre) &amp;gt; * {&lt;br /&gt;
  margin: auto;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.list-equip {&lt;br /&gt;
  padding: 5px;&lt;br /&gt;
  border: 1px solid #2f1d1f;&lt;br /&gt;
  display: flex;&lt;br /&gt;
  flex-direction: column;&lt;br /&gt;
  align-items: center;&lt;br /&gt;
  gap: 5px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.list-equip &amp;gt; :first-child {&lt;br /&gt;
  width: 100%;&lt;br /&gt;
  line-height: 25px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.list-equip &amp;gt; :first-child &amp;gt; * {&lt;br /&gt;
  padding: 0 5px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.fabrication {&lt;br /&gt;
  position: relative;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.fabrication &amp;gt; * {&lt;br /&gt;
  position: absolute;&lt;br /&gt;
  top: -188px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.fabrication &amp;gt; .bottom-fab,&lt;br /&gt;
.fabrication &amp;gt; .bottom-fab ~ * {&lt;br /&gt;
  top: -58px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.fabrication &amp;gt; * &amp;gt; *:nth-child(2) {&lt;br /&gt;
  position: relative;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.fabrication &amp;gt; * &amp;gt; *:nth-child(2) &amp;gt; * {&lt;br /&gt;
  position: absolute;&lt;br /&gt;
  top: -18px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.fabrication &amp;gt; * &amp;gt; *:nth-child(n+3) {&lt;br /&gt;
  position: absolute;&lt;br /&gt;
  top: 100px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.info-boutique ul {&lt;br /&gt;
  list-style-image: none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.info-boutique p:last-child {&lt;br /&gt;
  margin-bottom: 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
kbd {&lt;br /&gt;
  background-color: #eee;&lt;br /&gt;
  border-radius: 3px;&lt;br /&gt;
  border: 1px solid #b4b4b4;&lt;br /&gt;
  box-shadow: 0 1px 1px rgb(0 0 0 / 20%), 0 2px 0 0 rgb(255 255 255 / 70%) inset;&lt;br /&gt;
  color: #333;&lt;br /&gt;
  display: inline-block;&lt;br /&gt;
  font-size: 0.85em;&lt;br /&gt;
  font-weight: 700;&lt;br /&gt;
  line-height: 1;&lt;br /&gt;
  padding: 2px 4px;&lt;br /&gt;
  white-space: nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.top-button {&lt;br /&gt;
  display: flex;&lt;br /&gt;
  justify-content: center;&lt;br /&gt;
  align-items: center;&lt;br /&gt;
  opacity: 0;&lt;br /&gt;
  cursor: pointer;&lt;br /&gt;
  position: fixed;&lt;br /&gt;
  bottom: 10px;&lt;br /&gt;
  right: 10px;&lt;br /&gt;
  width: 32px;&lt;br /&gt;
  height: 32px;&lt;br /&gt;
  background: linear-gradient(180deg, &lt;br /&gt;
    rgba(124, 200, 65, 1) 0%, &lt;br /&gt;
    rgba(113, 161, 85, 1) 50%, &lt;br /&gt;
    rgba(64, 117, 39, 1) 50%, &lt;br /&gt;
    rgba(46, 97, 31, 1) 100%);&lt;br /&gt;
  border: 1px solid #d0af52;&lt;br /&gt;
  box-shadow: 1px 1px 2px #000,&lt;br /&gt;
              inset 1px 1px #090200,&lt;br /&gt;
              inset -1px -1px #090200; &lt;br /&gt;
  transform: translateY(100px);&lt;br /&gt;
  transition: all 0.5s ease;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.top-button:after {&lt;br /&gt;
  content: &amp;quot;&amp;quot;;&lt;br /&gt;
  height: 32px;&lt;br /&gt;
  width: 32px;&lt;br /&gt;
  background-image: url(&amp;quot;data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fffacb' height='32' viewBox='0 -960 960 960' width='32'%3E%3Cpath d='m296-345-56-56 240-240 240 240-56 56-184-184-184 184Z'/%3E%3C/svg%3E&amp;quot;);&lt;br /&gt;
  background-repeat: no-repeat;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.show-button {&lt;br /&gt;
  opacity: 1;&lt;br /&gt;
  transform: translateY(0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.ul-row ul {&lt;br /&gt;
  display: flex;&lt;br /&gt;
  column-gap: 30px;&lt;br /&gt;
  flex-wrap: wrap;&lt;br /&gt;
  overflow: hidden;&lt;br /&gt;
  margin: 0;&lt;br /&gt;
  list-style-image: none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.flex {&lt;br /&gt;
  display: flex;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#catlinks {&lt;br /&gt;
  margin-top: 10px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.improved-collapsible &amp;gt; .mw-collapsible-toggle {&lt;br /&gt;
  grid-area: 1 / -1;&lt;br /&gt;
  display: flex;&lt;br /&gt;
  justify-content: flex-end;&lt;br /&gt;
  align-items: center;&lt;br /&gt;
  float: initial;&lt;br /&gt;
  z-index: 1;&lt;br /&gt;
  padding-right: 5px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.improved-collapsible .mw-collapsible-toggle:before {&lt;br /&gt;
  content: &amp;quot;&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.improved-collapsible .mw-collapsible-text {&lt;br /&gt;
  display: none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.improved-collapsible .mw-collapsible-toggle:after {&lt;br /&gt;
  width: 32px;&lt;br /&gt;
  height: 32px;&lt;br /&gt;
  content: &amp;quot;&amp;quot;;&lt;br /&gt;
  background-image: url(&amp;quot;data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23000000' height='32' viewBox='0 -960 960 960' width='32'%3E%3Cpath d='M480-345 240-585l56-56 184 184 184-184 56 56-240 240Z'/%3E%3C/svg%3E&amp;quot;);&lt;br /&gt;
  background-repeat: no-repeat;&lt;br /&gt;
  transition: transform .2s ease-in-out;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.improved-collapsible .mw-collapsible-toggle-expanded:after {&lt;br /&gt;
  transform: rotate(-180deg);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tooltip-icon {&lt;br /&gt;
  background-image: url(&amp;quot;data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' height='24' viewBox='0 -960 960 960' width='24'%3E%3Cpath d='M443-285h75v-234h-75v234Zm36.895-311Q496-596 507-606.895q11-10.894 11-27Q518-650 507.105-661q-10.894-11-27-11Q464-672 453-661.105q-11 10.894-11 27Q442-618 452.895-607q10.894 11 27 11ZM480-90q-80.907 0-152.065-30.763-71.159-30.763-123.797-83.5Q151.5-257 120.75-328.087 90-399.175 90-480q0-80.907 30.763-152.065 30.763-71.159 83.5-123.797Q257-808.5 328.087-839.25 399.175-870 480-870q80.907 0 152.065 30.763 71.159 30.763 123.797 83.5Q808.5-703 839.25-631.913 870-560.825 870-480q0 80.907-30.763 152.065-30.763 71.159-83.5 123.797Q703-151.5 631.913-120.75 560.825-90 480-90Zm0-75q131.5 0 223.25-91.75T795-480q0-131.5-91.75-223.25T480-795q-131.5 0-223.25 91.75T165-480q0 131.5 91.75 223.25T480-165Zm0-315Z'/%3E%3C/svg%3E&amp;quot;);&lt;br /&gt;
  background-repeat: no-repeat;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tooltip-info {&lt;br /&gt;
  position: absolute;&lt;br /&gt;
  bottom: calc(100% + 8px);&lt;br /&gt;
  left: 50%;&lt;br /&gt;
  transform: translateX(-50%);&lt;br /&gt;
  max-width: 290px;&lt;br /&gt;
  width: max-content;&lt;br /&gt;
  z-index: 50;&lt;br /&gt;
  opacity: 0;&lt;br /&gt;
  visibility: hidden;&lt;br /&gt;
  transition: opacity 0.2s ease, visibility 0.2s ease;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tooltip-info:after {&lt;br /&gt;
    content: &amp;quot;&amp;quot;;&lt;br /&gt;
    border: 8px solid transparent;&lt;br /&gt;
    border-top-color: inherit;&lt;br /&gt;
    position: absolute;&lt;br /&gt;
    left: calc(50% - 8px);&lt;br /&gt;
    top: 100%;&lt;br /&gt;
    z-index: 50;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tooltip-icon:hover &amp;gt; .tooltip-info {&lt;br /&gt;
  opacity: 1;&lt;br /&gt;
  visibility: visible;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.cacheTel,&lt;br /&gt;
.tabber-container &amp;gt; :last-child &amp;gt; :not(.tabber-active),&lt;br /&gt;
.tabber-noactive {&lt;br /&gt;
  display: none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes pnj-square {&lt;br /&gt;
  from {background-color: #f80000;}&lt;br /&gt;
  to {background-color: white;}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes pnj-circle {&lt;br /&gt;
  from {border-color: #984c48;}&lt;br /&gt;
  to {border-color: white;}&lt;br /&gt;
  from {scale: 1;}&lt;br /&gt;
  to {scale: .1;}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes loading {&lt;br /&gt;
  0% {&lt;br /&gt;
    transform: scale(1.5);&lt;br /&gt;
  }&lt;br /&gt;
  100% {&lt;br /&gt;
    transform: scale(1);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
@media screen and (max-width: 768px){&lt;br /&gt;
  .texte-long {&lt;br /&gt;
    white-space: normal;&lt;br /&gt;
    overflow: visible;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  .grid2 {&lt;br /&gt;
    grid-template-columns: repeat(2, 1fr) !important;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  .grid3 {&lt;br /&gt;
    grid-template-columns: repeat(3, auto) !important;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  .container { &lt;br /&gt;
   flex-direction: column; &lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  .cacheTel,&lt;br /&gt;
  .subpage &amp;gt; li:nth-last-child(2) &amp;gt; a {&lt;br /&gt;
    display: block;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  .top-button {&lt;br /&gt;
    background: rgba(0, 0, 0, 0.7);&lt;br /&gt;
    color: #999;&lt;br /&gt;
    border: none;&lt;br /&gt;
    box-shadow: none;&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  .top-button::after {&lt;br /&gt;
    background-image: url(&amp;quot;data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23ffffff' height='24' viewBox='0 -960 960 960' width='24'%3E%3Cpath d='M440-80v-647L256-544l-56-56 280-280 280 280-56 57-184-184v647h-80Z'/%3E%3C/svg%3E&amp;quot;);&lt;br /&gt;
    height: 24px;&lt;br /&gt;
    width: 24px;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  .tooltip-icon {&lt;br /&gt;
    position: static;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  .tooltip-info {&lt;br /&gt;
    position: fixed;&lt;br /&gt;
    left: 20px;&lt;br /&gt;
    right: 20px;&lt;br /&gt;
    bottom: 50px;&lt;br /&gt;
    max-width: none;&lt;br /&gt;
    width: auto;&lt;br /&gt;
    transform: none;&lt;br /&gt;
    height: max-content;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  .subpage &amp;gt; li &amp;gt; a,&lt;br /&gt;
  .cacheOrdi,&lt;br /&gt;
  .tooltip-info:after {&lt;br /&gt;
    display: none;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
@media screen and (max-width: 340px){&lt;br /&gt;
  #mw-content {&lt;br /&gt;
    padding-left: 10px;&lt;br /&gt;
    padding-right: 10px;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
@media screen and (min-width: 851px){&lt;br /&gt;
  html {&lt;br /&gt;
    scroll-padding-top: 3.325em;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;/div&gt;</summary>
		<author><name>Dexter</name></author>
		
	</entry>
	<entry>
		<id>https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Common.js&amp;diff=105366</id>
		<title>MediaWiki:Common.js</title>
		<link rel="alternate" type="text/html" href="https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Common.js&amp;diff=105366"/>
		<updated>2024-12-01T05:23:37Z</updated>

		<summary type="html">&lt;p&gt;Dexter : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;/* Tout le JavaScript ici sera chargé avec chaque page accédée par n’importe quel utilisateur. */&lt;br /&gt;
&lt;br /&gt;
/* =====================================&lt;br /&gt;
DECLARATIONS DES FONCTIONS ET PROCEDURES&lt;br /&gt;
======================================== */&lt;br /&gt;
&lt;br /&gt;
function showElement(element) {&lt;br /&gt;
  element.classList.remove(&amp;quot;tabber-noactive&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function hideElement(element) {&lt;br /&gt;
  element.classList.add(&amp;quot;tabber-noactive&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function toggleElement(element) {&lt;br /&gt;
  element.classList.toggle(&amp;quot;tabber-noactive&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* Favicon */&lt;br /&gt;
function fixInsecureFavicon() {&lt;br /&gt;
  document.querySelector('link[rel=&amp;quot;shortcut icon&amp;quot;]').href =&lt;br /&gt;
    &amp;quot;https://gf1.geo.gfsrv.net/cdn98/191b803adbf82f4b8febe3a2c38c2c.ico&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* Liste des équipements */&lt;br /&gt;
function changeEquipementDisplay(container) {&lt;br /&gt;
  var switchButton = container.querySelector(&amp;quot;.button&amp;quot;);&lt;br /&gt;
  var content = container.nextElementSibling;&lt;br /&gt;
&lt;br /&gt;
  switchButton.addEventListener(&amp;quot;click&amp;quot;, function () {&lt;br /&gt;
    switchButton.classList.toggle(&amp;quot;tabber-active&amp;quot;);&lt;br /&gt;
    toggleElement(content);&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* Enlève l'animation de chargement et affiche le contenu de la page lorsque c'est nécessaire */&lt;br /&gt;
function removeLoadingAnimation() {&lt;br /&gt;
  var loadingAnimation = document.getElementById(&amp;quot;loading-animation&amp;quot;);&lt;br /&gt;
  var showAfterLoading = document.getElementById(&amp;quot;show-after-loading&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (loadingAnimation) {&lt;br /&gt;
    hideElement(loadingAnimation);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (showAfterLoading) {&lt;br /&gt;
    showElement(showAfterLoading);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* BOUTON RETOUR VERS LE HAUT */&lt;br /&gt;
function addButtonTop() {&lt;br /&gt;
  var contentText = document.querySelector(&amp;quot;div#mw-content-text&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (contentText !== null) {&lt;br /&gt;
    var divButtonTop = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
    divButtonTop.classList.add(&amp;quot;top-button&amp;quot;);&lt;br /&gt;
    contentText.appendChild(divButtonTop);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function buttonTop() {&lt;br /&gt;
  var balise = document.querySelector(&amp;quot;div#mw-page-header-links&amp;quot;);&lt;br /&gt;
  var topButton = document.querySelector(&amp;quot;.top-button&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (balise !== null) {&lt;br /&gt;
    var options = {&lt;br /&gt;
      root: null,&lt;br /&gt;
      rootMargin: &amp;quot;0px&amp;quot;,&lt;br /&gt;
      threshold: 0,&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    var observer = new IntersectionObserver(callback, options);&lt;br /&gt;
    observer.observe(balise);&lt;br /&gt;
&lt;br /&gt;
    function callback(entries) {&lt;br /&gt;
      entries.forEach(function (entry) {&lt;br /&gt;
        if (entry.isIntersecting) {&lt;br /&gt;
          topButton.classList.remove(&amp;quot;show-button&amp;quot;);&lt;br /&gt;
        } else {&lt;br /&gt;
          topButton.classList.add(&amp;quot;show-button&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
      });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    topButton.addEventListener(&amp;quot;click&amp;quot;, function () {&lt;br /&gt;
      document.documentElement.scrollTo({&lt;br /&gt;
        top: 0,&lt;br /&gt;
      });&lt;br /&gt;
    });&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* Cookies */&lt;br /&gt;
function cookies() {&lt;br /&gt;
  var req = new XMLHttpRequest();&lt;br /&gt;
  req.addEventListener(&amp;quot;load&amp;quot;, function (ev) {&lt;br /&gt;
    if (this.status &amp;gt;= 200 &amp;amp;&amp;amp; this.status &amp;lt; 300) {&lt;br /&gt;
      var data = JSON.parse(this.responseText);&lt;br /&gt;
      if (data.hasOwnProperty(&amp;quot;version&amp;quot;)) {&lt;br /&gt;
        var gdpr = document.createElement(&amp;quot;script&amp;quot;);&lt;br /&gt;
        gdpr.src =&lt;br /&gt;
          &amp;quot;https://s3-static.geo.gfsrv.net/cookiebanner/&amp;quot; +&lt;br /&gt;
          data.version +&lt;br /&gt;
          &amp;quot;/cookie.min.js&amp;quot;;&lt;br /&gt;
        document.head.appendChild(gdpr);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
  req.open(&amp;quot;GET&amp;quot;, &amp;quot;https://s3-static.geo.gfsrv.net/cookiebanner/version.json&amp;quot;);&lt;br /&gt;
  req.send();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addScript(src, callback) {&lt;br /&gt;
  var script = document.createElement(&amp;quot;script&amp;quot;);&lt;br /&gt;
  script.src = src;&lt;br /&gt;
&lt;br /&gt;
  function onComplete() {&lt;br /&gt;
    if (script.parentNode) {&lt;br /&gt;
      script.parentNode.removeChild(script);&lt;br /&gt;
    }&lt;br /&gt;
    if (callback) {&lt;br /&gt;
      callback();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  script.onload = onComplete;&lt;br /&gt;
  script.onerror = onComplete;&lt;br /&gt;
&lt;br /&gt;
  document.head.appendChild(script);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* =======================================&lt;br /&gt;
FONCTION GLOBALE&lt;br /&gt;
Exécutée une fois au chargement de la page&lt;br /&gt;
========================================== */&lt;br /&gt;
&lt;br /&gt;
(function () {&lt;br /&gt;
  fixInsecureFavicon();&lt;br /&gt;
&lt;br /&gt;
  var equipmentContainer = document.querySelectorAll(&lt;br /&gt;
    &amp;quot;div#mw-content-text .list-equip&amp;quot;&lt;br /&gt;
  );&lt;br /&gt;
  var loadScripts = document.querySelectorAll(&amp;quot;div[data-load-javascript]&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  equipmentContainer.forEach(function (container) {&lt;br /&gt;
    changeEquipementDisplay(container);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  /* Charge des scripts spécifiques au chargement de certaines pages */&lt;br /&gt;
  if (loadScripts.length &amp;gt; 0) {&lt;br /&gt;
    var allowedScripts = [&lt;br /&gt;
      &amp;quot;Tabber&amp;quot;,&lt;br /&gt;
      &amp;quot;Skills&amp;quot;,&lt;br /&gt;
      &amp;quot;Modal&amp;quot;,&lt;br /&gt;
      &amp;quot;Switch&amp;quot;,&lt;br /&gt;
      &amp;quot;Loot&amp;quot;,&lt;br /&gt;
      &amp;quot;Map&amp;quot;,&lt;br /&gt;
      &amp;quot;Filter&amp;quot;,&lt;br /&gt;
      &amp;quot;Calculator&amp;quot;,&lt;br /&gt;
      &amp;quot;Element&amp;quot;,&lt;br /&gt;
      &amp;quot;Pets&amp;quot;,&lt;br /&gt;
      &amp;quot;Colorblind&amp;quot;,&lt;br /&gt;
    ];&lt;br /&gt;
    var scriptsToLoad = [];&lt;br /&gt;
&lt;br /&gt;
    for (var i = 0; i &amp;lt; loadScripts.length; i++) {&lt;br /&gt;
      var script = loadScripts[i].dataset[&amp;quot;loadJavascript&amp;quot;];&lt;br /&gt;
&lt;br /&gt;
      if (&lt;br /&gt;
        allowedScripts.indexOf(script) !== -1 &amp;amp;&amp;amp;&lt;br /&gt;
        scriptsToLoad.indexOf(script) === -1&lt;br /&gt;
      ) {&lt;br /&gt;
        scriptsToLoad.push(script);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function loadNextScript() {&lt;br /&gt;
      if (scriptsToLoad.length &amp;gt; 0) {&lt;br /&gt;
        var script = scriptsToLoad.shift();&lt;br /&gt;
        addScript(&lt;br /&gt;
          &amp;quot;/index.php?title=MediaWiki:Script/&amp;quot; +&lt;br /&gt;
            script +&lt;br /&gt;
            &amp;quot;.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&amp;quot;,&lt;br /&gt;
          loadNextScript&lt;br /&gt;
        );&lt;br /&gt;
      } else {&lt;br /&gt;
        removeLoadingAnimation();&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    loadNextScript();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (mw.config.get(&amp;quot;wgUserName&amp;quot;)) {&lt;br /&gt;
    mw.loader.load(&lt;br /&gt;
      &amp;quot;/index.php?title=MediaWiki:Script/Redactor.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&amp;quot;&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  addButtonTop();&lt;br /&gt;
  buttonTop();&lt;br /&gt;
  cookies();&lt;br /&gt;
})();&lt;/div&gt;</summary>
		<author><name>Dexter</name></author>
		
	</entry>
	<entry>
		<id>https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Script/Filter.js&amp;diff=105342</id>
		<title>MediaWiki:Script/Filter.js</title>
		<link rel="alternate" type="text/html" href="https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Script/Filter.js&amp;diff=105342"/>
		<updated>2024-11-30T22:13:45Z</updated>

		<summary type="html">&lt;p&gt;Dexter : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;function removeAccent(str) {&lt;br /&gt;
  return str&lt;br /&gt;
    .normalize(&amp;quot;NFD&amp;quot;)&lt;br /&gt;
    .replace(/[\u0300-\u036f]/g, &amp;quot;&amp;quot;)&lt;br /&gt;
    .toLowerCase();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function toNormalForm(str) {&lt;br /&gt;
  return removeAccent(str).replace(/[^a-zA-Z0-9 ]/g, &amp;quot;&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addValueToObject(object, key, value) {&lt;br /&gt;
  if (object[key]) {&lt;br /&gt;
    object[key].push(value);&lt;br /&gt;
  } else {&lt;br /&gt;
    object[key] = [value];&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleDropdowns(filterInformation) {&lt;br /&gt;
  var form = filterInformation.form;&lt;br /&gt;
  var activeButton = null;&lt;br /&gt;
&lt;br /&gt;
  function toggleDropdown(button, dropdownMenu) {&lt;br /&gt;
    if (button === activeButton) {&lt;br /&gt;
      hideElement(dropdownMenu);&lt;br /&gt;
      activeButton = null;&lt;br /&gt;
    } else {&lt;br /&gt;
      if (activeButton) {&lt;br /&gt;
        hideElement(activeButton.nextElementSibling);&lt;br /&gt;
      }&lt;br /&gt;
      showElement(dropdownMenu);&lt;br /&gt;
      activeButton = button;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function closeDropdowns() {&lt;br /&gt;
    if (activeButton) {&lt;br /&gt;
      hideElement(activeButton.nextElementSibling);&lt;br /&gt;
      activeButton = null;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  form.addEventListener(&amp;quot;click&amp;quot;, function (event) {&lt;br /&gt;
    var target = event.target;&lt;br /&gt;
    var button = target.closest(&amp;quot;button&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (button) {&lt;br /&gt;
      var dropdownMenu = button.nextElementSibling;&lt;br /&gt;
&lt;br /&gt;
      toggleDropdown(button, dropdownMenu);&lt;br /&gt;
    } else if (!target.closest(&amp;quot;.dropdown-menu&amp;quot;)) {&lt;br /&gt;
      closeDropdowns();&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  document.addEventListener(&amp;quot;mousedown&amp;quot;, function (event) {&lt;br /&gt;
    if (!form.contains(event.target)) {&lt;br /&gt;
      closeDropdowns();&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function incrementCounter(counterElement, counterValue) {&lt;br /&gt;
  if (counterValue === 0) {&lt;br /&gt;
    showElement(counterElement);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  counterElement.textContent = counterValue + 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function decrementCounter(counterElement, counterValue) {&lt;br /&gt;
  if (counterValue === 1) {&lt;br /&gt;
    hideElement(counterElement);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  counterElement.textContent = counterValue - 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterItems(filterInformation, cardInformation) {&lt;br /&gt;
  function showCounter() {&lt;br /&gt;
    var checkbox = filterInformation.checkbox;&lt;br /&gt;
&lt;br /&gt;
    for (var filterName in checkbox) {&lt;br /&gt;
      var values = checkbox[filterName].values;&lt;br /&gt;
&lt;br /&gt;
      for (var filterValue in values) {&lt;br /&gt;
        var span = values[filterValue].span;&lt;br /&gt;
&lt;br /&gt;
        span.textContent = &amp;quot; (&amp;quot; + values[filterValue].value + &amp;quot;)&amp;quot;;&lt;br /&gt;
        values[filterValue].value = 0;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function addCount(cardParameters, checkboxNames, parameter) {&lt;br /&gt;
    cardParameters[parameter].split(&amp;quot; &amp;quot;).forEach(function (cardValue) {&lt;br /&gt;
      checkboxNames[parameter].values[cardValue].value += 1;&lt;br /&gt;
    });&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function isObjectValuesInRangeFilter(parameters, rangeFilter) {&lt;br /&gt;
    return Object.keys(rangeFilter).every(function (property) {&lt;br /&gt;
      var propertyValue = parameters[property];&lt;br /&gt;
      return (&lt;br /&gt;
        rangeFilter[property].min &amp;lt;= propertyValue &amp;amp;&amp;amp;&lt;br /&gt;
        rangeFilter[property].max &amp;gt;= propertyValue&lt;br /&gt;
      );&lt;br /&gt;
    });&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function filterByName(parameters, filterName) {&lt;br /&gt;
    if (filterName) {&lt;br /&gt;
      return parameters.name.indexOf(filterName) !== -1;&lt;br /&gt;
    }&lt;br /&gt;
    return true;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function isObjectValuesInFilter(parameters, filter) {&lt;br /&gt;
    return Object.keys(filter).every(function (property) {&lt;br /&gt;
      return parameters[property].split(&amp;quot; &amp;quot;).some(function (value) {&lt;br /&gt;
        return filter[property].indexOf(value) !== -1;&lt;br /&gt;
      });&lt;br /&gt;
    });&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function isObjectValuesInFilters(&lt;br /&gt;
    parameters,&lt;br /&gt;
    filter,&lt;br /&gt;
    rangeFilter,&lt;br /&gt;
    filterName&lt;br /&gt;
  ) {&lt;br /&gt;
    return (&lt;br /&gt;
      isObjectValuesInFilter(parameters, filter) &amp;amp;&amp;amp;&lt;br /&gt;
      filterByName(parameters, filterName) &amp;amp;&amp;amp;&lt;br /&gt;
      isObjectValuesInRangeFilter(parameters, rangeFilter)&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var filter = filterInformation.filters.filter;&lt;br /&gt;
  var rangeFilter = filterInformation.filters.rangeFilter;&lt;br /&gt;
  var filterName = filterInformation.filters.filterName;&lt;br /&gt;
  var checkboxNames = filterInformation.checkbox;&lt;br /&gt;
  var listToFilter = cardInformation.listToFilter.children;&lt;br /&gt;
  var cardData = cardInformation.data;&lt;br /&gt;
&lt;br /&gt;
  if (filterInformation.reverse) {&lt;br /&gt;
    var parent = cardInformation.listToFilter;&lt;br /&gt;
    for (&lt;br /&gt;
      var reverseIndex = 1;&lt;br /&gt;
      reverseIndex &amp;lt; listToFilter.length;&lt;br /&gt;
      reverseIndex++&lt;br /&gt;
    ) {&lt;br /&gt;
      parent.insertBefore(listToFilter[reverseIndex], parent.firstChild);&lt;br /&gt;
    }&lt;br /&gt;
    cardInformation.data.reverse();&lt;br /&gt;
    filterInformation.reverse = false;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (var cardIndex = 0; cardIndex &amp;lt; listToFilter.length; cardIndex++) {&lt;br /&gt;
    var card = listToFilter[cardIndex];&lt;br /&gt;
    var cardParameters = cardData[cardIndex];&lt;br /&gt;
    if (&lt;br /&gt;
      isObjectValuesInFilters(cardParameters, filter, rangeFilter, filterName)&lt;br /&gt;
    ) {&lt;br /&gt;
      showElement(card);&lt;br /&gt;
      for (var parameter in checkboxNames) {&lt;br /&gt;
        addCount(cardParameters, checkboxNames, parameter);&lt;br /&gt;
      }&lt;br /&gt;
    } else {&lt;br /&gt;
      hideElement(card);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  showCounter();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateFilterObject(filterInformation, cardInformation) {&lt;br /&gt;
  function updateFilter(event, filterByName = false) {&lt;br /&gt;
    function handleNumberType(target) {&lt;br /&gt;
      var [filterName, extremum] = target.id.split(&amp;quot;-&amp;quot;);&lt;br /&gt;
      var currentValue = Number(target.value);&lt;br /&gt;
      var counterElement = filterInformation.range[filterName].counter;&lt;br /&gt;
      var counterValue = Number(counterElement.textContent);&lt;br /&gt;
      var initialRange = filterInformation.range[filterName].init;&lt;br /&gt;
      var rangeFilter = filterInformation.filters.rangeFilter;&lt;br /&gt;
&lt;br /&gt;
      if (rangeFilter[filterName]) {&lt;br /&gt;
        rangeFilter[filterName][extremum] = currentValue;&lt;br /&gt;
      } else {&lt;br /&gt;
        incrementCounter(counterElement, counterValue);&lt;br /&gt;
        rangeFilter[filterName] = {&lt;br /&gt;
          min: initialRange.min,&lt;br /&gt;
          max: initialRange.max,&lt;br /&gt;
        };&lt;br /&gt;
        rangeFilter[filterName][extremum] = currentValue;&lt;br /&gt;
      }&lt;br /&gt;
      if (&lt;br /&gt;
        rangeFilter[filterName].max === initialRange.max &amp;amp;&amp;amp;&lt;br /&gt;
        rangeFilter[filterName].min === initialRange.min&lt;br /&gt;
      ) {&lt;br /&gt;
        decrementCounter(counterElement, counterValue);&lt;br /&gt;
        delete rangeFilter[filterName];&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handleCheckbox(target) {&lt;br /&gt;
      var filterName = target.id.split(&amp;quot;-&amp;quot;)[0];&lt;br /&gt;
      var filter = filterInformation.filters.filter;&lt;br /&gt;
      var filterValue = target.dataset.filter;&lt;br /&gt;
      var counterElement = filterInformation.checkbox[filterName].counter;&lt;br /&gt;
      var counterValue = Number(counterElement.textContent);&lt;br /&gt;
&lt;br /&gt;
      if (target.checked) {&lt;br /&gt;
        incrementCounter(counterElement, counterValue);&lt;br /&gt;
        addValueToObject(filter, filterName, filterValue);&lt;br /&gt;
      } else {&lt;br /&gt;
        decrementCounter(counterElement, counterValue);&lt;br /&gt;
        var index = filter[filterName].indexOf(filterValue);&lt;br /&gt;
        if (index !== -1) {&lt;br /&gt;
          if (filter[filterName].length === 1) {&lt;br /&gt;
            delete filter[filterName];&lt;br /&gt;
          } else {&lt;br /&gt;
            filter[filterName].splice(index, 1);&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var target = event.target;&lt;br /&gt;
&lt;br /&gt;
    if (filterByName) {&lt;br /&gt;
      filterInformation.filters.filterName = toNormalForm(target.value);&lt;br /&gt;
    } else {&lt;br /&gt;
      var type = target.type;&lt;br /&gt;
&lt;br /&gt;
      if (type === &amp;quot;number&amp;quot;) {&lt;br /&gt;
        handleNumberType(target);&lt;br /&gt;
      } else if (type === &amp;quot;checkbox&amp;quot;) {&lt;br /&gt;
        if (target.id === &amp;quot;filter-reverse&amp;quot;) {&lt;br /&gt;
          filterInformation.reverse = true;&lt;br /&gt;
        } else {&lt;br /&gt;
          handleCheckbox(target);&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
    filterItems(filterInformation, cardInformation);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var form = filterInformation.form;&lt;br /&gt;
  var debounceTimer;&lt;br /&gt;
&lt;br /&gt;
  form.addEventListener(&amp;quot;submit&amp;quot;, function (event) {&lt;br /&gt;
    event.preventDefault();&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  form.addEventListener(&amp;quot;change&amp;quot;, function (event) {&lt;br /&gt;
    updateFilter(event);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  form.addEventListener(&amp;quot;input&amp;quot;, function (event) {&lt;br /&gt;
    if (event.target.id === &amp;quot;filter-name&amp;quot;) {&lt;br /&gt;
      clearTimeout(debounceTimer);&lt;br /&gt;
      debounceTimer = setTimeout(function () {&lt;br /&gt;
        updateFilter(event, true);&lt;br /&gt;
      }, 500);&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterInitialization() {&lt;br /&gt;
  function createSpan() {&lt;br /&gt;
    var span = document.createElement(&amp;quot;span&amp;quot;);&lt;br /&gt;
    span.style.color = &amp;quot;#9F9F9F&amp;quot;;&lt;br /&gt;
    span.style.fontSize = &amp;quot;12px&amp;quot;;&lt;br /&gt;
    return span;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function handlefilterParameters(filterParameters, param, filterName) {&lt;br /&gt;
    if (param === &amp;quot;levels&amp;quot;) {&lt;br /&gt;
      addValueToObject(filterParameters, &amp;quot;levels&amp;quot;, filterName);&lt;br /&gt;
    } else if (param.startsWith(&amp;quot;replace_&amp;quot;)) {&lt;br /&gt;
      var replace = param.split(&amp;quot;replace_&amp;quot;)[1].replace(&amp;quot;_&amp;quot;, &amp;quot; &amp;quot;);&lt;br /&gt;
&lt;br /&gt;
      if (!filterParameters[&amp;quot;replace&amp;quot;]) {&lt;br /&gt;
        filterParameters[&amp;quot;replace&amp;quot;] = {};&lt;br /&gt;
      }&lt;br /&gt;
      filterParameters[&amp;quot;replace&amp;quot;][filterName] = { value: replace };&lt;br /&gt;
    } else if (param === &amp;quot;elem&amp;quot;) {&lt;br /&gt;
      filterParameters[&amp;quot;elem&amp;quot;] = filterName;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var form = document.getElementById(&amp;quot;filter-form&amp;quot;);&lt;br /&gt;
  var filters = { filterName: &amp;quot;&amp;quot;, filter: {}, rangeFilter: {} };&lt;br /&gt;
  var filterInformation = {&lt;br /&gt;
    form: form,&lt;br /&gt;
    filters: filters,&lt;br /&gt;
    range: {},&lt;br /&gt;
    checkbox: {},&lt;br /&gt;
    reverse: false,&lt;br /&gt;
  };&lt;br /&gt;
  var allButton = form.querySelectorAll(&amp;quot;button&amp;quot;);&lt;br /&gt;
  var filterParameters = {};&lt;br /&gt;
&lt;br /&gt;
  allButton.forEach(function (button) {&lt;br /&gt;
    var buttonSibling = button.nextElementSibling;&lt;br /&gt;
&lt;br /&gt;
    if (!buttonSibling) return;&lt;br /&gt;
&lt;br /&gt;
    var filterName = buttonSibling.id;&lt;br /&gt;
    var counter = buttonSibling.nextElementSibling;&lt;br /&gt;
    var param = buttonSibling.dataset.param;&lt;br /&gt;
&lt;br /&gt;
    if (!filterName || !counter || !param) return;&lt;br /&gt;
&lt;br /&gt;
    var infoType = filterName.endsWith(&amp;quot;-range&amp;quot;) ? &amp;quot;range&amp;quot; : &amp;quot;checkbox&amp;quot;;&lt;br /&gt;
    var filterName = filterName.replace(&amp;quot;-range&amp;quot;, &amp;quot;&amp;quot;);&lt;br /&gt;
    var filterObj = (filterInformation[infoType][filterName] = {&lt;br /&gt;
      counter: counter,&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    handlefilterParameters(filterParameters, param, filterName);&lt;br /&gt;
&lt;br /&gt;
    if (infoType === &amp;quot;checkbox&amp;quot;) {&lt;br /&gt;
      filterObj.values = {};&lt;br /&gt;
      var allInput = buttonSibling.querySelectorAll(&amp;quot;input&amp;quot;);&lt;br /&gt;
      allInput.forEach(function (input) {&lt;br /&gt;
        var filterValue = input.dataset.filter;&lt;br /&gt;
&lt;br /&gt;
        if (!filterValue) return;&lt;br /&gt;
&lt;br /&gt;
        var span = createSpan();&lt;br /&gt;
        input.parentElement.appendChild(span);&lt;br /&gt;
        filterObj.values[filterValue] = { value: 0, span: span };&lt;br /&gt;
      });&lt;br /&gt;
    } else if (infoType === &amp;quot;range&amp;quot;) {&lt;br /&gt;
      filterObj.init = {};&lt;br /&gt;
      filterObj.init.min = Number(buttonSibling.children[0].firstChild.min);&lt;br /&gt;
      filterObj.init.max = Number(buttonSibling.children[0].firstChild.max);&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  return [filterInformation, filterParameters];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getCardInformation(filterParameters) {&lt;br /&gt;
  function createDataSelector(name) {&lt;br /&gt;
    return &amp;quot;[data-&amp;quot; + name + &amp;quot;]&amp;quot;;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var listToFilter = document.getElementById(&amp;quot;list-to-filter&amp;quot;);&lt;br /&gt;
  var listToFilterChildren = listToFilter.children;&lt;br /&gt;
  var allCardInformation = [];&lt;br /&gt;
  var filterLevelsNames = filterParameters[&amp;quot;levels&amp;quot;];&lt;br /&gt;
  var filterWithReplace = filterParameters[&amp;quot;replace&amp;quot;];&lt;br /&gt;
  var filterElementName = filterParameters[&amp;quot;elem&amp;quot;];&lt;br /&gt;
&lt;br /&gt;
  if (filterLevelsNames) {&lt;br /&gt;
    var [level0, level1] = filterLevelsNames;&lt;br /&gt;
    var levelsSelector = createDataSelector(level0);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (filterWithReplace) {&lt;br /&gt;
    for (var replaceName in filterWithReplace) {&lt;br /&gt;
      filterWithReplace[replaceName].selector = createDataSelector(replaceName);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (filterElementName) {&lt;br /&gt;
    var elementSelector = createDataSelector(filterElementName);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (&lt;br /&gt;
    var cardIndex = 0;&lt;br /&gt;
    cardIndex &amp;lt; listToFilterChildren.length;&lt;br /&gt;
    cardIndex++&lt;br /&gt;
  ) {&lt;br /&gt;
    var card = listToFilterChildren[cardIndex];&lt;br /&gt;
    var cardInformation = {};&lt;br /&gt;
    var cardNameElement = card.querySelector(&amp;quot;[data-name]&amp;quot;);&lt;br /&gt;
    cardInformation.name = toNormalForm(cardNameElement.textContent);&lt;br /&gt;
    cardInformation.trueName = cardNameElement.firstChild.title;&lt;br /&gt;
&lt;br /&gt;
    if (filterLevelsNames) {&lt;br /&gt;
      var levelsElement = card.querySelector(levelsSelector);&lt;br /&gt;
      var [levelValue0, levelValue1] = levelsElement.textContent&lt;br /&gt;
        .slice(1, -1)&lt;br /&gt;
        .split(&amp;quot;, &amp;quot;);&lt;br /&gt;
      cardInformation[level0] = Number(levelValue0);&lt;br /&gt;
      cardInformation[level1] = removeAccent(levelValue1);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (filterElementName) {&lt;br /&gt;
      var elementChild = card.querySelector(elementSelector).children;&lt;br /&gt;
      var elementValue = &amp;quot;&amp;quot;;&lt;br /&gt;
      if (elementChild.length) {&lt;br /&gt;
        for (&lt;br /&gt;
          var elementIndex = 0;&lt;br /&gt;
          elementIndex &amp;lt; elementChild.length;&lt;br /&gt;
          elementIndex++&lt;br /&gt;
        ) {&lt;br /&gt;
          elementValue += elementChild[elementIndex].title + &amp;quot; &amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
      elementValue = elementValue.trim() || &amp;quot;Aucun&amp;quot;;&lt;br /&gt;
      cardInformation[filterElementName] = removeAccent(elementValue);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (filterWithReplace) {&lt;br /&gt;
      for (var replaceName in filterWithReplace) {&lt;br /&gt;
        var replaceInformation = filterWithReplace[replaceName];&lt;br /&gt;
        var replaceValue = card&lt;br /&gt;
          .querySelector(replaceInformation.selector)&lt;br /&gt;
          .textContent.replace(replaceInformation.value, &amp;quot;&amp;quot;);&lt;br /&gt;
        cardInformation[replaceName] = removeAccent(replaceValue);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    allCardInformation.push(cardInformation);&lt;br /&gt;
  }&lt;br /&gt;
  allCardInformation = { listToFilter: listToFilter, data: allCardInformation };&lt;br /&gt;
&lt;br /&gt;
  return allCardInformation;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function editCardInformation(cardInformation) {&lt;br /&gt;
  var listToFilterChildren = cardInformation.listToFilter.children;&lt;br /&gt;
&lt;br /&gt;
  for (&lt;br /&gt;
    var cardIndex = 0;&lt;br /&gt;
    cardIndex &amp;lt; listToFilterChildren.length;&lt;br /&gt;
    cardIndex++&lt;br /&gt;
  ) {&lt;br /&gt;
    var card = listToFilterChildren[cardIndex];&lt;br /&gt;
    var cardName = card.querySelector(&amp;quot;[data-name]&amp;quot;).textContent;&lt;br /&gt;
    cardInformation.data[cardIndex].name = toNormalForm(cardName);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function observeLanguageChange(cardInformation) {&lt;br /&gt;
  var filterName = document.getElementById(&amp;quot;filter-name&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (!filterName) {&lt;br /&gt;
    return;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var observer = new MutationObserver(function (mutation) {&lt;br /&gt;
    editCardInformation(cardInformation);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  observer.observe(filterName, { attributes: true });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterWithUrl(filterInformation) {&lt;br /&gt;
  function processParameter(key, value, filters) {&lt;br /&gt;
    if (key === &amp;quot;name&amp;quot;) {&lt;br /&gt;
      var filterName = document.getElementById(&amp;quot;filter-name&amp;quot;);&lt;br /&gt;
      filterName.value = toNormalForm(value);&lt;br /&gt;
      filters.filterName = value;&lt;br /&gt;
    } else if (Object.keys(filterInformation.checkbox).indexOf(key) !== -1) {&lt;br /&gt;
      var checkboxElement = document.getElementById(key + &amp;quot;-&amp;quot; + value);&lt;br /&gt;
      if (!checkboxElement) return;&lt;br /&gt;
      var counterElement = filterInformation.checkbox[key].counter;&lt;br /&gt;
      var counterValue = Number(counterElement.textContent);&lt;br /&gt;
      incrementCounter(counterElement, counterValue);&lt;br /&gt;
      checkboxElement.checked = true;&lt;br /&gt;
      addValueToObject(filters.filter, key, value);&lt;br /&gt;
    } else if (key === &amp;quot;reverse&amp;quot;) {&lt;br /&gt;
      if (value === &amp;quot;1&amp;quot;) {&lt;br /&gt;
        filterInformation.reverse = true;&lt;br /&gt;
        var reverseElement = document.getElementById(&amp;quot;filter-reverse&amp;quot;);&lt;br /&gt;
        if (reverseElement) {&lt;br /&gt;
          reverseElement.checked = true;&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    } else {&lt;br /&gt;
      var splitKey = key.split(&amp;quot;-&amp;quot;)[0];&lt;br /&gt;
      if (Object.keys(filterInformation.range).indexOf(splitKey) !== -1) {&lt;br /&gt;
        var rangeElement = document.getElementById(key);&lt;br /&gt;
        if (!rangeElement) return;&lt;br /&gt;
        rangeElement.value = value;&lt;br /&gt;
        var rangeInformation = filterInformation.range[splitKey];&lt;br /&gt;
        incrementCounter(rangeInformation.counter, 0);&lt;br /&gt;
        var extremum = key.split(&amp;quot;-&amp;quot;)[1];&lt;br /&gt;
        var rangeFilter = filters.rangeFilter;&lt;br /&gt;
        if (rangeFilter[splitKey]) {&lt;br /&gt;
          rangeFilter[splitKey][extremum] = value;&lt;br /&gt;
        } else {&lt;br /&gt;
          rangeFilter[splitKey] = {&lt;br /&gt;
            min: rangeInformation.init.min,&lt;br /&gt;
            max: rangeInformation.init.max,&lt;br /&gt;
          };&lt;br /&gt;
          rangeFilter[splitKey][extremum] = value;&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var url = new URL(window.location.href);&lt;br /&gt;
  var urlHash = url.hash;&lt;br /&gt;
  var useParams = true;&lt;br /&gt;
  var filters = filterInformation.filters;&lt;br /&gt;
&lt;br /&gt;
  if (urlHash) {&lt;br /&gt;
    var start = &amp;quot;.3F&amp;quot;;&lt;br /&gt;
    var equal = &amp;quot;.3D&amp;quot;;&lt;br /&gt;
    var and = &amp;quot;.26&amp;quot;;&lt;br /&gt;
    var startParametersIndex = urlHash.indexOf(start);&lt;br /&gt;
&lt;br /&gt;
    if (startParametersIndex !== -1) {&lt;br /&gt;
      useParams = false;&lt;br /&gt;
      var parameters = urlHash.slice(startParametersIndex + start.length);&lt;br /&gt;
&lt;br /&gt;
      parameters.split(and).forEach(function (keyValue) {&lt;br /&gt;
        var [key, value] = keyValue.split(equal);&lt;br /&gt;
        processParameter(key, value, filters);&lt;br /&gt;
      });&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (useParams) {&lt;br /&gt;
    var URLparams = new URLSearchParams(url.search);&lt;br /&gt;
&lt;br /&gt;
    for (var [key, value] of URLparams.entries()) {&lt;br /&gt;
      processParameter(key, value, filters);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
(function () {&lt;br /&gt;
  var [filterInformation, filterParameters] = filterInitialization();&lt;br /&gt;
  var cardInformation = getCardInformation(filterParameters);&lt;br /&gt;
&lt;br /&gt;
  observeLanguageChange(cardInformation);&lt;br /&gt;
  handleDropdowns(filterInformation);&lt;br /&gt;
  filterWithUrl(filterInformation);&lt;br /&gt;
  filterItems(filterInformation, cardInformation);&lt;br /&gt;
  updateFilterObject(filterInformation, cardInformation);&lt;br /&gt;
})();&lt;/div&gt;</summary>
		<author><name>Dexter</name></author>
		
	</entry>
	<entry>
		<id>https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Common.js&amp;diff=105341</id>
		<title>MediaWiki:Common.js</title>
		<link rel="alternate" type="text/html" href="https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Common.js&amp;diff=105341"/>
		<updated>2024-11-30T22:13:06Z</updated>

		<summary type="html">&lt;p&gt;Dexter : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;/* Tout le JavaScript ici sera chargé avec chaque page accédée par n’importe quel utilisateur. */&lt;br /&gt;
&lt;br /&gt;
/* =====================================&lt;br /&gt;
DECLARATIONS DES FONCTIONS ET PROCEDURES&lt;br /&gt;
======================================== */&lt;br /&gt;
&lt;br /&gt;
function showElement(element) {&lt;br /&gt;
  element.classList.remove(&amp;quot;tabber-noactive&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function hideElement(element) {&lt;br /&gt;
  element.classList.add(&amp;quot;tabber-noactive&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function toggleElement(element) {&lt;br /&gt;
  element.classList.toggle(&amp;quot;tabber-noactive&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* Favicon */&lt;br /&gt;
function fixInsecureFavicon() {&lt;br /&gt;
  document.querySelector('link[rel=&amp;quot;shortcut icon&amp;quot;]').href =&lt;br /&gt;
    &amp;quot;https://gf1.geo.gfsrv.net/cdn98/191b803adbf82f4b8febe3a2c38c2c.ico&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* Liste des équipements */&lt;br /&gt;
function changeEquipementDisplay(container) {&lt;br /&gt;
  var switchButton = container.querySelector(&amp;quot;.button&amp;quot;);&lt;br /&gt;
  var content = container.nextElementSibling;&lt;br /&gt;
&lt;br /&gt;
  switchButton.addEventListener(&amp;quot;click&amp;quot;, function () {&lt;br /&gt;
    switchButton.classList.toggle(&amp;quot;tabber-active&amp;quot;);&lt;br /&gt;
    toggleElement(content);&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* Enlève l'animation de chargement et affiche le contenu de la page lorsque c'est nécessaire */&lt;br /&gt;
function removeLoadingAnimation() {&lt;br /&gt;
  var loadingAnimation = document.getElementById(&amp;quot;loading-animation&amp;quot;);&lt;br /&gt;
  var showAfterLoading = document.getElementById(&amp;quot;show-after-loading&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (loadingAnimation) {&lt;br /&gt;
    hideElement(loadingAnimation);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (showAfterLoading) {&lt;br /&gt;
    showElement(showAfterLoading);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* BOUTON RETOUR VERS LE HAUT */&lt;br /&gt;
function addButtonTop() {&lt;br /&gt;
  var contentText = document.querySelector(&amp;quot;div#mw-content-text&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (contentText !== null) {&lt;br /&gt;
    var divButtonTop = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
    divButtonTop.classList.add(&amp;quot;top-button&amp;quot;);&lt;br /&gt;
    contentText.appendChild(divButtonTop);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function buttonTop() {&lt;br /&gt;
  var balise = document.querySelector(&amp;quot;div#mw-page-header-links&amp;quot;);&lt;br /&gt;
  var topButton = document.querySelector(&amp;quot;.top-button&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  if (balise !== null) {&lt;br /&gt;
    var options = {&lt;br /&gt;
      root: null,&lt;br /&gt;
      rootMargin: &amp;quot;0px&amp;quot;,&lt;br /&gt;
      threshold: 0,&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    var observer = new IntersectionObserver(callback, options);&lt;br /&gt;
    observer.observe(balise);&lt;br /&gt;
&lt;br /&gt;
    function callback(entries) {&lt;br /&gt;
      entries.forEach(function (entry) {&lt;br /&gt;
        if (entry.isIntersecting) {&lt;br /&gt;
          topButton.classList.remove(&amp;quot;show-button&amp;quot;);&lt;br /&gt;
        } else {&lt;br /&gt;
          topButton.classList.add(&amp;quot;show-button&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
      });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    topButton.addEventListener(&amp;quot;click&amp;quot;, function () {&lt;br /&gt;
      document.documentElement.scrollTo({&lt;br /&gt;
        top: 0,&lt;br /&gt;
      });&lt;br /&gt;
    });&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* Cookies */&lt;br /&gt;
function cookies() {&lt;br /&gt;
  var req = new XMLHttpRequest();&lt;br /&gt;
  req.addEventListener(&amp;quot;load&amp;quot;, function (ev) {&lt;br /&gt;
    if (this.status &amp;gt;= 200 &amp;amp;&amp;amp; this.status &amp;lt; 300) {&lt;br /&gt;
      var data = JSON.parse(this.responseText);&lt;br /&gt;
      if (data.hasOwnProperty(&amp;quot;version&amp;quot;)) {&lt;br /&gt;
        var gdpr = document.createElement(&amp;quot;script&amp;quot;);&lt;br /&gt;
        gdpr.src =&lt;br /&gt;
          &amp;quot;https://s3-static.geo.gfsrv.net/cookiebanner/&amp;quot; +&lt;br /&gt;
          data.version +&lt;br /&gt;
          &amp;quot;/cookie.min.js&amp;quot;;&lt;br /&gt;
        document.head.appendChild(gdpr);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
  req.open(&amp;quot;GET&amp;quot;, &amp;quot;https://s3-static.geo.gfsrv.net/cookiebanner/version.json&amp;quot;);&lt;br /&gt;
  req.send();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addScript(src, callback) {&lt;br /&gt;
  var script = document.createElement(&amp;quot;script&amp;quot;);&lt;br /&gt;
  script.src = src;&lt;br /&gt;
&lt;br /&gt;
  function onComplete() {&lt;br /&gt;
    if (script.parentNode) {&lt;br /&gt;
      script.parentNode.removeChild(script);&lt;br /&gt;
    }&lt;br /&gt;
    if (callback) {&lt;br /&gt;
      callback();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  script.onload = onComplete;&lt;br /&gt;
  script.onerror = onComplete;&lt;br /&gt;
&lt;br /&gt;
  document.head.appendChild(script);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* =======================================&lt;br /&gt;
FONCTION GLOBALE&lt;br /&gt;
Exécutée une fois au chargement de la page&lt;br /&gt;
========================================== */&lt;br /&gt;
&lt;br /&gt;
(function () {&lt;br /&gt;
  fixInsecureFavicon();&lt;br /&gt;
&lt;br /&gt;
  var equipmentContainer = document.querySelectorAll(&lt;br /&gt;
    &amp;quot;div#mw-content-text .list-equip&amp;quot;&lt;br /&gt;
  );&lt;br /&gt;
  var loadScripts = document.querySelectorAll(&amp;quot;div[data-load-javascript]&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  equipmentContainer.forEach(function (container) {&lt;br /&gt;
    changeEquipementDisplay(container);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  /* Charge des scripts spécifiques au chargement de certaines pages */&lt;br /&gt;
  if (loadScripts.length &amp;gt; 0) {&lt;br /&gt;
    var allowedScripts = [&lt;br /&gt;
      &amp;quot;Tabber&amp;quot;,&lt;br /&gt;
      &amp;quot;Skills&amp;quot;,&lt;br /&gt;
      &amp;quot;Modal&amp;quot;,&lt;br /&gt;
      &amp;quot;Switch&amp;quot;,&lt;br /&gt;
      &amp;quot;Loot&amp;quot;,&lt;br /&gt;
      &amp;quot;Map&amp;quot;,&lt;br /&gt;
      &amp;quot;Filter&amp;quot;,&lt;br /&gt;
      &amp;quot;Calculator&amp;quot;,&lt;br /&gt;
      &amp;quot;Element&amp;quot;,&lt;br /&gt;
      &amp;quot;Pets&amp;quot;,&lt;br /&gt;
      &amp;quot;Colorblind&amp;quot;,&lt;br /&gt;
    ];&lt;br /&gt;
    var scriptsToLoad = [];&lt;br /&gt;
&lt;br /&gt;
    for (var i = 0; i &amp;lt; loadScripts.length; i++) {&lt;br /&gt;
      var script = loadScripts[i].dataset[&amp;quot;loadJavascript&amp;quot;];&lt;br /&gt;
&lt;br /&gt;
      if (&lt;br /&gt;
        allowedScripts.indexOf(script) !== -1 &amp;amp;&amp;amp;&lt;br /&gt;
        scriptsToLoad.indexOf(script) === -1&lt;br /&gt;
      ) {&lt;br /&gt;
        scriptsToLoad.push(script);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function loadNextScript() {&lt;br /&gt;
      if (scriptsToLoad.length &amp;gt; 0) {&lt;br /&gt;
        var script = scriptsToLoad.shift();&lt;br /&gt;
        addScript(&lt;br /&gt;
          &amp;quot;/index.php?title=MediaWiki:Script/&amp;quot; +&lt;br /&gt;
            script +&lt;br /&gt;
            &amp;quot;.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&amp;quot;,&lt;br /&gt;
          loadNextScript&lt;br /&gt;
        );&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    loadNextScript();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (mw.config.get(&amp;quot;wgUserName&amp;quot;)) {&lt;br /&gt;
    mw.loader.load(&lt;br /&gt;
      &amp;quot;/index.php?title=MediaWiki:Script/Redactor.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&amp;quot;&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  removeLoadingAnimation();&lt;br /&gt;
  addButtonTop();&lt;br /&gt;
  buttonTop();&lt;br /&gt;
  cookies();&lt;br /&gt;
})();&lt;/div&gt;</summary>
		<author><name>Dexter</name></author>
		
	</entry>
	<entry>
		<id>https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Script/Modal.js&amp;diff=105340</id>
		<title>MediaWiki:Script/Modal.js</title>
		<link rel="alternate" type="text/html" href="https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Script/Modal.js&amp;diff=105340"/>
		<updated>2024-11-30T22:12:17Z</updated>

		<summary type="html">&lt;p&gt;Dexter : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;const modalButtons = document.querySelectorAll(&amp;quot;.modal-trigger&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
modalButtons.forEach((button) =&amp;gt; {&lt;br /&gt;
  const modalName = button.dataset.modal;&lt;br /&gt;
  let modalContainer;&lt;br /&gt;
&lt;br /&gt;
  if (modalName) {&lt;br /&gt;
    modalContainer = document.querySelector(&lt;br /&gt;
      `.modal[data-modal=&amp;quot;${modalName}&amp;quot;]`&lt;br /&gt;
    );&lt;br /&gt;
  } else {&lt;br /&gt;
    modalContainer = button.nextElementSibling;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  const closeButton = modalContainer.querySelector(&amp;quot;.close-button&amp;quot;);&lt;br /&gt;
  const autoClose = modalContainer.dataset.autoClose === &amp;quot;1&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  button.addEventListener(&amp;quot;click&amp;quot;, openModal);&lt;br /&gt;
  closeButton.addEventListener(&amp;quot;click&amp;quot;, closeModal);&lt;br /&gt;
&lt;br /&gt;
  if (autoClose) {&lt;br /&gt;
    modalContainer.addEventListener(&amp;quot;change&amp;quot;, closeModal);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function openModal() {&lt;br /&gt;
    button.classList.add(&amp;quot;tabber-active&amp;quot;);&lt;br /&gt;
    modalContainer.classList.add(&amp;quot;show-modal&amp;quot;);&lt;br /&gt;
    window.addEventListener(&amp;quot;click&amp;quot;, handleClickOutside);&lt;br /&gt;
    window.addEventListener(&amp;quot;keydown&amp;quot;, handleEscape);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function closeModal() {&lt;br /&gt;
    button.classList.remove(&amp;quot;tabber-active&amp;quot;);&lt;br /&gt;
    modalContainer.classList.remove(&amp;quot;show-modal&amp;quot;);&lt;br /&gt;
    window.removeEventListener(&amp;quot;click&amp;quot;, handleClickOutside);&lt;br /&gt;
    window.removeEventListener(&amp;quot;keydown&amp;quot;, handleEscape);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function handleClickOutside(event) {&lt;br /&gt;
    if (event.target === modalContainer) {&lt;br /&gt;
      closeModal();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function handleEscape(event) {&lt;br /&gt;
    if (event.key === &amp;quot;Escape&amp;quot;) {&lt;br /&gt;
      closeModal();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
});&lt;/div&gt;</summary>
		<author><name>Dexter</name></author>
		
	</entry>
	<entry>
		<id>https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Common.css&amp;diff=105339</id>
		<title>MediaWiki:Common.css</title>
		<link rel="alternate" type="text/html" href="https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Common.css&amp;diff=105339"/>
		<updated>2024-11-30T22:11:22Z</updated>

		<summary type="html">&lt;p&gt;Dexter : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;/* Le CSS placé ici sera chargé sur toutes les pages */&lt;br /&gt;
&lt;br /&gt;
html {&lt;br /&gt;
  scroll-behavior: smooth;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
body {&lt;br /&gt;
  background-image: url('https://fr-wiki.metin2.gameforge.com/images/b/bf/Fondhalloween.png');&lt;br /&gt;
}&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
body {&lt;br /&gt;
  background-image: url('https://fr-wiki.metin2.gameforge.com/images/1/15/Fond2015.jpg');&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#mw-content ul {&lt;br /&gt;
    margin-bottom: 0.3em;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#mw-content ol {&lt;br /&gt;
  list-style: none;&lt;br /&gt;
  counter-reset: custom-counter;&lt;br /&gt;
  margin: 0.3em 0 0.3em 1.6em;&lt;br /&gt;
  padding: 0;&lt;br /&gt;
}&lt;br /&gt;
ol li {&lt;br /&gt;
  padding: 0;&lt;br /&gt;
  counter-increment: custom-counter;&lt;br /&gt;
}&lt;br /&gt;
ol li::marker {&lt;br /&gt;
  content: counter(custom-counter) &amp;quot;.  &amp;quot;;&lt;br /&gt;
  font-weight: bold;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
td, th {&lt;br /&gt;
  padding: 2px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.map span.mw-collapsible-toggle {&lt;br /&gt;
  padding-right: 10px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
table.map a.mw-collapsible-text,&lt;br /&gt;
.prettytable &amp;gt; span.mw-collapsible-toggle,&lt;br /&gt;
.prettytable &amp;gt; span.mw-collapsible-toggle &amp;gt; a {&lt;br /&gt;
  color: #ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.boxesheaderbackground, .cadre &amp;gt; div:first-child {&lt;br /&gt;
  background: repeat url(&amp;quot;https://fr-wiki.metin2.gameforge.com/images/a/a7/Boxheaderbrown.png&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.cadre {&lt;br /&gt;
  border: 1px solid #2f1d1f;&lt;br /&gt;
  border-radius: 15px 0;&lt;br /&gt;
  width: 100%;&lt;br /&gt;
  box-shadow: 3px 3px 9px 0px #544e41;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.cadre &amp;gt; div:first-child {&lt;br /&gt;
  text-align: center;&lt;br /&gt;
  color: white;&lt;br /&gt;
  line-height: 25px;&lt;br /&gt;
  overflow: hidden;&lt;br /&gt;
  border-top-left-radius: 15px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.fondfenetre,&lt;br /&gt;
.sous-titre,&lt;br /&gt;
table.pretty-table th { &lt;br /&gt;
  background: url(&amp;quot;https://fr-wiki.metin2.gameforge.com/images/8/89/Fondfenetre.png&amp;quot;) repeat;&lt;br /&gt;
  color: white;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
table.pretty-table td {&lt;br /&gt;
  padding: 5px 10px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
table.pretty-table th {&lt;br /&gt;
  padding: 2px 10px;&lt;br /&gt;
  font-weight: normal;&lt;br /&gt;
  font-size: 1.1em;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
table.pretty-table tbody &amp;gt; *:nth-child(2n+1) &amp;gt; td {&lt;br /&gt;
  background: rgba(0, 0, 0, .1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
table.pretty-table tr:hover {&lt;br /&gt;
  background: rgba(0, 0, 0, .05);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
table.pretty-table tr:first-child &amp;gt; th:first-child {&lt;br /&gt;
  border-radius: 8px 0 0 0;&lt;br /&gt;
  overflow: hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
table.pretty-table caption {&lt;br /&gt;
  margin-top: 10px;&lt;br /&gt;
  font-weight: bold;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.fondfenetre a,&lt;br /&gt;
.fondfenetre span,&lt;br /&gt;
table.pretty-table th a,&lt;br /&gt;
table.pretty-table th span {&lt;br /&gt;
  color: white;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
table.sticky-header-row thead tr {&lt;br /&gt;
  position: sticky;&lt;br /&gt;
  top: 0;&lt;br /&gt;
  z-index: 10;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
table.sticky-header-column th:first-child {&lt;br /&gt;
  position: sticky;&lt;br /&gt;
  left: 0;&lt;br /&gt;
  z-index: 20;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sous-titre {&lt;br /&gt;
  max-width: 180px;&lt;br /&gt;
  border: 1px solid black;&lt;br /&gt;
  border-radius: 8px;&lt;br /&gt;
  color: white;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.modeleAnnonce {&lt;br /&gt;
  border-image: url(&amp;quot;https://fr-wiki.metin2.gameforge.com/images/f/fb/Modeleannonce.png&amp;quot;) 17 35 3 fill / auto / 0 repeat;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.container { &lt;br /&gt;
 display: flex;&lt;br /&gt;
 flex-direction: row; &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.monster-card { &lt;br /&gt;
 border: 1px black solid;&lt;br /&gt;
 padding: 5px;&lt;br /&gt;
 max-width: 400px;&lt;br /&gt;
 box-sizing: border-box;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.monster-card &amp;gt; :first-child {&lt;br /&gt;
 display: flex;&lt;br /&gt;
 justify-content: space-between;&lt;br /&gt;
 margin-bottom: 5px;&lt;br /&gt;
 line-height: 25px;&lt;br /&gt;
 padding: 0 5px;&lt;br /&gt;
 background: none;&lt;br /&gt;
 background-color: black;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.button {&lt;br /&gt;
  border: 2px solid grey;&lt;br /&gt;
  padding: 0 12px;&lt;br /&gt;
  line-height: 25px;&lt;br /&gt;
  border-radius: 16px;&lt;br /&gt;
  background: rgba(234, 234, 234);&lt;br /&gt;
  cursor: pointer;&lt;br /&gt;
  display: inline-block;&lt;br /&gt;
  position: relative;&lt;br /&gt;
  user-select: none;&lt;br /&gt;
  white-space: nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.button:hover {&lt;br /&gt;
  background: transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.modal {&lt;br /&gt;
    opacity: 0;&lt;br /&gt;
    visibility: hidden;&lt;br /&gt;
    transform: scale(1.1);&lt;br /&gt;
    transition: visibility 0s linear 0.25s, opacity 0.25s 0s, transform 0.25s;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.close-button {&lt;br /&gt;
  transition: color .2s linear, background-color .2s linear;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.close-button:hover {&lt;br /&gt;
  background-color: red;&lt;br /&gt;
  color: #ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.show-modal {&lt;br /&gt;
    opacity: 1;&lt;br /&gt;
    visibility: visible;&lt;br /&gt;
    transform: scale(1.0);&lt;br /&gt;
    transition: visibility 0s linear 0s, opacity 0.25s 0s, transform 0.25s;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.cacheOrdi,&lt;br /&gt;
.gen-active {&lt;br /&gt;
  display: block;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.texte-long,&lt;br /&gt;
.texte-long-2 {&lt;br /&gt;
  text-overflow: ellipsis;&lt;br /&gt;
  white-space: nowrap;&lt;br /&gt;
  overflow: hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.texte-long:hover,&lt;br /&gt;
.texte-long-2:hover {&lt;br /&gt;
  white-space: normal;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.shop-img img {&lt;br /&gt;
    height: auto;&lt;br /&gt;
    width: auto;&lt;br /&gt;
    max-height: 130px;&lt;br /&gt;
    max-width: 130px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#mw-content .soulignement &amp;gt; a:link {&lt;br /&gt;
  text-decoration: none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.popContenu {&lt;br /&gt;
  display: inline-block;&lt;br /&gt;
  transition: all 0.4s ease;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.popInfo:hover .popContenu {&lt;br /&gt;
  opacity: 1 !important;&lt;br /&gt;
  transition: all 0.4s ease;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.cadreFenetre {&lt;br /&gt;
  border: solid;&lt;br /&gt;
  border-image: url(&amp;quot;https://fr-wiki.metin2.gameforge.com/images/1/11/Cadrefenetre.png&amp;quot;) 11 fill / auto / 0 repeat;&lt;br /&gt;
  padding: 10px;&lt;br /&gt;
  backdrop-filter: blur(4px);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tabber-active.button {&lt;br /&gt;
  background: rgba(75, 85, 95);&lt;br /&gt;
  color: white;&lt;br /&gt;
  border: 2px solid rgba(75, 85, 95);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
ul.subpage {&lt;br /&gt;
  display: flex;&lt;br /&gt;
  list-style: none;&lt;br /&gt;
  margin: 0 0 10px;&lt;br /&gt;
  padding: 0;&lt;br /&gt;
  background: rgba(81,36,16, 0.3);&lt;br /&gt;
  overflow: hidden;&lt;br /&gt;
  line-height: 30px;&lt;br /&gt;
  white-space: nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.subpage a {&lt;br /&gt;
  padding-left: 20px;&lt;br /&gt;
  background: #512410;&lt;br /&gt;
  display: inline-block;&lt;br /&gt;
  line-height: 30px;&lt;br /&gt;
  position: relative;&lt;br /&gt;
  color: #f1de8e;&lt;br /&gt;
  cursor: pointer;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.subpage a:before,&lt;br /&gt;
.subpage a:after { &lt;br /&gt;
  content: &amp;quot;&amp;quot;;&lt;br /&gt;
  position: absolute;&lt;br /&gt;
  width: 0;&lt;br /&gt;
  height: 0;&lt;br /&gt;
  right: 0;&lt;br /&gt;
  padding: 1px 0;&lt;br /&gt;
  border-top: 14px solid transparent;&lt;br /&gt;
  border-bottom: 14px solid transparent;&lt;br /&gt;
  border-left: 14px solid white;&lt;br /&gt;
  transform: translate(14px);&lt;br /&gt;
  z-index: 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.subpage a:after {&lt;br /&gt;
  border-left: 14px solid #512410;&lt;br /&gt;
  transform: translate(13px);&lt;br /&gt;
  z-index: 2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.subpage &amp;gt; li:last-child {&lt;br /&gt;
  padding-left: 20px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
ul.subpage &amp;gt; li:first-child {&lt;br /&gt;
  flex-shrink: 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
ul.subpage &amp;gt; li:first-child &amp;gt; a {&lt;br /&gt;
  height: 100%;&lt;br /&gt;
  display: flex;&lt;br /&gt;
  align-items: center;&lt;br /&gt;
  padding-left: 10px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
ul.subpage &amp;gt; li &amp;gt; a:hover {&lt;br /&gt;
  background: #9D5B37;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
ul.subpage &amp;gt; li &amp;gt; a:hover:after {&lt;br /&gt;
  border-left-color: #9D5B37; &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.image-sizing img,&lt;br /&gt;
.image-sizing-200 img,&lt;br /&gt;
.image-sizing-none img {&lt;br /&gt;
  height: auto;&lt;br /&gt;
  width: auto;&lt;br /&gt;
  max-height: 300px;&lt;br /&gt;
  max-width: 100%;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.image-sizing-200 img {&lt;br /&gt;
  max-height: 200px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.image-sizing-none img {&lt;br /&gt;
  max-height: none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
div.ul-res ul {&lt;br /&gt;
  margin: 0;&lt;br /&gt;
  list-style: none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tab-glob {&lt;br /&gt;
    display: flex;&lt;br /&gt;
    flex-direction: row;&lt;br /&gt;
    margin: 10px 0;&lt;br /&gt;
    column-gap: 2px;&lt;br /&gt;
    align-items: flex-start;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tab-glob &amp;gt; :first-child {&lt;br /&gt;
    display: grid;&lt;br /&gt;
    grid-template-columns: max-content;&lt;br /&gt;
    row-gap: 2px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tab-glob &amp;gt; :first-child &amp;gt; * {&lt;br /&gt;
    border: 1px black solid;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tab-glob &amp;gt; :first-child &amp;gt; *:not(.fondfenetre) {&lt;br /&gt;
    font-weight: bold;&lt;br /&gt;
    display: flex;&lt;br /&gt;
    justify-content: center;&lt;br /&gt;
    align-items: center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tab-glob &amp;gt; :nth-child(2) {&lt;br /&gt;
    width: 100%;&lt;br /&gt;
    overflow-x: auto;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tab-glob &amp;gt; :nth-child(2) &amp;gt; :first-child {&lt;br /&gt;
    display: grid;&lt;br /&gt;
    grid-template-columns: repeat(10,minmax(75px,1fr));&lt;br /&gt;
    gap: 2px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tab-glob &amp;gt; :nth-child(2) &amp;gt; :first-child &amp;gt; * {&lt;br /&gt;
    border: 1px black solid;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tab-glob &amp;gt; :nth-child(2) &amp;gt; :first-child &amp;gt; :not(.fondfenetre) {&lt;br /&gt;
    display: flex;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tab-glob &amp;gt; :nth-child(2) &amp;gt; :first-child &amp;gt; :not(.fondfenetre) &amp;gt; * {&lt;br /&gt;
  margin: auto;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.list-equip {&lt;br /&gt;
  padding: 5px;&lt;br /&gt;
  border: 1px solid #2f1d1f;&lt;br /&gt;
  display: flex;&lt;br /&gt;
  flex-direction: column;&lt;br /&gt;
  align-items: center;&lt;br /&gt;
  gap: 5px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.list-equip &amp;gt; :first-child {&lt;br /&gt;
  width: 100%;&lt;br /&gt;
  line-height: 25px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.list-equip &amp;gt; :first-child &amp;gt; * {&lt;br /&gt;
  padding: 0 5px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.fabrication {&lt;br /&gt;
  position: relative;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.fabrication &amp;gt; * {&lt;br /&gt;
  position: absolute;&lt;br /&gt;
  top: -188px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.fabrication &amp;gt; .bottom-fab,&lt;br /&gt;
.fabrication &amp;gt; .bottom-fab ~ * {&lt;br /&gt;
  top: -58px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.fabrication &amp;gt; * &amp;gt; *:nth-child(2) {&lt;br /&gt;
  position: relative;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.fabrication &amp;gt; * &amp;gt; *:nth-child(2) &amp;gt; * {&lt;br /&gt;
  position: absolute;&lt;br /&gt;
  top: -18px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.fabrication &amp;gt; * &amp;gt; *:nth-child(n+3) {&lt;br /&gt;
  position: absolute;&lt;br /&gt;
  top: 100px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.info-boutique ul {&lt;br /&gt;
  list-style-image: none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.info-boutique p:last-child {&lt;br /&gt;
  margin-bottom: 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
kbd {&lt;br /&gt;
  background-color: #eee;&lt;br /&gt;
  border-radius: 3px;&lt;br /&gt;
  border: 1px solid #b4b4b4;&lt;br /&gt;
  box-shadow: 0 1px 1px rgb(0 0 0 / 20%), 0 2px 0 0 rgb(255 255 255 / 70%) inset;&lt;br /&gt;
  color: #333;&lt;br /&gt;
  display: inline-block;&lt;br /&gt;
  font-size: 0.85em;&lt;br /&gt;
  font-weight: 700;&lt;br /&gt;
  line-height: 1;&lt;br /&gt;
  padding: 2px 4px;&lt;br /&gt;
  white-space: nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.top-button {&lt;br /&gt;
  display: flex;&lt;br /&gt;
  justify-content: center;&lt;br /&gt;
  align-items: center;&lt;br /&gt;
  opacity: 0;&lt;br /&gt;
  cursor: pointer;&lt;br /&gt;
  position: fixed;&lt;br /&gt;
  bottom: 10px;&lt;br /&gt;
  right: 10px;&lt;br /&gt;
  width: 32px;&lt;br /&gt;
  height: 32px;&lt;br /&gt;
  background: linear-gradient(180deg, &lt;br /&gt;
    rgba(124, 200, 65, 1) 0%, &lt;br /&gt;
    rgba(113, 161, 85, 1) 50%, &lt;br /&gt;
    rgba(64, 117, 39, 1) 50%, &lt;br /&gt;
    rgba(46, 97, 31, 1) 100%);&lt;br /&gt;
  border: 1px solid #d0af52;&lt;br /&gt;
  box-shadow: 1px 1px 2px #000,&lt;br /&gt;
              inset 1px 1px #090200,&lt;br /&gt;
              inset -1px -1px #090200; &lt;br /&gt;
  transform: translateY(100px);&lt;br /&gt;
  transition: all 0.5s ease;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.top-button:after {&lt;br /&gt;
  content: &amp;quot;&amp;quot;;&lt;br /&gt;
  height: 32px;&lt;br /&gt;
  width: 32px;&lt;br /&gt;
  background-image: url(&amp;quot;data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fffacb' height='32' viewBox='0 -960 960 960' width='32'%3E%3Cpath d='m296-345-56-56 240-240 240 240-56 56-184-184-184 184Z'/%3E%3C/svg%3E&amp;quot;);&lt;br /&gt;
  background-repeat: no-repeat;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.show-button {&lt;br /&gt;
  opacity: 1;&lt;br /&gt;
  transform: translateY(0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.ul-row ul {&lt;br /&gt;
  display: flex;&lt;br /&gt;
  column-gap: 30px;&lt;br /&gt;
  flex-wrap: wrap;&lt;br /&gt;
  overflow: hidden;&lt;br /&gt;
  margin: 0;&lt;br /&gt;
  list-style-image: none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.flex {&lt;br /&gt;
  display: flex;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#catlinks {&lt;br /&gt;
  margin-top: 10px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.improved-collapsible &amp;gt; .mw-collapsible-toggle {&lt;br /&gt;
  grid-area: 1 / -1;&lt;br /&gt;
  display: flex;&lt;br /&gt;
  justify-content: flex-end;&lt;br /&gt;
  align-items: center;&lt;br /&gt;
  float: initial;&lt;br /&gt;
  z-index: 1;&lt;br /&gt;
  padding-right: 5px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.improved-collapsible .mw-collapsible-toggle:before {&lt;br /&gt;
  content: &amp;quot;&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.improved-collapsible .mw-collapsible-text {&lt;br /&gt;
  display: none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.improved-collapsible .mw-collapsible-toggle:after {&lt;br /&gt;
  width: 32px;&lt;br /&gt;
  height: 32px;&lt;br /&gt;
  content: &amp;quot;&amp;quot;;&lt;br /&gt;
  background-image: url(&amp;quot;data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23000000' height='32' viewBox='0 -960 960 960' width='32'%3E%3Cpath d='M480-345 240-585l56-56 184 184 184-184 56 56-240 240Z'/%3E%3C/svg%3E&amp;quot;);&lt;br /&gt;
  background-repeat: no-repeat;&lt;br /&gt;
  transition: transform .2s ease-in-out;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.improved-collapsible .mw-collapsible-toggle-expanded:after {&lt;br /&gt;
  transform: rotate(-180deg);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tooltip-icon {&lt;br /&gt;
  background-image: url(&amp;quot;data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' height='24' viewBox='0 -960 960 960' width='24'%3E%3Cpath d='M443-285h75v-234h-75v234Zm36.895-311Q496-596 507-606.895q11-10.894 11-27Q518-650 507.105-661q-10.894-11-27-11Q464-672 453-661.105q-11 10.894-11 27Q442-618 452.895-607q10.894 11 27 11ZM480-90q-80.907 0-152.065-30.763-71.159-30.763-123.797-83.5Q151.5-257 120.75-328.087 90-399.175 90-480q0-80.907 30.763-152.065 30.763-71.159 83.5-123.797Q257-808.5 328.087-839.25 399.175-870 480-870q80.907 0 152.065 30.763 71.159 30.763 123.797 83.5Q808.5-703 839.25-631.913 870-560.825 870-480q0 80.907-30.763 152.065-30.763 71.159-83.5 123.797Q703-151.5 631.913-120.75 560.825-90 480-90Zm0-75q131.5 0 223.25-91.75T795-480q0-131.5-91.75-223.25T480-795q-131.5 0-223.25 91.75T165-480q0 131.5 91.75 223.25T480-165Zm0-315Z'/%3E%3C/svg%3E&amp;quot;);&lt;br /&gt;
  background-repeat: no-repeat;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tooltip-info {&lt;br /&gt;
  position: absolute;&lt;br /&gt;
  bottom: calc(100% + 8px);&lt;br /&gt;
  left: 50%;&lt;br /&gt;
  transform: translateX(-50%);&lt;br /&gt;
  max-width: 290px;&lt;br /&gt;
  width: max-content;&lt;br /&gt;
  z-index: 50;&lt;br /&gt;
  opacity: 0;&lt;br /&gt;
  visibility: hidden;&lt;br /&gt;
  transition: opacity 0.2s ease, visibility 0.2s ease;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tooltip-info:after {&lt;br /&gt;
    content: &amp;quot;&amp;quot;;&lt;br /&gt;
    border: 8px solid transparent;&lt;br /&gt;
    border-top-color: inherit;&lt;br /&gt;
    position: absolute;&lt;br /&gt;
    left: calc(50% - 8px);&lt;br /&gt;
    top: 100%;&lt;br /&gt;
    z-index: 50;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tooltip-icon:hover &amp;gt; .tooltip-info {&lt;br /&gt;
  opacity: 1;&lt;br /&gt;
  visibility: visible;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.cacheTel,&lt;br /&gt;
.tabber-container &amp;gt; :last-child &amp;gt; :not(.tabber-active),&lt;br /&gt;
.tabber-noactive {&lt;br /&gt;
  display: none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes pnj-square {&lt;br /&gt;
  from {background-color: #f80000;}&lt;br /&gt;
  to {background-color: white;}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes pnj-circle {&lt;br /&gt;
  from {border-color: #984c48;}&lt;br /&gt;
  to {border-color: white;}&lt;br /&gt;
  from {scale: 1;}&lt;br /&gt;
  to {scale: .1;}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes loading {&lt;br /&gt;
  0% {&lt;br /&gt;
    transform: scale(1.5);&lt;br /&gt;
  }&lt;br /&gt;
  100% {&lt;br /&gt;
    transform: scale(1);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
@media screen and (max-width: 768px){&lt;br /&gt;
  .texte-long {&lt;br /&gt;
    white-space: normal;&lt;br /&gt;
    overflow: visible;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  .grid2 {&lt;br /&gt;
    grid-template-columns: repeat(2, 1fr) !important;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  .grid3 {&lt;br /&gt;
    grid-template-columns: repeat(3, auto) !important;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  .modal-content {&lt;br /&gt;
    padding: 30px 0 0 10px;&lt;br /&gt;
    width: 90%;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  .container { &lt;br /&gt;
   flex-direction: column; &lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  .cacheTel,&lt;br /&gt;
  .subpage &amp;gt; li:nth-last-child(2) &amp;gt; a {&lt;br /&gt;
    display: block;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  .top-button {&lt;br /&gt;
    background: rgba(0, 0, 0, 0.7);&lt;br /&gt;
    color: #999;&lt;br /&gt;
    border: none;&lt;br /&gt;
    box-shadow: none;&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  .top-button::after {&lt;br /&gt;
    background-image: url(&amp;quot;data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23ffffff' height='24' viewBox='0 -960 960 960' width='24'%3E%3Cpath d='M440-80v-647L256-544l-56-56 280-280 280 280-56 57-184-184v647h-80Z'/%3E%3C/svg%3E&amp;quot;);&lt;br /&gt;
    height: 24px;&lt;br /&gt;
    width: 24px;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  .tooltip-icon {&lt;br /&gt;
    position: static;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  .tooltip-info {&lt;br /&gt;
    position: fixed;&lt;br /&gt;
    left: 20px;&lt;br /&gt;
    right: 20px;&lt;br /&gt;
    bottom: 50px;&lt;br /&gt;
    max-width: none;&lt;br /&gt;
    width: auto;&lt;br /&gt;
    transform: none;&lt;br /&gt;
    height: max-content;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  .subpage &amp;gt; li &amp;gt; a,&lt;br /&gt;
  .cacheOrdi,&lt;br /&gt;
  .tooltip-info:after {&lt;br /&gt;
    display: none;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
@media screen and (max-width: 340px){&lt;br /&gt;
  #mw-content {&lt;br /&gt;
    padding-left: 10px;&lt;br /&gt;
    padding-right: 10px;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
@media screen and (min-width: 851px){&lt;br /&gt;
  html {&lt;br /&gt;
    scroll-padding-top: 3.325em;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;/div&gt;</summary>
		<author><name>Dexter</name></author>
		
	</entry>
	<entry>
		<id>https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Common.js&amp;diff=105316</id>
		<title>MediaWiki:Common.js</title>
		<link rel="alternate" type="text/html" href="https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Common.js&amp;diff=105316"/>
		<updated>2024-11-29T07:02:42Z</updated>

		<summary type="html">&lt;p&gt;Dexter : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;/* Tout le JavaScript ici sera chargé avec chaque page accédée par n’importe quel utilisateur. */&lt;br /&gt;
&lt;br /&gt;
/* =====================================&lt;br /&gt;
DECLARATIONS DES FONCTIONS ET PROCEDURES&lt;br /&gt;
======================================== */&lt;br /&gt;
&lt;br /&gt;
/* Favicon */&lt;br /&gt;
function fixInsecureFavicon() {&lt;br /&gt;
    document.querySelector('link[rel=&amp;quot;shortcut icon&amp;quot;]').href = &amp;quot;https://gf1.geo.gfsrv.net/cdn98/191b803adbf82f4b8febe3a2c38c2c.ico&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* Liste des équipements */&lt;br /&gt;
function changeDisplay(content) {&lt;br /&gt;
    var boutonSwitch = content.querySelector(&amp;quot;.button&amp;quot;);&lt;br /&gt;
    var frereList = content.nextElementSibling;&lt;br /&gt;
&lt;br /&gt;
    boutonSwitch.addEventListener(&amp;quot;click&amp;quot;, function () {&lt;br /&gt;
        this.classList.toggle('tabber-active');&lt;br /&gt;
        frereList.classList.toggle('tabber-noactive');&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* BOUTON RETOUR VERS LE HAUT */&lt;br /&gt;
function addButtonTop() {&lt;br /&gt;
    var contentText = document.querySelector(&amp;quot;div#mw-content-text&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (contentText !== null) {&lt;br /&gt;
&lt;br /&gt;
        var divButtonTop = document.createElement(&amp;quot;div&amp;quot;);&lt;br /&gt;
        divButtonTop.classList.add(&amp;quot;top-button&amp;quot;);&lt;br /&gt;
        contentText.appendChild(divButtonTop);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function buttonTop() {&lt;br /&gt;
    var balise = document.querySelector(&amp;quot;div#mw-page-header-links&amp;quot;);&lt;br /&gt;
    var topButton = document.querySelector(&amp;quot;.top-button&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (balise !== null) {&lt;br /&gt;
        var options = {&lt;br /&gt;
            root: null,&lt;br /&gt;
            rootMargin: &amp;quot;0px&amp;quot;,&lt;br /&gt;
            threshold: 0,&lt;br /&gt;
        };&lt;br /&gt;
&lt;br /&gt;
        var observer = new IntersectionObserver(callback, options);&lt;br /&gt;
        observer.observe(balise);&lt;br /&gt;
&lt;br /&gt;
        function callback(entries) {&lt;br /&gt;
            entries.forEach(function (entry) {&lt;br /&gt;
                if (entry.isIntersecting) {&lt;br /&gt;
                    topButton.classList.remove(&amp;quot;show-button&amp;quot;);&lt;br /&gt;
                } else {&lt;br /&gt;
                    topButton.classList.add(&amp;quot;show-button&amp;quot;);&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        topButton.addEventListener(&amp;quot;click&amp;quot;, function () {&lt;br /&gt;
            document.documentElement.scrollTo({&lt;br /&gt;
                top: 0&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* Cookies */&lt;br /&gt;
function cookies() {&lt;br /&gt;
    var req = new XMLHttpRequest();&lt;br /&gt;
    req.addEventListener('load', function (ev) {&lt;br /&gt;
        if (this.status &amp;gt;= 200 &amp;amp;&amp;amp; this.status &amp;lt; 300) {&lt;br /&gt;
            var data = JSON.parse(this.responseText);&lt;br /&gt;
            if (data.hasOwnProperty('version')) {&lt;br /&gt;
                var gdpr = document.createElement(&amp;quot;script&amp;quot;);&lt;br /&gt;
                gdpr.src = &amp;quot;https://s3-static.geo.gfsrv.net/cookiebanner/&amp;quot; + data.version + &amp;quot;/cookie.min.js&amp;quot;;&lt;br /&gt;
                document.head.appendChild(gdpr);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
    req.open('GET', &amp;quot;https://s3-static.geo.gfsrv.net/cookiebanner/version.json&amp;quot;);&lt;br /&gt;
    req.send();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function addScript(src, callback) {&lt;br /&gt;
    var script = document.createElement('script');&lt;br /&gt;
    script.src = src;&lt;br /&gt;
&lt;br /&gt;
    function onComplete() {&lt;br /&gt;
        if (script.parentNode) {&lt;br /&gt;
            script.parentNode.removeChild(script);&lt;br /&gt;
        }&lt;br /&gt;
        if (callback) {&lt;br /&gt;
            callback();&lt;br /&gt;
            callback = null;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    script.onload = onComplete;&lt;br /&gt;
    script.onerror = onComplete;&lt;br /&gt;
&lt;br /&gt;
    document.head.appendChild(script);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/* =======================================&lt;br /&gt;
FONCTION GLOBALE&lt;br /&gt;
Exécutée une fois au chargement de la page&lt;br /&gt;
========================================== */&lt;br /&gt;
&lt;br /&gt;
(function () {&lt;br /&gt;
    fixInsecureFavicon()&lt;br /&gt;
&lt;br /&gt;
    var equipmentContainer = document.querySelectorAll('div#mw-content-text .list-equip');&lt;br /&gt;
    var loadScripts = document.querySelectorAll('div[data-load-javascript]');&lt;br /&gt;
&lt;br /&gt;
    equipmentContainer.forEach(function (container) {&lt;br /&gt;
        changeDisplay(container);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    /* Charge des scripts spécifiques au chargement de certaines pages */&lt;br /&gt;
    if (loadScripts.length &amp;gt; 0) {&lt;br /&gt;
&lt;br /&gt;
        var allowedScripts = [&amp;quot;Tabber&amp;quot;, &amp;quot;Skills&amp;quot;, &amp;quot;Modal&amp;quot;, &amp;quot;Switch&amp;quot;, &amp;quot;Loot&amp;quot;, &amp;quot;Map&amp;quot;, &amp;quot;Filter&amp;quot;, &amp;quot;Calculator&amp;quot;, &amp;quot;Element&amp;quot;, &amp;quot;Pets&amp;quot;, &amp;quot;Colorblind&amp;quot;];&lt;br /&gt;
        var scriptsToLoad = [];&lt;br /&gt;
&lt;br /&gt;
        for (var i = 0; i &amp;lt; loadScripts.length; i++) {&lt;br /&gt;
&lt;br /&gt;
            var script = loadScripts[i].dataset['loadJavascript'];&lt;br /&gt;
&lt;br /&gt;
            if ((allowedScripts.indexOf(script) !== -1) &amp;amp;&amp;amp; (scriptsToLoad.indexOf(script) === -1)) {&lt;br /&gt;
                scriptsToLoad.push(script);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        function loadNextScript() {&lt;br /&gt;
            if (scriptsToLoad.length &amp;gt; 0) {&lt;br /&gt;
                var script = scriptsToLoad.shift();&lt;br /&gt;
                addScript(&amp;quot;/index.php?title=MediaWiki:Script/&amp;quot; + script + &amp;quot;.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&amp;quot;, loadNextScript);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        loadNextScript();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (mw.config.get(&amp;quot;wgUserName&amp;quot;)) {&lt;br /&gt;
        mw.loader.load(&amp;quot;/index.php?title=MediaWiki:Script/Redactor.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    addButtonTop();&lt;br /&gt;
    buttonTop();&lt;br /&gt;
    cookies()&lt;br /&gt;
})();&lt;/div&gt;</summary>
		<author><name>Dexter</name></author>
		
	</entry>
	<entry>
		<id>https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Script/Modal.js&amp;diff=105315</id>
		<title>MediaWiki:Script/Modal.js</title>
		<link rel="alternate" type="text/html" href="https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Script/Modal.js&amp;diff=105315"/>
		<updated>2024-11-29T07:01:38Z</updated>

		<summary type="html">&lt;p&gt;Dexter : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;function createModalInteraction(content) {&lt;br /&gt;
    const boutonModal = content.querySelector(&amp;quot;.button&amp;quot;);&lt;br /&gt;
    const modalContent = content.querySelector(&amp;quot;.modal&amp;quot;);&lt;br /&gt;
    const boutonClose = content.querySelector(&amp;quot;.close&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    const openModal = () =&amp;gt; {&lt;br /&gt;
        boutonModal.classList.add(&amp;quot;tabber-active&amp;quot;);&lt;br /&gt;
        modalContent.classList.add(&amp;quot;gen-active&amp;quot;);&lt;br /&gt;
        window.addEventListener(&amp;quot;click&amp;quot;, handleClickOutside);&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    const closeModal = () =&amp;gt; {&lt;br /&gt;
        boutonModal.classList.remove(&amp;quot;tabber-active&amp;quot;);&lt;br /&gt;
        modalContent.classList.remove(&amp;quot;gen-active&amp;quot;);&lt;br /&gt;
        window.removeEventListener(&amp;quot;click&amp;quot;, handleClickOutside);&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    const handleClickOutside = (event) =&amp;gt; {&lt;br /&gt;
        if (event.target === modalContent) {&lt;br /&gt;
            closeModal();&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    boutonModal.addEventListener(&amp;quot;click&amp;quot;, openModal);&lt;br /&gt;
    boutonClose.addEventListener(&amp;quot;click&amp;quot;, closeModal);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
(() =&amp;gt; {&lt;br /&gt;
    const modalContainers = document.querySelectorAll(&amp;quot;div#mw-content-text div.modalContainer&amp;quot;);&lt;br /&gt;
    modalContainers.forEach(createModalInteraction);&lt;br /&gt;
})();&lt;/div&gt;</summary>
		<author><name>Dexter</name></author>
		
	</entry>
	<entry>
		<id>https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Script/Colorblind.js&amp;diff=105314</id>
		<title>MediaWiki:Script/Colorblind.js</title>
		<link rel="alternate" type="text/html" href="https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Script/Colorblind.js&amp;diff=105314"/>
		<updated>2024-11-29T06:59:13Z</updated>

		<summary type="html">&lt;p&gt;Dexter : Page créée avec « const SPAWN_LAYER_COLOR = &amp;quot;spawnLayerColor&amp;quot;; const OPTION_MAPPING = {   0: &amp;quot;🟥 Rouge&amp;quot;,   50: &amp;quot;🟫 Marron&amp;quot;,   140: &amp;quot;🟩 Vert&amp;quot;,   230: &amp;quot;🟦 Bleu&amp;quot;,   290: &amp;quot;🟪 Violet&amp;quot;,... »&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;const SPAWN_LAYER_COLOR = &amp;quot;spawnLayerColor&amp;quot;;&lt;br /&gt;
const OPTION_MAPPING = {&lt;br /&gt;
  0: &amp;quot;🟥 Rouge&amp;quot;,&lt;br /&gt;
  50: &amp;quot;🟫 Marron&amp;quot;,&lt;br /&gt;
  140: &amp;quot;🟩 Vert&amp;quot;,&lt;br /&gt;
  230: &amp;quot;🟦 Bleu&amp;quot;,&lt;br /&gt;
  290: &amp;quot;🟪 Violet&amp;quot;,&lt;br /&gt;
  black: &amp;quot;⬛ Noir&amp;quot;,&lt;br /&gt;
  white: &amp;quot;⬜ Blanc&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
const STYLE_MAPPING = {&lt;br /&gt;
  position: &amp;quot;absolute&amp;quot;,&lt;br /&gt;
  left: &amp;quot;0&amp;quot;,&lt;br /&gt;
  margin: &amp;quot;0&amp;quot;,&lt;br /&gt;
  background: &amp;quot;#434242b3&amp;quot;,&lt;br /&gt;
  color: &amp;quot;white&amp;quot;,&lt;br /&gt;
  borderRadius: &amp;quot;5px&amp;quot;,&lt;br /&gt;
  cursor: &amp;quot;pointer&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
const spawnLayerContainers = document.querySelectorAll(&amp;quot;.spawn-layer&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
if (spawnLayerContainers.length) {&lt;br /&gt;
  initializeSpawnLayers(spawnLayerContainers);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initializeSpawnLayers(spawnLayerContainers) {&lt;br /&gt;
    const selects = [];&lt;br /&gt;
    const spawnLayers = [];&lt;br /&gt;
    const spawnLayerColor = localStorage.getItem(SPAWN_LAYER_COLOR);&lt;br /&gt;
&lt;br /&gt;
    spawnLayerContainers.forEach((spawnLayerContainer) =&amp;gt; {&lt;br /&gt;
        const spawnLayer = spawnLayerContainer.querySelector(&amp;quot;img&amp;quot;);&lt;br /&gt;
        &lt;br /&gt;
        if (spawnLayer) {&lt;br /&gt;
            const selectColor = createSelectColor();&lt;br /&gt;
            spawnLayerContainer.appendChild(selectColor);&lt;br /&gt;
            selects.push(selectColor);&lt;br /&gt;
            spawnLayers.push(spawnLayer);&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    function handleChange(event) {&lt;br /&gt;
        changeSpawnLayerColor(event.target.value, selects, spawnLayers);&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    selects.forEach(select =&amp;gt; {&lt;br /&gt;
        select.addEventListener(&amp;quot;change&amp;quot;, handleChange);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    if (spawnLayerColor) {&lt;br /&gt;
        changeSpawnLayerColor(spawnLayerColor, selects, spawnLayers);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createSelectColor() {&lt;br /&gt;
    const select = document.createElement(&amp;quot;select&amp;quot;);&lt;br /&gt;
    Object.entries(OPTION_MAPPING).forEach(([key, value]) =&amp;gt; {&lt;br /&gt;
        const option = document.createElement(&amp;quot;option&amp;quot;);&lt;br /&gt;
        option.value = key;&lt;br /&gt;
        option.textContent = value;&lt;br /&gt;
        select.appendChild(option);&lt;br /&gt;
    });&lt;br /&gt;
    Object.entries(STYLE_MAPPING).forEach(([property, value]) =&amp;gt; {&lt;br /&gt;
        select.style[property] = value;&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    return select;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function changeSpawnLayerColor(value, selects, spawnLayers) {&lt;br /&gt;
    if (!OPTION_MAPPING.hasOwnProperty(value)) {&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    let filter;&lt;br /&gt;
&lt;br /&gt;
    if (value === &amp;quot;black&amp;quot;) {&lt;br /&gt;
        filter = &amp;quot;invert(1) brightness(0) contrast(100%)&amp;quot;;&lt;br /&gt;
    } else if (value === &amp;quot;white&amp;quot;) {&lt;br /&gt;
        filter = &amp;quot;invert(1) sepia(1) saturate(100%) brightness(3)&amp;quot;;&lt;br /&gt;
    } else {&lt;br /&gt;
        filter = `hue-rotate(${value}deg)`;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    selects.forEach(select =&amp;gt; select.value = value);&lt;br /&gt;
    spawnLayers.forEach(spawnLayer =&amp;gt; spawnLayer.style.filter = filter);&lt;br /&gt;
&lt;br /&gt;
    localStorage.setItem(SPAWN_LAYER_COLOR, value);&lt;br /&gt;
}&lt;/div&gt;</summary>
		<author><name>Dexter</name></author>
		
	</entry>
	<entry>
		<id>https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Script/Calculator.js&amp;diff=105283</id>
		<title>MediaWiki:Script/Calculator.js</title>
		<link rel="alternate" type="text/html" href="https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Script/Calculator.js&amp;diff=105283"/>
		<updated>2024-11-27T20:18:39Z</updated>

		<summary type="html">&lt;p&gt;Dexter : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;function showElement(element) {&lt;br /&gt;
  element.classList.remove(&amp;quot;tabber-noactive&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function hideElement(element) {&lt;br /&gt;
  element.classList.add(&amp;quot;tabber-noactive&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function removeAccent(str) {&lt;br /&gt;
  return str.normalize(&amp;quot;NFD&amp;quot;).replace(/[\u0300-\u036f]/g, &amp;quot;&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function toNormalForm(str) {&lt;br /&gt;
  return removeAccent(str)&lt;br /&gt;
    .replace(&amp;quot;-&amp;quot;, &amp;quot; &amp;quot;)&lt;br /&gt;
    .replace(/[^a-zA-Z0-9 ]/g, &amp;quot;&amp;quot;)&lt;br /&gt;
    .toLowerCase();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function pseudoFormat(str) {&lt;br /&gt;
  return removeAccent(str).replace(/[^A-Za-z0-9 \(\)\+_-]+/g, &amp;quot;&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isValueInArray(value, array) {&lt;br /&gt;
  return array.indexOf(value) !== -1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function copyObject(object) {&lt;br /&gt;
  var copy = {};&lt;br /&gt;
  for (var key in object) {&lt;br /&gt;
    copy[key] = object[key];&lt;br /&gt;
  }&lt;br /&gt;
  return copy;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function compareNumbers(a, b) {&lt;br /&gt;
  return b - a;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isChecked(attribute) {&lt;br /&gt;
  return attribute === &amp;quot;on&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function floorMultiplication(firstFactor, secondFactor) {&lt;br /&gt;
  return Math.floor((firstFactor * secondFactor).toFixed(8));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function truncateNumber(number, precision) {&lt;br /&gt;
  return Math.floor(number * 10 ** precision) / 10 ** precision;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addKeyValue(object, key, value) {&lt;br /&gt;
  if (object.hasOwnProperty(key)) {&lt;br /&gt;
    object[key] += value;&lt;br /&gt;
  } else {&lt;br /&gt;
    object[key] = value;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function editTableResultRow(row, valuesToDisplay, numberFormat) {&lt;br /&gt;
  row.innerHTML = &amp;quot;&amp;quot;;&lt;br /&gt;
  for (var index = 0; index &amp;lt; valuesToDisplay.length; index++) {&lt;br /&gt;
    var cell = row.insertCell();&lt;br /&gt;
    var textContent;&lt;br /&gt;
&lt;br /&gt;
    if (index &amp;gt;= 3) {&lt;br /&gt;
      textContent = numberFormat.format(valuesToDisplay[index]);&lt;br /&gt;
    } else {&lt;br /&gt;
      textContent = valuesToDisplay[index];&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    cell.textContent = textContent;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return row;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addRowToTableResultHistory(&lt;br /&gt;
  tableResultHistory,&lt;br /&gt;
  valuesToDisplay,&lt;br /&gt;
  deleteFightTemplate,&lt;br /&gt;
  numberFormat&lt;br /&gt;
) {&lt;br /&gt;
  var row = tableResultHistory.insertRow();&lt;br /&gt;
  editTableResultRow(row, valuesToDisplay, numberFormat);&lt;br /&gt;
  var cell = row.insertCell();&lt;br /&gt;
  cell.appendChild(deleteFightTemplate.cloneNode(true));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcMeanDamages(damagesWeightedByType, totalCardinal) {&lt;br /&gt;
  var sumDamages = 0;&lt;br /&gt;
&lt;br /&gt;
  for (var damagesTypeName in damagesWeightedByType) {&lt;br /&gt;
    if (damagesTypeName === &amp;quot;miss&amp;quot;) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var damagesWeighted = damagesWeightedByType[damagesTypeName];&lt;br /&gt;
&lt;br /&gt;
    for (var damages in damagesWeighted) {&lt;br /&gt;
      sumDamages += damages * damagesWeighted[damages];&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return sumDamages / totalCardinal;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function prepareDamagesData(&lt;br /&gt;
  damagesWeightedByType,&lt;br /&gt;
  possibleDamagesCountTemp,&lt;br /&gt;
  totalCardinal&lt;br /&gt;
) {&lt;br /&gt;
  var minDamages = Infinity;&lt;br /&gt;
  var maxDamages = 0;&lt;br /&gt;
  var scatterDataByType = {};&lt;br /&gt;
  var sumDamages = 0;&lt;br /&gt;
  var possibleDamagesCount = 0;&lt;br /&gt;
  var uniqueDamagesCount = 0;&lt;br /&gt;
&lt;br /&gt;
  for (var damagesTypeName in damagesWeightedByType) {&lt;br /&gt;
    if (damagesTypeName === &amp;quot;miss&amp;quot;) {&lt;br /&gt;
      scatterDataByType.miss = damagesWeightedByType.miss;&lt;br /&gt;
      possibleDamagesCount++;&lt;br /&gt;
      uniqueDamagesCount++;&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var firstIteration = true;&lt;br /&gt;
    var damagesWeighted = damagesWeightedByType[damagesTypeName];&lt;br /&gt;
    var scatterData = [];&lt;br /&gt;
    scatterDataByType[damagesTypeName] = scatterData;&lt;br /&gt;
&lt;br /&gt;
    for (var damages in damagesWeighted) {&lt;br /&gt;
      damages = +damages;&lt;br /&gt;
&lt;br /&gt;
      if (firstIteration) {&lt;br /&gt;
        if (damages &amp;lt; minDamages) {&lt;br /&gt;
          minDamages = damages;&lt;br /&gt;
        }&lt;br /&gt;
        firstIteration = false;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      var weight = damagesWeighted[damages];&lt;br /&gt;
      var probability = weight / totalCardinal;&lt;br /&gt;
&lt;br /&gt;
      sumDamages += damages * weight;&lt;br /&gt;
      damagesWeighted[damages] = probability;&lt;br /&gt;
      scatterData.push({ x: damages, y: probability });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var scatterDataLength = scatterData.length;&lt;br /&gt;
&lt;br /&gt;
    possibleDamagesCount += possibleDamagesCountTemp;&lt;br /&gt;
    uniqueDamagesCount += scatterDataLength;&lt;br /&gt;
&lt;br /&gt;
    if (damages &amp;gt; maxDamages) {&lt;br /&gt;
      maxDamages = damages;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (minDamages === Infinity) {&lt;br /&gt;
    minDamages = 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return [&lt;br /&gt;
    sumDamages / totalCardinal,&lt;br /&gt;
    minDamages,&lt;br /&gt;
    maxDamages,&lt;br /&gt;
    scatterDataByType,&lt;br /&gt;
    possibleDamagesCount,&lt;br /&gt;
    uniqueDamagesCount,&lt;br /&gt;
  ];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function aggregateDamages(scatterData, maxPoints) {&lt;br /&gt;
  var dataLength = scatterData.length;&lt;br /&gt;
  var remainingData = dataLength;&lt;br /&gt;
  var aggregateScatterData = [];&lt;br /&gt;
&lt;br /&gt;
  for (var groupIndex = 0; groupIndex &amp;lt; maxPoints; groupIndex++) {&lt;br /&gt;
    var groupLength = Math.floor(remainingData / (maxPoints - groupIndex));&lt;br /&gt;
    var startIndex = dataLength - remainingData;&lt;br /&gt;
    var aggregateDamages = 0;&lt;br /&gt;
    var aggregateProbability = 0;&lt;br /&gt;
&lt;br /&gt;
    for (var index = startIndex; index &amp;lt; startIndex + groupLength; index++) {&lt;br /&gt;
      var { x: damages, y: probability } = scatterData[index];&lt;br /&gt;
      aggregateDamages += damages * probability;&lt;br /&gt;
      aggregateProbability += probability;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    aggregateScatterData.push({&lt;br /&gt;
      x: aggregateDamages / aggregateProbability,&lt;br /&gt;
      y: aggregateProbability,&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    remainingData -= groupLength;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return aggregateScatterData;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addToDamagesChart(&lt;br /&gt;
  scatterDataByType,&lt;br /&gt;
  damagesChart,&lt;br /&gt;
  isReducePointsChecked&lt;br /&gt;
) {&lt;br /&gt;
  var { chart, datasetsStyle, maxPoints, reduceChartPointsContainer } =&lt;br /&gt;
    damagesChart;&lt;br /&gt;
  var isFirstDataset = true;&lt;br /&gt;
  var datasets = chart.data.datasets;&lt;br /&gt;
&lt;br /&gt;
  datasets.length = 0;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; datasetsStyle.length; index++) {&lt;br /&gt;
    var dataset = copyObject(datasetsStyle[index]);&lt;br /&gt;
&lt;br /&gt;
    if (!scatterDataByType.hasOwnProperty(dataset.name)) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var scatterData = scatterDataByType[dataset.name];&lt;br /&gt;
    var canBeReduced = scatterData.length &amp;gt; 2 * maxPoints;&lt;br /&gt;
&lt;br /&gt;
    dataset.hidden = !isFirstDataset;&lt;br /&gt;
    dataset.canBeReduced = canBeReduced;&lt;br /&gt;
&lt;br /&gt;
    if (canBeReduced &amp;amp;&amp;amp; isReducePointsChecked) {&lt;br /&gt;
      dataset.data = aggregateDamages(scatterData, maxPoints);&lt;br /&gt;
    } else {&lt;br /&gt;
      dataset.data = scatterData;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isFirstDataset) {&lt;br /&gt;
      isFirstDataset = false;&lt;br /&gt;
&lt;br /&gt;
      if (canBeReduced) {&lt;br /&gt;
        showElement(reduceChartPointsContainer);&lt;br /&gt;
&lt;br /&gt;
        if (!isReducePointsChecked) {&lt;br /&gt;
          handleChartAnimations(chart, false);&lt;br /&gt;
        }&lt;br /&gt;
      } else {&lt;br /&gt;
        hideElement(reduceChartPointsContainer);&lt;br /&gt;
        handleChartAnimations(chart, true);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    datasets.push(dataset);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  chart.data.missPercentage = scatterDataByType.miss;&lt;br /&gt;
  chart.update();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addToBonusVariationChart(&lt;br /&gt;
  damagesByBonus,&lt;br /&gt;
  augmentationByBonus,&lt;br /&gt;
  xLabel,&lt;br /&gt;
  chart&lt;br /&gt;
) {&lt;br /&gt;
  chart.data.datasets[0].data = damagesByBonus;&lt;br /&gt;
  chart.data.datasets[1].data = augmentationByBonus;&lt;br /&gt;
  chart.options.scales.x.title.text = xLabel;&lt;br /&gt;
  chart.update();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleChartAnimations(chart, addAnimations) {&lt;br /&gt;
  chart.options.animation = addAnimations;&lt;br /&gt;
  chart.options.animations.colors = addAnimations;&lt;br /&gt;
  chart.options.animations.x = addAnimations;&lt;br /&gt;
  chart.options.transitions.active.animation.duration = addAnimations * 1000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateDamagesChartDescription(&lt;br /&gt;
  uniqueDamagesCounters,&lt;br /&gt;
  uniqueDamagesCount,&lt;br /&gt;
  formatNumber&lt;br /&gt;
) {&lt;br /&gt;
  uniqueDamagesCounters.forEach(function (element) {&lt;br /&gt;
    if (uniqueDamagesCount &amp;lt;= 1) {&lt;br /&gt;
      hideElement(element.parentElement);&lt;br /&gt;
    } else {&lt;br /&gt;
      showElement(element.parentElement);&lt;br /&gt;
      element.textContent = formatNumber.format(uniqueDamagesCount);&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getMonsterName(monsterVnum) {&lt;br /&gt;
  var monsterAttributes = monsterData[monsterVnum];&lt;br /&gt;
  return monsterAttributes[monsterAttributes.length - 1];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterClass(selectedRace, classChoice, selectValueIsChanged = false) {&lt;br /&gt;
  showElement(classChoice.parentElement);&lt;br /&gt;
&lt;br /&gt;
  for (var option of classChoice.options) {&lt;br /&gt;
    if (option.getAttribute(&amp;quot;data-race&amp;quot;) === selectedRace) {&lt;br /&gt;
      if (!selectValueIsChanged) {&lt;br /&gt;
        classChoice.value = option.value;&lt;br /&gt;
        selectValueIsChanged = true;&lt;br /&gt;
      }&lt;br /&gt;
      showElement(option);&lt;br /&gt;
    } else {&lt;br /&gt;
      hideElement(option);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  if (selectedRace == &amp;quot;lycan&amp;quot;) {&lt;br /&gt;
    hideElement(classChoice.parentElement);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterWeapon(&lt;br /&gt;
  selectedRace,&lt;br /&gt;
  weaponElement,&lt;br /&gt;
  weaponCategory,&lt;br /&gt;
  allowedWeaponsPerRace,&lt;br /&gt;
  selectValueIsChanged = false&lt;br /&gt;
) {&lt;br /&gt;
  var allowedWeapons = allowedWeaponsPerRace[selectedRace];&lt;br /&gt;
&lt;br /&gt;
  if (!selectValueIsChanged) {&lt;br /&gt;
    var weaponType = weaponData[weaponElement.value][1];&lt;br /&gt;
&lt;br /&gt;
    if (!isValueInArray(weaponType, allowedWeapons)) {&lt;br /&gt;
      weaponElement.value = 0;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var children = weaponCategory.children;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; children.length; index++) {&lt;br /&gt;
    var child = children[index];&lt;br /&gt;
&lt;br /&gt;
    if (isValueInArray(index, allowedWeapons)) {&lt;br /&gt;
      showElement(child);&lt;br /&gt;
    } else {&lt;br /&gt;
      hideElement(child);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSelectedWeapon(weaponCategory) {&lt;br /&gt;
  return weaponCategory.querySelector(&amp;quot;input[type='radio']:checked&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleWeaponDisplay(weaponDisplay, newWeapon, weaponVnum) {&lt;br /&gt;
  var newImage = newWeapon.nextElementSibling.cloneNode();&lt;br /&gt;
  var newText = document.createElement(&amp;quot;span&amp;quot;);&lt;br /&gt;
  var oldImage = weaponDisplay.firstChild;&lt;br /&gt;
  var oldText = oldImage.nextElementSibling;&lt;br /&gt;
  var weaponName = createWeapon(weaponVnum).name;&lt;br /&gt;
&lt;br /&gt;
  if (weaponVnum == 0) {&lt;br /&gt;
    newText.textContent = &amp;quot; &amp;quot; + weaponName + &amp;quot; &amp;quot;;&lt;br /&gt;
  } else {&lt;br /&gt;
    var weaponLink = document.createElement(&amp;quot;a&amp;quot;);&lt;br /&gt;
    weaponLink.href = mw.util.getUrl(weaponName);&lt;br /&gt;
    weaponLink.title = weaponName;&lt;br /&gt;
    weaponLink.textContent = weaponName;&lt;br /&gt;
&lt;br /&gt;
    newText.appendChild(document.createTextNode(&amp;quot; &amp;quot;));&lt;br /&gt;
    newText.appendChild(weaponLink);&lt;br /&gt;
    newText.appendChild(document.createTextNode(&amp;quot; &amp;quot;));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  weaponDisplay.replaceChild(newImage, oldImage);&lt;br /&gt;
  weaponDisplay.replaceChild(newText, oldText);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterUpgrade(&lt;br /&gt;
  selectedRace,&lt;br /&gt;
  weaponUpgrade,&lt;br /&gt;
  weaponVnum,&lt;br /&gt;
  randomAttackValue,&lt;br /&gt;
  randomMagicAttackValue,&lt;br /&gt;
  currentUpgrade&lt;br /&gt;
) {&lt;br /&gt;
  var weapon = createWeapon(weaponVnum);&lt;br /&gt;
&lt;br /&gt;
  if (weapon.isSerpent) {&lt;br /&gt;
    showElement(randomAttackValue);&lt;br /&gt;
&lt;br /&gt;
    if (selectedRace === &amp;quot;sura&amp;quot; || selectedRace === &amp;quot;shaman&amp;quot;) {&lt;br /&gt;
      showElement(randomMagicAttackValue);&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    hideElement(randomAttackValue);&lt;br /&gt;
    hideElement(randomMagicAttackValue);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var upgradeNumber = weapon.upgrades.length;&lt;br /&gt;
&lt;br /&gt;
  if (upgradeNumber &amp;lt;= 1) {&lt;br /&gt;
    hideElement(weaponUpgrade.parentElement);&lt;br /&gt;
  } else {&lt;br /&gt;
    showElement(weaponUpgrade.parentElement);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  weaponUpgrade.innerHTML = &amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  for (var upgrade = 0; upgrade &amp;lt; upgradeNumber; upgrade++) {&lt;br /&gt;
    var option = document.createElement(&amp;quot;option&amp;quot;);&lt;br /&gt;
    option.value = upgrade;&lt;br /&gt;
    option.textContent = &amp;quot;+&amp;quot; + upgrade;&lt;br /&gt;
    weaponUpgrade.appendChild(option);&lt;br /&gt;
  }&lt;br /&gt;
  if (currentUpgrade === undefined) {&lt;br /&gt;
    option.selected = true;&lt;br /&gt;
  } else {&lt;br /&gt;
    weaponUpgrade.value = currentUpgrade;&lt;br /&gt;
    currentUpgrade = undefined;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterState(selectedState, polymorphMonster) {&lt;br /&gt;
  if (selectedState === &amp;quot;polymorph&amp;quot;) {&lt;br /&gt;
    showElement(polymorphMonster.parentElement);&lt;br /&gt;
  } else {&lt;br /&gt;
    hideElement(polymorphMonster.parentElement);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterCheckbox(checkbox, element) {&lt;br /&gt;
  if (checkbox.checked) {&lt;br /&gt;
    showElement(element);&lt;br /&gt;
  } else {&lt;br /&gt;
    hideElement(element);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterSkills(selectedClass, skillElementsToFilter) {&lt;br /&gt;
  for (var element of skillElementsToFilter) {&lt;br /&gt;
    if (isValueInArray(selectedClass, element.dataset.class)) {&lt;br /&gt;
      showElement(element);&lt;br /&gt;
    } else {&lt;br /&gt;
      hideElement(element);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterAttackTypeSelection(attacker, attackTypeSelection) {&lt;br /&gt;
  var attackerClass = attacker.class;&lt;br /&gt;
  var selectedOption =&lt;br /&gt;
    attackTypeSelection.options[attackTypeSelection.selectedIndex];&lt;br /&gt;
  var attackerIsNotPolymorph = !isPolymorph(attacker);&lt;br /&gt;
&lt;br /&gt;
  for (var index = 2; index &amp;lt; attackTypeSelection.options.length; index++) {&lt;br /&gt;
    var option = attackTypeSelection.options[index];&lt;br /&gt;
    var optionClass = option.dataset.class;&lt;br /&gt;
    var optionValue = option.value;&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      attackerIsNotPolymorph &amp;amp;&amp;amp;&lt;br /&gt;
      attacker[optionValue] &amp;amp;&amp;amp;&lt;br /&gt;
      (attackerClass === optionClass ||&lt;br /&gt;
        (optionValue.startsWith(&amp;quot;horseSkill&amp;quot;) &amp;amp;&amp;amp;&lt;br /&gt;
          isRiding(attacker) &amp;amp;&amp;amp;&lt;br /&gt;
          (!optionClass || isValueInArray(attackerClass, optionClass))))&lt;br /&gt;
    ) {&lt;br /&gt;
      showElement(option);&lt;br /&gt;
    } else {&lt;br /&gt;
      hideElement(option);&lt;br /&gt;
&lt;br /&gt;
      if (selectedOption === option) {&lt;br /&gt;
        attackTypeSelection.selectedIndex = 0;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterAttackTypeSelectionMonster(attackTypeSelection) {&lt;br /&gt;
  for (var index = 2; index &amp;lt; attackTypeSelection.options.length; index++) {&lt;br /&gt;
    hideElement(attackTypeSelection.options[index]);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (attackTypeSelection.selectedIndex !== 1) {&lt;br /&gt;
    attackTypeSelection.selectedIndex = 0;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterForm(characters, battle) {&lt;br /&gt;
  var characterCreation = characters.characterCreation;&lt;br /&gt;
  var allowedWeaponsPerRace = battle.constants.allowedWeaponsPerRace;&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;change&amp;quot;, function (event) {&lt;br /&gt;
    var target = event.target;&lt;br /&gt;
    var targetName = target.name;&lt;br /&gt;
&lt;br /&gt;
    switch (targetName) {&lt;br /&gt;
      case &amp;quot;race&amp;quot;:&lt;br /&gt;
        var selectedRace = target.value;&lt;br /&gt;
        var classChoice = characterCreation.class;&lt;br /&gt;
        var weaponElement = characterCreation.weapon;&lt;br /&gt;
&lt;br /&gt;
        filterClass(selectedRace, classChoice);&lt;br /&gt;
        filterWeapon(&lt;br /&gt;
          selectedRace,&lt;br /&gt;
          weaponElement,&lt;br /&gt;
          characters.weaponCategory,&lt;br /&gt;
          allowedWeaponsPerRace&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        var newWeapon = getSelectedWeapon(characters.weaponCategory);&lt;br /&gt;
        handleWeaponDisplay(&lt;br /&gt;
          characters.weaponDisplay,&lt;br /&gt;
          newWeapon,&lt;br /&gt;
          weaponElement.value&lt;br /&gt;
        );&lt;br /&gt;
        filterUpgrade(&lt;br /&gt;
          selectedRace,&lt;br /&gt;
          characterCreation.weaponUpgrade,&lt;br /&gt;
          weaponElement.value,&lt;br /&gt;
          characters.randomAttackValue,&lt;br /&gt;
          characters.randomMagicAttackValue&lt;br /&gt;
        );&lt;br /&gt;
        filterSkills(classChoice.value, characters.skillElementsToFilter);&lt;br /&gt;
&lt;br /&gt;
        if (characterCreation.name.value === battle.attackerSelection.value) {&lt;br /&gt;
          battle.resetAttackType = true;&lt;br /&gt;
        }&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;class&amp;quot;:&lt;br /&gt;
        filterSkills(target.value, characters.skillElementsToFilter);&lt;br /&gt;
&lt;br /&gt;
        if (characterCreation.name.value === battle.attackerSelection.value) {&lt;br /&gt;
          battle.resetAttackType = true;&lt;br /&gt;
        }&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;weapon&amp;quot;:&lt;br /&gt;
        handleWeaponDisplay(&lt;br /&gt;
          characters.weaponDisplay,&lt;br /&gt;
          target,&lt;br /&gt;
          characterCreation.weapon.value&lt;br /&gt;
        );&lt;br /&gt;
        filterUpgrade(&lt;br /&gt;
          characterCreation.race.value,&lt;br /&gt;
          characterCreation.weaponUpgrade,&lt;br /&gt;
          target.value,&lt;br /&gt;
          characters.randomAttackValue,&lt;br /&gt;
          characters.randomMagicAttackValue&lt;br /&gt;
        );&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;state&amp;quot;:&lt;br /&gt;
        filterState(target.value, characterCreation.polymorphMonster);&lt;br /&gt;
        if (characterCreation.name.value === battle.attackerSelection.value) {&lt;br /&gt;
          battle.resetAttackType = true;&lt;br /&gt;
        }&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;lowRank&amp;quot;:&lt;br /&gt;
        filterCheckbox(target, characterCreation.playerRank.parentElement);&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;isBlessed&amp;quot;:&lt;br /&gt;
        filterCheckbox(target, characters.blessingCreation);&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;onYohara&amp;quot;:&lt;br /&gt;
        filterCheckbox(target, characters.yoharaCreation);&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;isMarried&amp;quot;:&lt;br /&gt;
        filterCheckbox(target, characters.marriageCreation);&lt;br /&gt;
        break;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      targetName.startsWith(&amp;quot;attackSkill&amp;quot;) ||&lt;br /&gt;
      targetName.startsWith(&amp;quot;horseSkill&amp;quot;)&lt;br /&gt;
    ) {&lt;br /&gt;
      battle.resetAttackType = true;&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addUniquePseudo(characterDataObject, savedCharactersPseudo) {&lt;br /&gt;
  var characterPseudo = String(characterDataObject.name);&lt;br /&gt;
  var originalPseudo = characterPseudo;&lt;br /&gt;
  var count = 0;&lt;br /&gt;
&lt;br /&gt;
  var regex = /(.*)(\d)$/;&lt;br /&gt;
  var match = characterPseudo.match(regex);&lt;br /&gt;
&lt;br /&gt;
  if (match) {&lt;br /&gt;
    originalPseudo = match[1];&lt;br /&gt;
    count = match[2];&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  while (isValueInArray(characterPseudo, savedCharactersPseudo)) {&lt;br /&gt;
    characterPseudo = originalPseudo + count;&lt;br /&gt;
    count++;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  characterDataObject.name = characterPseudo;&lt;br /&gt;
  return [characterDataObject, characterPseudo];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function convertToNumber(value) {&lt;br /&gt;
  var valueNumber = Number(value);&lt;br /&gt;
  return isNaN(valueNumber) ? value : valueNumber;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getLocalStorageValue(key, defaultValue) {&lt;br /&gt;
  var storedValue = localStorage.getItem(key);&lt;br /&gt;
&lt;br /&gt;
  if (storedValue) {&lt;br /&gt;
    return JSON.parse(storedValue);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return defaultValue;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSavedCharacters() {&lt;br /&gt;
  return getLocalStorageValue(&amp;quot;savedCharactersCalculator&amp;quot;, {});&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSavedMonsters() {&lt;br /&gt;
  return getLocalStorageValue(&amp;quot;savedMonstersCalculator&amp;quot;, []).filter(function (&lt;br /&gt;
    num&lt;br /&gt;
  ) {&lt;br /&gt;
    return !isNaN(Number(num));&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSavedFights() {&lt;br /&gt;
  return getLocalStorageValue(&amp;quot;savedFightsCalculator&amp;quot;, []);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveToLocalStorage(key, value) {&lt;br /&gt;
  localStorage.setItem(key, JSON.stringify(value));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateSavedCharacters(savedCharacters) {&lt;br /&gt;
  saveToLocalStorage(&amp;quot;savedCharactersCalculator&amp;quot;, savedCharacters);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateSavedMonsters(savedMonsters) {&lt;br /&gt;
  saveToLocalStorage(&amp;quot;savedMonstersCalculator&amp;quot;, savedMonsters);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateSavedFights(savedFights) {&lt;br /&gt;
  saveToLocalStorage(&amp;quot;savedFightsCalculator&amp;quot;, savedFights);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveCharacter(&lt;br /&gt;
  savedCharacters,&lt;br /&gt;
  characterCreation,&lt;br /&gt;
  battle,&lt;br /&gt;
  newCharacter,&lt;br /&gt;
  characterDataObject&lt;br /&gt;
) {&lt;br /&gt;
  if (!characterDataObject) {&lt;br /&gt;
    var characterData = new FormData(characterCreation);&lt;br /&gt;
    var characterDataObject = {};&lt;br /&gt;
&lt;br /&gt;
    characterData.forEach(function (value, key) {&lt;br /&gt;
      characterDataObject[key] = convertToNumber(value);&lt;br /&gt;
    });&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  savedCharacters[characterDataObject.name] = characterDataObject;&lt;br /&gt;
  updateSavedCharacters(savedCharacters);&lt;br /&gt;
&lt;br /&gt;
  if (newCharacter) {&lt;br /&gt;
    addBattleChoice(battle, characterDataObject.name);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (battle.resetAttackType) {&lt;br /&gt;
    filterAttackTypeSelection(characterDataObject, battle.attackTypeSelection);&lt;br /&gt;
    battle.resetAttackType = false;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveButtonGreen(saveButton) {&lt;br /&gt;
  saveButton.classList.remove(&amp;quot;unsaved-character&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveButtonOrange(saveButton) {&lt;br /&gt;
  saveButton.classList.add(&amp;quot;unsaved-character&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function characterCreationListener(characters, battle) {&lt;br /&gt;
  var { characterCreation, saveButton, weaponCategory } = characters;&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;submit&amp;quot;, function (event) {&lt;br /&gt;
    event.preventDefault();&lt;br /&gt;
&lt;br /&gt;
    if (characters.unsavedChanges) {&lt;br /&gt;
      saveCharacter(characters.savedCharacters, characterCreation, battle);&lt;br /&gt;
      saveButtonGreen(saveButton);&lt;br /&gt;
      characters.unsavedChanges = false;&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  document.addEventListener(&amp;quot;keydown&amp;quot;, function (event) {&lt;br /&gt;
    if (event.ctrlKey &amp;amp;&amp;amp; event.key === &amp;quot;s&amp;quot;) {&lt;br /&gt;
      event.preventDefault();&lt;br /&gt;
      saveButton.click();&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  weaponCategory.addEventListener(&amp;quot;mouseover&amp;quot;, function (event) {&lt;br /&gt;
    label = event.target.closest(&amp;quot;label&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (label) {&lt;br /&gt;
      var tooltip = label.lastChild;&lt;br /&gt;
&lt;br /&gt;
      if (tooltip.classList.contains(&amp;quot;popContenu&amp;quot;)) {&lt;br /&gt;
        var tooltipRect = tooltip.getBoundingClientRect();&lt;br /&gt;
        var modalRect = weaponCategory.getBoundingClientRect();&lt;br /&gt;
&lt;br /&gt;
        if (tooltipRect.right &amp;gt; modalRect.right) {&lt;br /&gt;
          tooltip.style.left = &amp;quot;-100%&amp;quot;;&lt;br /&gt;
        } else if (tooltipRect.left &amp;lt; modalRect.left) {&lt;br /&gt;
          tooltip.style.left = &amp;quot;200%&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function downloadData(content, type, filename) {&lt;br /&gt;
  var link = document.createElement(&amp;quot;a&amp;quot;);&lt;br /&gt;
  var blob = new Blob([content], { type: type });&lt;br /&gt;
  var blobURL = URL.createObjectURL(blob);&lt;br /&gt;
&lt;br /&gt;
  link.href = blobURL;&lt;br /&gt;
  link.download = filename;&lt;br /&gt;
  document.body.appendChild(link);&lt;br /&gt;
&lt;br /&gt;
  link.click();&lt;br /&gt;
  document.body.removeChild(link);&lt;br /&gt;
  URL.revokeObjectURL(blobURL);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function uploadCharacter(&lt;br /&gt;
  selectedFiles,&lt;br /&gt;
  characters,&lt;br /&gt;
  characterTemplate,&lt;br /&gt;
  charactersContainer,&lt;br /&gt;
  battle&lt;br /&gt;
) {&lt;br /&gt;
  var selectFilesLength = selectedFiles.length;&lt;br /&gt;
&lt;br /&gt;
  for (var fileIndex = 0; fileIndex &amp;lt; selectFilesLength; fileIndex++) {&lt;br /&gt;
    var selectedFile = selectedFiles[fileIndex];&lt;br /&gt;
&lt;br /&gt;
    if (selectedFile.type === &amp;quot;text/plain&amp;quot;) {&lt;br /&gt;
      var reader = new FileReader();&lt;br /&gt;
      reader.onload = function (e) {&lt;br /&gt;
        var fileContent = e.target.result;&lt;br /&gt;
        try {&lt;br /&gt;
          var characterDataObject = JSON.parse(fileContent);&lt;br /&gt;
&lt;br /&gt;
          if (characterDataObject.hasOwnProperty(&amp;quot;name&amp;quot;)) {&lt;br /&gt;
            var characterPseudo = String(characterDataObject.name);&lt;br /&gt;
&lt;br /&gt;
            hideElement(characters.characterCreation);&lt;br /&gt;
            characterPseudo = validPseudo(characterPseudo);&lt;br /&gt;
&lt;br /&gt;
            [characterDataObject, characterPseudo] = addUniquePseudo(&lt;br /&gt;
              characterDataObject,&lt;br /&gt;
              Object.keys(characters.savedCharacters)&lt;br /&gt;
            );&lt;br /&gt;
            var selectedCharacter = handleNewCharacter(&lt;br /&gt;
              characters,&lt;br /&gt;
              characterTemplate,&lt;br /&gt;
              charactersContainer,&lt;br /&gt;
              battle,&lt;br /&gt;
              characterPseudo&lt;br /&gt;
            )[0];&lt;br /&gt;
&lt;br /&gt;
            if (selectFilesLength === 1) {&lt;br /&gt;
              updateForm(&lt;br /&gt;
                characterDataObject,&lt;br /&gt;
                characters.characterCreation,&lt;br /&gt;
                characters,&lt;br /&gt;
                selectedCharacter,&lt;br /&gt;
                battle&lt;br /&gt;
              );&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            saveCharacter(&lt;br /&gt;
              characters.savedCharacters,&lt;br /&gt;
              characters.characterCreation,&lt;br /&gt;
              battle,&lt;br /&gt;
              true,&lt;br /&gt;
              characterDataObject&lt;br /&gt;
            );&lt;br /&gt;
          }&lt;br /&gt;
        } catch (error) {&lt;br /&gt;
          console.log(error);&lt;br /&gt;
          if (error.name === &amp;quot;TypeError&amp;quot;) {&lt;br /&gt;
            // delete the character&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
      };&lt;br /&gt;
      reader.readAsText(selectedFile);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleUploadCharacter(&lt;br /&gt;
  characters,&lt;br /&gt;
  characterTemplate,&lt;br /&gt;
  charactersContainer,&lt;br /&gt;
  battle&lt;br /&gt;
) {&lt;br /&gt;
  var characterInput = characters.characterInput;&lt;br /&gt;
  var dropZone = characters.dropZone;&lt;br /&gt;
&lt;br /&gt;
  characterInput.accept = &amp;quot;.txt&amp;quot;;&lt;br /&gt;
  characterInput.multiple = true;&lt;br /&gt;
  dropZone.setAttribute(&amp;quot;tabindex&amp;quot;, &amp;quot;0&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  dropZone.addEventListener(&amp;quot;click&amp;quot;, function () {&lt;br /&gt;
    characterInput.click();&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  dropZone.addEventListener(&amp;quot;dragover&amp;quot;, function (event) {&lt;br /&gt;
    event.preventDefault();&lt;br /&gt;
    dropZone.classList.add(&amp;quot;drop-zone--dragover&amp;quot;);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  [&amp;quot;dragleave&amp;quot;, &amp;quot;dragend&amp;quot;].forEach(function (type) {&lt;br /&gt;
    dropZone.addEventListener(type, function () {&lt;br /&gt;
      dropZone.classList.remove(&amp;quot;drop-zone--dragover&amp;quot;);&lt;br /&gt;
    });&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  dropZone.addEventListener(&amp;quot;drop&amp;quot;, function (event) {&lt;br /&gt;
    event.preventDefault();&lt;br /&gt;
    uploadCharacter(&lt;br /&gt;
      event.dataTransfer.files,&lt;br /&gt;
      characters,&lt;br /&gt;
      characterTemplate,&lt;br /&gt;
      charactersContainer,&lt;br /&gt;
      battle&lt;br /&gt;
    );&lt;br /&gt;
    dropZone.classList.remove(&amp;quot;drop-zone--dragover&amp;quot;);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  characterInput.addEventListener(&amp;quot;change&amp;quot;, function (event) {&lt;br /&gt;
    uploadCharacter(&lt;br /&gt;
      event.target.files,&lt;br /&gt;
      characters,&lt;br /&gt;
      characterTemplate,&lt;br /&gt;
      charactersContainer,&lt;br /&gt;
      battle&lt;br /&gt;
    );&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function deleteCharacter(characters, pseudo, element, battle) {&lt;br /&gt;
  battle.battleForm.reset();&lt;br /&gt;
  delete characters.savedCharacters[pseudo];&lt;br /&gt;
  element.remove();&lt;br /&gt;
&lt;br /&gt;
  updateSavedCharacters(characters.savedCharacters);&lt;br /&gt;
  removeBattleChoice(battle, pseudo);&lt;br /&gt;
&lt;br /&gt;
  if (&lt;br /&gt;
    !Object.keys(characters.savedCharacters).length ||&lt;br /&gt;
    characters.characterCreation.name.value === pseudo&lt;br /&gt;
  ) {&lt;br /&gt;
    saveButtonGreen(characters.saveButton);&lt;br /&gt;
    characters.unsavedChanges = false;&lt;br /&gt;
    hideElement(characters.characterCreation);&lt;br /&gt;
    showElement(characters.characterCreation.previousElementSibling);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function deleteMonster(characters, monsterVnum, element, battle) {&lt;br /&gt;
  battle.battleForm.reset();&lt;br /&gt;
  characters.savedMonsters.splice(&lt;br /&gt;
    characters.savedMonsters.indexOf(monsterVnum),&lt;br /&gt;
    1&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  if (element) {&lt;br /&gt;
    element.remove();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  updateSavedMonsters(characters.savedMonsters);&lt;br /&gt;
  removeBattleChoice(battle, monsterVnum);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleStyle(characters, selectedElement) {&lt;br /&gt;
  var currentCharacter = characters.currentCharacter;&lt;br /&gt;
&lt;br /&gt;
  if (currentCharacter) {&lt;br /&gt;
    currentCharacter.classList.remove(&amp;quot;selected-character&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  selectedElement.classList.add(&amp;quot;selected-character&amp;quot;);&lt;br /&gt;
  characters.currentCharacter = selectedElement;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateForm(&lt;br /&gt;
  formData,&lt;br /&gt;
  characterCreation,&lt;br /&gt;
  characters,&lt;br /&gt;
  selectedElement,&lt;br /&gt;
  battle&lt;br /&gt;
) {&lt;br /&gt;
  saveButtonGreen(characters.saveButton);&lt;br /&gt;
  hideElement(characterCreation.previousElementSibling);&lt;br /&gt;
  showElement(characterCreation);&lt;br /&gt;
  handleStyle(characters, selectedElement);&lt;br /&gt;
&lt;br /&gt;
  characterCreation.reset();&lt;br /&gt;
&lt;br /&gt;
  for (var [name, value] of Object.entries(formData)) {&lt;br /&gt;
    var formElement = characterCreation[name];&lt;br /&gt;
&lt;br /&gt;
    if (!formElement) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (formElement.type === &amp;quot;checkbox&amp;quot;) {&lt;br /&gt;
      if (isChecked(value)) {&lt;br /&gt;
        formElement.checked = true;&lt;br /&gt;
      }&lt;br /&gt;
    } else {&lt;br /&gt;
      formElement.value = value;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  var selectedRace = characterCreation.race.value;&lt;br /&gt;
  var classChoice = characterCreation.class;&lt;br /&gt;
  var weaponElement = characterCreation.weapon;&lt;br /&gt;
&lt;br /&gt;
  filterClass(selectedRace, classChoice, true);&lt;br /&gt;
  filterWeapon(&lt;br /&gt;
    selectedRace,&lt;br /&gt;
    weaponElement,&lt;br /&gt;
    characters.weaponCategory,&lt;br /&gt;
    battle.constants.allowedWeaponsPerRace,&lt;br /&gt;
    true&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  var newWeapon = getSelectedWeapon(characters.weaponCategory);&lt;br /&gt;
&lt;br /&gt;
  handleWeaponDisplay(characters.weaponDisplay, newWeapon, weaponElement.value);&lt;br /&gt;
  filterUpgrade(&lt;br /&gt;
    selectedRace,&lt;br /&gt;
    characterCreation.weaponUpgrade,&lt;br /&gt;
    weaponElement.value,&lt;br /&gt;
    characters.randomAttackValue,&lt;br /&gt;
    characters.randomMagicAttackValue,&lt;br /&gt;
    formData.weaponUpgrade&lt;br /&gt;
  );&lt;br /&gt;
  filterState(&lt;br /&gt;
    characterCreation.state.value,&lt;br /&gt;
    characterCreation.polymorphMonster&lt;br /&gt;
  );&lt;br /&gt;
  filterCheckbox(&lt;br /&gt;
    characterCreation.lowRank,&lt;br /&gt;
    characterCreation.playerRank.parentElement&lt;br /&gt;
  );&lt;br /&gt;
  filterCheckbox(characterCreation.onYohara, characters.yoharaCreation);&lt;br /&gt;
  filterCheckbox(characterCreation.isBlessed, characters.blessingCreation);&lt;br /&gt;
  filterCheckbox(characterCreation.isMarried, characters.marriageCreation);&lt;br /&gt;
  filterSkills(classChoice.value, characters.skillElementsToFilter);&lt;br /&gt;
  handleBonusVariationUpdate(characterCreation, characters.bonusVariation);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleClickOnCharacter(&lt;br /&gt;
  spanInput,&lt;br /&gt;
  target,&lt;br /&gt;
  characters,&lt;br /&gt;
  characterElement,&lt;br /&gt;
  battle,&lt;br /&gt;
  edition&lt;br /&gt;
) {&lt;br /&gt;
  var displayedPseudo = characters.characterCreation.name.value;&lt;br /&gt;
  var pseudo = spanInput.dataset.name;&lt;br /&gt;
&lt;br /&gt;
  if (edition) {&lt;br /&gt;
    if (!characters.unsavedChanges) {&lt;br /&gt;
      updateForm(&lt;br /&gt;
        characters.savedCharacters[pseudo],&lt;br /&gt;
        characters.characterCreation,&lt;br /&gt;
        characters,&lt;br /&gt;
        characterElement,&lt;br /&gt;
        battle&lt;br /&gt;
      );&lt;br /&gt;
    } else if (displayedPseudo === pseudo) {&lt;br /&gt;
      // pass&lt;br /&gt;
    } else {&lt;br /&gt;
      var result = confirm(&lt;br /&gt;
        &amp;quot;Voulez-vous continuer ? Les dernières modifications ne seront pas sauvegardées.&amp;quot;&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      if (result) {&lt;br /&gt;
        updateForm(&lt;br /&gt;
          characters.savedCharacters[pseudo],&lt;br /&gt;
          characters.characterCreation,&lt;br /&gt;
          characters,&lt;br /&gt;
          characterElement,&lt;br /&gt;
          battle&lt;br /&gt;
        );&lt;br /&gt;
        characters.unsavedChanges = false;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    if (target.tagName === &amp;quot;path&amp;quot;) {&lt;br /&gt;
      target = target.parentElement;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    switch (target.dataset.icon) {&lt;br /&gt;
      case &amp;quot;duplicate&amp;quot;:&lt;br /&gt;
        if (!characters.unsavedChanges) {&lt;br /&gt;
          addNewCharacter(&lt;br /&gt;
            characters,&lt;br /&gt;
            characters.newCharacterTemplate,&lt;br /&gt;
            characters.charactersContainer,&lt;br /&gt;
            battle,&lt;br /&gt;
            pseudo&lt;br /&gt;
          );&lt;br /&gt;
        } else {&lt;br /&gt;
          var result = confirm(&lt;br /&gt;
            &amp;quot;Voulez-vous continuer ? Les dernières modifications ne seront pas sauvegardées.&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
&lt;br /&gt;
          if (result) {&lt;br /&gt;
            addNewCharacter(&lt;br /&gt;
              characters,&lt;br /&gt;
              characters.newCharacterTemplate,&lt;br /&gt;
              characters.charactersContainer,&lt;br /&gt;
              battle,&lt;br /&gt;
              pseudo&lt;br /&gt;
            );&lt;br /&gt;
            saveButtonGreen(characters.saveButton);&lt;br /&gt;
            characters.unsavedChanges = false;&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
        break;&lt;br /&gt;
&lt;br /&gt;
      case &amp;quot;download&amp;quot;:&lt;br /&gt;
        var character = characters.savedCharacters[pseudo];&lt;br /&gt;
        downloadData(&lt;br /&gt;
          JSON.stringify(character),&lt;br /&gt;
          &amp;quot;text/plain&amp;quot;,&lt;br /&gt;
          character.name + &amp;quot;.txt&amp;quot;&lt;br /&gt;
        );&lt;br /&gt;
        break;&lt;br /&gt;
&lt;br /&gt;
      case &amp;quot;delete&amp;quot;:&lt;br /&gt;
        var result = confirm(&lt;br /&gt;
          &amp;quot;Voulez-vous vraiment supprimer définitivement le personnage &amp;quot; +&lt;br /&gt;
            pseudo +&lt;br /&gt;
            &amp;quot; ?&amp;quot;&lt;br /&gt;
        );&lt;br /&gt;
        if (result) {&lt;br /&gt;
          deleteCharacter(characters, pseudo, characterElement, battle);&lt;br /&gt;
        }&lt;br /&gt;
        break;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleNewCharacter(&lt;br /&gt;
  characters,&lt;br /&gt;
  characterTemplate,&lt;br /&gt;
  charactersContainer,&lt;br /&gt;
  battle,&lt;br /&gt;
  pseudo&lt;br /&gt;
) {&lt;br /&gt;
  var newCharacterTemplate = characterTemplate.cloneNode(true);&lt;br /&gt;
  var spanInput = newCharacterTemplate.querySelector(&amp;quot;span.input&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  newCharacterTemplate.setAttribute(&amp;quot;tabindex&amp;quot;, &amp;quot;0&amp;quot;);&lt;br /&gt;
  charactersContainer.appendChild(newCharacterTemplate);&lt;br /&gt;
&lt;br /&gt;
  if (pseudo) {&lt;br /&gt;
    spanInput.textContent = pseudo;&lt;br /&gt;
    spanInput.setAttribute(&amp;quot;data-name&amp;quot;, pseudo);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  newCharacterTemplate.addEventListener(&amp;quot;click&amp;quot;, function (event) {&lt;br /&gt;
    var target = event.target;&lt;br /&gt;
&lt;br /&gt;
    if (target.tagName === &amp;quot;path&amp;quot; || target.tagName === &amp;quot;svg&amp;quot;) {&lt;br /&gt;
      handleClickOnCharacter(&lt;br /&gt;
        spanInput,&lt;br /&gt;
        target,&lt;br /&gt;
        characters,&lt;br /&gt;
        newCharacterTemplate,&lt;br /&gt;
        battle&lt;br /&gt;
      );&lt;br /&gt;
    } else {&lt;br /&gt;
      handleClickOnCharacter(&lt;br /&gt;
        spanInput,&lt;br /&gt;
        null,&lt;br /&gt;
        characters,&lt;br /&gt;
        newCharacterTemplate,&lt;br /&gt;
        battle,&lt;br /&gt;
        true&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  newCharacterTemplate.addEventListener(&amp;quot;keydown&amp;quot;, function (event) {&lt;br /&gt;
    if (event.keyCode === 13) {&lt;br /&gt;
      event.target.click();&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  return [newCharacterTemplate, spanInput];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function validPseudo(pseudo) {&lt;br /&gt;
  var newPseudo = pseudoFormat(pseudo);&lt;br /&gt;
&lt;br /&gt;
  if (!newPseudo) {&lt;br /&gt;
    return &amp;quot;Pseudo&amp;quot;;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return newPseudo;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addNewCharacter(&lt;br /&gt;
  characters,&lt;br /&gt;
  characterTemplate,&lt;br /&gt;
  charactersContainer,&lt;br /&gt;
  battle,&lt;br /&gt;
  pseudoToDuplicate&lt;br /&gt;
) {&lt;br /&gt;
  function editAndSetCharacterPseudoInput(selectedCharacter, spanInput) {&lt;br /&gt;
    var maxPseudoLength = 20;&lt;br /&gt;
&lt;br /&gt;
    var selection = window.getSelection();&lt;br /&gt;
    var range = document.createRange();&lt;br /&gt;
&lt;br /&gt;
    if (pseudoToDuplicate) {&lt;br /&gt;
      spanInput.textContent = pseudoToDuplicate;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    spanInput.contentEditable = true;&lt;br /&gt;
    spanInput.focus();&lt;br /&gt;
    range.selectNodeContents(spanInput);&lt;br /&gt;
    selection.removeAllRanges();&lt;br /&gt;
    selection.addRange(range);&lt;br /&gt;
&lt;br /&gt;
    function pseudoValidation() {&lt;br /&gt;
      var characterPseudo = validPseudo(spanInput.textContent);&lt;br /&gt;
      var characterDataObject = { name: characterPseudo };&lt;br /&gt;
&lt;br /&gt;
      if (pseudoToDuplicate) {&lt;br /&gt;
        characterDataObject = copyObject(&lt;br /&gt;
          characters.savedCharacters[pseudoToDuplicate]&lt;br /&gt;
        );&lt;br /&gt;
        characterDataObject.name = characterPseudo;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      [characterDataObject, characterPseudo] = addUniquePseudo(&lt;br /&gt;
        characterDataObject,&lt;br /&gt;
        Object.keys(characters.savedCharacters)&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      selection.removeAllRanges();&lt;br /&gt;
      spanInput.contentEditable = false;&lt;br /&gt;
      spanInput.textContent = characterPseudo;&lt;br /&gt;
      spanInput.setAttribute(&amp;quot;data-name&amp;quot;, characterPseudo);&lt;br /&gt;
&lt;br /&gt;
      updateForm(&lt;br /&gt;
        characterDataObject,&lt;br /&gt;
        characters.characterCreation,&lt;br /&gt;
        characters,&lt;br /&gt;
        selectedCharacter,&lt;br /&gt;
        battle&lt;br /&gt;
      );&lt;br /&gt;
      saveCharacter(&lt;br /&gt;
        characters.savedCharacters,&lt;br /&gt;
        characters.characterCreation,&lt;br /&gt;
        battle,&lt;br /&gt;
        true&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handleMaxLength(event) {&lt;br /&gt;
      if (spanInput.textContent.length &amp;gt; maxPseudoLength) {&lt;br /&gt;
        spanInput.textContent = spanInput.textContent.slice(0, maxPseudoLength);&lt;br /&gt;
        range.setStart(spanInput.childNodes[0], maxPseudoLength);&lt;br /&gt;
        selection.removeAllRanges();&lt;br /&gt;
        selection.addRange(range);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handleBlur() {&lt;br /&gt;
      spanInput.removeEventListener(&amp;quot;blur&amp;quot;, handleBlur);&lt;br /&gt;
      spanInput.removeEventListener(&amp;quot;input&amp;quot;, handleMaxLength);&lt;br /&gt;
      pseudoValidation();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handleKeyDown(event) {&lt;br /&gt;
      if (event.key === &amp;quot;Enter&amp;quot;) {&lt;br /&gt;
        event.preventDefault();&lt;br /&gt;
&lt;br /&gt;
        spanInput.removeEventListener(&amp;quot;keydown&amp;quot;, handleKeyDown);&lt;br /&gt;
        spanInput.removeEventListener(&amp;quot;blur&amp;quot;, handleBlur);&lt;br /&gt;
        spanInput.removeEventListener(&amp;quot;input&amp;quot;, handleMaxLength);&lt;br /&gt;
&lt;br /&gt;
        pseudoValidation();&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    spanInput.addEventListener(&amp;quot;input&amp;quot;, handleMaxLength);&lt;br /&gt;
    spanInput.addEventListener(&amp;quot;keydown&amp;quot;, handleKeyDown);&lt;br /&gt;
    spanInput.addEventListener(&amp;quot;blur&amp;quot;, handleBlur);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  hideElement(characters.characterCreation);&lt;br /&gt;
  var [selectedCharacter, spanInput] = handleNewCharacter(&lt;br /&gt;
    characters,&lt;br /&gt;
    characterTemplate,&lt;br /&gt;
    charactersContainer,&lt;br /&gt;
    battle&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  editAndSetCharacterPseudoInput(selectedCharacter, spanInput);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleFocus() {&lt;br /&gt;
  var tooltipLinks = document.querySelectorAll(&amp;quot;div.tooltip a&amp;quot;);&lt;br /&gt;
  tooltipLinks.forEach(function (link) {&lt;br /&gt;
    link.setAttribute(&amp;quot;tabindex&amp;quot;, -1);&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleBonusVariationUpdate(characterCreation, bonusVariation) {&lt;br /&gt;
  var selectedBonus = characterCreation.bonusVariation.value;&lt;br /&gt;
&lt;br /&gt;
  if (characterCreation.hasOwnProperty(selectedBonus)) {&lt;br /&gt;
    handleBonusVariation(characterCreation[selectedBonus], bonusVariation);&lt;br /&gt;
  } else {&lt;br /&gt;
    var { minValue, maxValue } = bonusVariation;&lt;br /&gt;
&lt;br /&gt;
    minValue.removeAttribute(&amp;quot;min&amp;quot;);&lt;br /&gt;
    minValue.removeAttribute(&amp;quot;max&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    maxValue.removeAttribute(&amp;quot;min&amp;quot;);&lt;br /&gt;
    maxValue.removeAttribute(&amp;quot;max&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    hideElement(bonusVariation.container);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getTargetContent(targetParent, targetName, isSkill) {&lt;br /&gt;
  var targetContent = &amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  if (targetParent.children.length &amp;lt;= 1) {&lt;br /&gt;
    targetContent = targetParent.textContent;&lt;br /&gt;
  } else if (targetName === &amp;quot;weaponUpgrade&amp;quot;) {&lt;br /&gt;
    targetContent = targetParent.children[1].textContent;&lt;br /&gt;
  } else if (isSkill) {&lt;br /&gt;
    var container = targetParent.children[1];&lt;br /&gt;
&lt;br /&gt;
    for (var index = 1; index &amp;lt; container.children.length; index++) {&lt;br /&gt;
      var element = container.children[index];&lt;br /&gt;
&lt;br /&gt;
      if (element.checkVisibility()) {&lt;br /&gt;
        targetContent += element.textContent;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    for (var index = 1; index &amp;lt; targetParent.children.length; index++) {&lt;br /&gt;
      var element = targetParent.children[index];&lt;br /&gt;
&lt;br /&gt;
      if (element.checkVisibility()) {&lt;br /&gt;
        targetContent += element.textContent;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return targetContent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleBonusVariation(target, bonusVariation, isSelectedByUser) {&lt;br /&gt;
  var { activation, inputDisplay, minValue, maxValue, container } =&lt;br /&gt;
    bonusVariation;&lt;br /&gt;
&lt;br /&gt;
  var {&lt;br /&gt;
    min: targetMin,&lt;br /&gt;
    max: targetMax,&lt;br /&gt;
    name: targetName,&lt;br /&gt;
    value: targetValue,&lt;br /&gt;
    parentElement: targetParent,&lt;br /&gt;
    tagName,&lt;br /&gt;
  } = target;&lt;br /&gt;
&lt;br /&gt;
  targetMin = Number(targetMin);&lt;br /&gt;
  targetMax = Number(targetMax);&lt;br /&gt;
  targetValue = Number(targetValue);&lt;br /&gt;
&lt;br /&gt;
  var isSkill = tagName === &amp;quot;SELECT&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  if (container.contains(target) || targetName == 0) {&lt;br /&gt;
    if (!isSelectedByUser) {&lt;br /&gt;
      hideElement(container);&lt;br /&gt;
    }&lt;br /&gt;
    return;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (isSkill) {&lt;br /&gt;
    var options = target.options;&lt;br /&gt;
&lt;br /&gt;
    targetMin = options[0].value;&lt;br /&gt;
    targetMax = options[options.length - 1].value;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  minValue.min = targetMin;&lt;br /&gt;
  minValue.max = targetMax;&lt;br /&gt;
&lt;br /&gt;
  maxValue.min = targetMin;&lt;br /&gt;
  maxValue.max = targetMax;&lt;br /&gt;
&lt;br /&gt;
  if (isSelectedByUser) {&lt;br /&gt;
    var { input, tab } = bonusVariation;&lt;br /&gt;
&lt;br /&gt;
    inputDisplay.value = getTargetContent(targetParent, targetName, isSkill);&lt;br /&gt;
&lt;br /&gt;
    input.value = targetName;&lt;br /&gt;
    minValue.value = Math.max(targetValue - 10, targetMin);&lt;br /&gt;
    maxValue.value = Math.min(targetValue + 10, targetMax);&lt;br /&gt;
&lt;br /&gt;
    activation.checked = true;&lt;br /&gt;
&lt;br /&gt;
    tab.click();&lt;br /&gt;
    tab.scrollIntoView(true);&lt;br /&gt;
&lt;br /&gt;
    input.dispatchEvent(new Event(&amp;quot;change&amp;quot;, { bubbles: true }));&lt;br /&gt;
  } else {&lt;br /&gt;
    if (minValue.value &amp;lt; targetMin) {&lt;br /&gt;
      minValue.value = targetMin;&lt;br /&gt;
      minValue.dispatchEvent(new Event(&amp;quot;change&amp;quot;, { bubbles: true }));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (maxValue.value &amp;gt; targetMax) {&lt;br /&gt;
      maxValue.value = targetMax;&lt;br /&gt;
      maxValue.dispatchEvent(new Event(&amp;quot;change&amp;quot;, { bubbles: true }));&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  inputDisplay.style.width = inputDisplay.value.length * 0.55 + &amp;quot;em&amp;quot;;&lt;br /&gt;
  showElement(container);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function characterManagement(characters, battle) {&lt;br /&gt;
  var {&lt;br /&gt;
    newCharacterTemplate: characterTemplate,&lt;br /&gt;
    charactersContainer,&lt;br /&gt;
    addNewCharacterButton,&lt;br /&gt;
    saveButton,&lt;br /&gt;
    characterCreation,&lt;br /&gt;
    bonusVariation,&lt;br /&gt;
  } = characters;&lt;br /&gt;
&lt;br /&gt;
  Object.keys(characters.savedCharacters).forEach(function (pseudo) {&lt;br /&gt;
    handleNewCharacter(&lt;br /&gt;
      characters,&lt;br /&gt;
      characterTemplate,&lt;br /&gt;
      charactersContainer,&lt;br /&gt;
      battle,&lt;br /&gt;
      pseudo&lt;br /&gt;
    );&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  addNewCharacterButton.addEventListener(&amp;quot;click&amp;quot;, function (event) {&lt;br /&gt;
    if (!characters.unsavedChanges) {&lt;br /&gt;
      addNewCharacter(&lt;br /&gt;
        characters,&lt;br /&gt;
        characterTemplate,&lt;br /&gt;
        charactersContainer,&lt;br /&gt;
        battle&lt;br /&gt;
      );&lt;br /&gt;
    } else {&lt;br /&gt;
      var result = confirm(&lt;br /&gt;
        &amp;quot;Voulez-vous continuer ? Les dernières modifications ne seront pas sauvegardées.&amp;quot;&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      if (result) {&lt;br /&gt;
        addNewCharacter(&lt;br /&gt;
          characters,&lt;br /&gt;
          characterTemplate,&lt;br /&gt;
          charactersContainer,&lt;br /&gt;
          battle&lt;br /&gt;
        );&lt;br /&gt;
        saveButtonGreen(saveButton);&lt;br /&gt;
        characters.unsavedChanges = false;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  handleUploadCharacter(&lt;br /&gt;
    characters,&lt;br /&gt;
    characterTemplate,&lt;br /&gt;
    charactersContainer,&lt;br /&gt;
    battle&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;change&amp;quot;, function () {&lt;br /&gt;
    saveButtonOrange(saveButton);&lt;br /&gt;
    characters.unsavedChanges = true;&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  function handleLongPress(target) {&lt;br /&gt;
    if (target.tagName !== &amp;quot;INPUT&amp;quot; &amp;amp;&amp;amp; target.tagName !== &amp;quot;SELECT&amp;quot;) {&lt;br /&gt;
      target = target.querySelector(&amp;quot;input&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      !target ||&lt;br /&gt;
      (target.type !== &amp;quot;number&amp;quot; &amp;amp;&amp;amp;&lt;br /&gt;
        !target.classList.contains(&amp;quot;skill-select&amp;quot;) &amp;amp;&amp;amp;&lt;br /&gt;
        target.name !== &amp;quot;weaponUpgrade&amp;quot;)&lt;br /&gt;
    ) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    handleBonusVariation(target, bonusVariation, true);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;click&amp;quot;, function (event) {&lt;br /&gt;
    if (event.shiftKey || event.ctrlKey) {&lt;br /&gt;
      handleLongPress(event.target);&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  var longPressTimer;&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;touchstart&amp;quot;, function (event) {&lt;br /&gt;
    longPressTimer = setTimeout(function () {&lt;br /&gt;
      handleLongPress(event.target);&lt;br /&gt;
    }, 800);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;touchend&amp;quot;, function () {&lt;br /&gt;
    clearTimeout(longPressTimer);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;touchmove&amp;quot;, function () {&lt;br /&gt;
    clearTimeout(longPressTimer);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  filterForm(characters, battle);&lt;br /&gt;
  characterCreationListener(characters, battle);&lt;br /&gt;
  handleFocus();&lt;br /&gt;
&lt;br /&gt;
  window.addEventListener(&amp;quot;beforeunload&amp;quot;, function (event) {&lt;br /&gt;
    if (characters.unsavedChanges) {&lt;br /&gt;
      event.preventDefault();&lt;br /&gt;
      return &amp;quot;&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleNewMonster(&lt;br /&gt;
  characters,&lt;br /&gt;
  monsterTemplate,&lt;br /&gt;
  monstersContainer,&lt;br /&gt;
  battle,&lt;br /&gt;
  monsterVnum,&lt;br /&gt;
  monsterList&lt;br /&gt;
) {&lt;br /&gt;
  var newMonsterTemplate = monsterTemplate.cloneNode(true);&lt;br /&gt;
  var spanInput = newMonsterTemplate.querySelector(&amp;quot;span.input&amp;quot;);&lt;br /&gt;
  var deleteSvg = newMonsterTemplate.querySelector(&amp;quot;svg&amp;quot;);&lt;br /&gt;
  var monsterName = getMonsterName(monsterVnum);&lt;br /&gt;
&lt;br /&gt;
  var link = document.createElement(&amp;quot;a&amp;quot;);&lt;br /&gt;
  link.href = mw.util.getUrl(monsterName);&lt;br /&gt;
  link.title = monsterName;&lt;br /&gt;
  link.textContent = monsterName;&lt;br /&gt;
&lt;br /&gt;
  spanInput.appendChild(link);&lt;br /&gt;
  monstersContainer.appendChild(newMonsterTemplate);&lt;br /&gt;
&lt;br /&gt;
  newMonsterTemplate.setAttribute(&amp;quot;tabindex&amp;quot;, &amp;quot;0&amp;quot;);&lt;br /&gt;
  newMonsterTemplate.setAttribute(&amp;quot;data-name&amp;quot;, monsterVnum);&lt;br /&gt;
  monstersContainer.appendChild(newMonsterTemplate);&lt;br /&gt;
&lt;br /&gt;
  deleteSvg.addEventListener(&amp;quot;click&amp;quot;, function (event) {&lt;br /&gt;
    deleteMonster(characters, monsterVnum, newMonsterTemplate, battle);&lt;br /&gt;
    var inputMonster = monsterList.querySelector(&lt;br /&gt;
      &amp;quot;input[name='&amp;quot; + monsterVnum + &amp;quot;']&amp;quot;&lt;br /&gt;
    );&lt;br /&gt;
    inputMonster.checked = false;&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function monsterManagement(characters, battle) {&lt;br /&gt;
  function handleDropdown(searchMonster, monsterList) {&lt;br /&gt;
    searchMonster.addEventListener(&amp;quot;focus&amp;quot;, function (event) {&lt;br /&gt;
      showElement(monsterList);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.addEventListener(&amp;quot;mousedown&amp;quot;, function (event) {&lt;br /&gt;
      var target = event.target;&lt;br /&gt;
      if (!monsterList.contains(target) &amp;amp;&amp;amp; !searchMonster.contains(target)) {&lt;br /&gt;
        hideElement(monsterList);&lt;br /&gt;
      }&lt;br /&gt;
    });&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function addMonsterNames(monsterList) {&lt;br /&gt;
    var lastMonsterAttributeIndex = monsterData[101].length - 1;&lt;br /&gt;
&lt;br /&gt;
    for (var monsterVnum in monsterData) {&lt;br /&gt;
      var li = document.createElement(&amp;quot;li&amp;quot;);&lt;br /&gt;
      var label = document.createElement(&amp;quot;label&amp;quot;);&lt;br /&gt;
      var input = document.createElement(&amp;quot;input&amp;quot;);&lt;br /&gt;
      var textNode = document.createTextNode(&lt;br /&gt;
        monsterData[monsterVnum][lastMonsterAttributeIndex]&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      label.htmlFor = &amp;quot;monster&amp;quot; + monsterVnum;&lt;br /&gt;
      input.id = &amp;quot;monster&amp;quot; + monsterVnum;&lt;br /&gt;
      input.type = &amp;quot;checkbox&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
      input.name = monsterVnum;&lt;br /&gt;
&lt;br /&gt;
      label.appendChild(input);&lt;br /&gt;
      label.appendChild(textNode);&lt;br /&gt;
      li.appendChild(label);&lt;br /&gt;
      monsterList.appendChild(li);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function filterNames(searchMonster, monsterList) {&lt;br /&gt;
    var debounceTimer;&lt;br /&gt;
&lt;br /&gt;
    searchMonster.addEventListener(&amp;quot;input&amp;quot;, function (event) {&lt;br /&gt;
      clearTimeout(debounceTimer);&lt;br /&gt;
      debounceTimer = setTimeout(function () {&lt;br /&gt;
        var value = toNormalForm(event.target.value);&lt;br /&gt;
        for (var element of monsterList.children) {&lt;br /&gt;
          if (!isValueInArray(value, toNormalForm(element.textContent))) {&lt;br /&gt;
            hideElement(element);&lt;br /&gt;
          } else {&lt;br /&gt;
            showElement(element);&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
      }, 500);&lt;br /&gt;
    });&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var monsterTemplate = characters.newMonsterTemplate;&lt;br /&gt;
  var monstersContainer = characters.monstersContainer;&lt;br /&gt;
  var monsterList = characters.monsterList;&lt;br /&gt;
  var searchMonster = characters.searchMonster;&lt;br /&gt;
  var monsterListForm = characters.monsterListForm;&lt;br /&gt;
&lt;br /&gt;
  document&lt;br /&gt;
    .getElementById(&amp;quot;monster-link&amp;quot;)&lt;br /&gt;
    .querySelector(&amp;quot;a&amp;quot;)&lt;br /&gt;
    .setAttribute(&amp;quot;target&amp;quot;, &amp;quot;_blank&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  handleDropdown(searchMonster, monsterList);&lt;br /&gt;
  addMonsterNames(monsterList, characters.monsterListTemplate);&lt;br /&gt;
  filterNames(searchMonster, monsterList);&lt;br /&gt;
&lt;br /&gt;
  characters.savedMonsters.slice().forEach(function (monsterVnum) {&lt;br /&gt;
    var inputMonster = monsterList.querySelector(&lt;br /&gt;
      &amp;quot;input[name='&amp;quot; + monsterVnum + &amp;quot;']&amp;quot;&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    if (inputMonster) {&lt;br /&gt;
      handleNewMonster(&lt;br /&gt;
        characters,&lt;br /&gt;
        monsterTemplate,&lt;br /&gt;
        monstersContainer,&lt;br /&gt;
        battle,&lt;br /&gt;
        monsterVnum,&lt;br /&gt;
        monsterList&lt;br /&gt;
      );&lt;br /&gt;
      inputMonster.checked = true;&lt;br /&gt;
    } else {&lt;br /&gt;
      deleteMonster(characters, monsterVnum, null, battle);&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  monsterListForm.addEventListener(&amp;quot;submit&amp;quot;, function (event) {&lt;br /&gt;
    event.preventDefault();&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  monsterListForm.addEventListener(&amp;quot;change&amp;quot;, function (event) {&lt;br /&gt;
    var target = event.target;&lt;br /&gt;
    var monsterVnum = target.name;&lt;br /&gt;
&lt;br /&gt;
    if (monsterVnum === &amp;quot;search-monster&amp;quot;) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (target.checked) {&lt;br /&gt;
      handleNewMonster(&lt;br /&gt;
        characters,&lt;br /&gt;
        monsterTemplate,&lt;br /&gt;
        monstersContainer,&lt;br /&gt;
        battle,&lt;br /&gt;
        monsterVnum,&lt;br /&gt;
        monsterList&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      characters.savedMonsters.push(monsterVnum);&lt;br /&gt;
      updateSavedMonsters(characters.savedMonsters);&lt;br /&gt;
      addBattleChoice(battle, monsterVnum, true);&lt;br /&gt;
    } else {&lt;br /&gt;
      var currentMonsterTemplate = monstersContainer.querySelector(&lt;br /&gt;
        &amp;quot;[data-name='&amp;quot; + monsterVnum + &amp;quot;']&amp;quot;&lt;br /&gt;
      );&lt;br /&gt;
      deleteMonster(characters, monsterVnum, currentMonsterTemplate, battle);&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  addEventListener(&amp;quot;storage&amp;quot;, function (event) {&lt;br /&gt;
    if (event.key === &amp;quot;newMonsterCalculator&amp;quot;) {&lt;br /&gt;
      var monsterVnum = Number(event.newValue);&lt;br /&gt;
&lt;br /&gt;
      if (!monsterVnum) {&lt;br /&gt;
        return;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      var inputMonster = monsterList.querySelector(&lt;br /&gt;
        &amp;quot;input[name='&amp;quot; + Math.abs(monsterVnum) + &amp;quot;']&amp;quot;&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      if (inputMonster) {&lt;br /&gt;
        if (&lt;br /&gt;
          (monsterVnum &amp;gt; 0 &amp;amp;&amp;amp; !inputMonster.checked) ||&lt;br /&gt;
          (monsterVnum &amp;lt; 0 &amp;amp;&amp;amp; inputMonster.checked)&lt;br /&gt;
        ) {&lt;br /&gt;
          inputMonster.click();&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function removeBattleChoice(battle, name) {&lt;br /&gt;
  var battleSelects = [battle.attackerSelection, battle.victimSelection];&lt;br /&gt;
&lt;br /&gt;
  battleSelects.forEach(function (battleSelect) {&lt;br /&gt;
    for (&lt;br /&gt;
      var optionIndex = 0;&lt;br /&gt;
      optionIndex &amp;lt; battleSelect.options.length;&lt;br /&gt;
      optionIndex++&lt;br /&gt;
    ) {&lt;br /&gt;
      if (battleSelect.options[optionIndex].value === name) {&lt;br /&gt;
        battleSelect.remove(optionIndex);&lt;br /&gt;
        break;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addBattleChoice(battle, name, isMonster = false) {&lt;br /&gt;
  function createOption(text, vnum) {&lt;br /&gt;
    var option = document.createElement(&amp;quot;option&amp;quot;);&lt;br /&gt;
    option.textContent = text;&lt;br /&gt;
    option.value = vnum;&lt;br /&gt;
&lt;br /&gt;
    if (!isMonster) {&lt;br /&gt;
      option.classList.add(&amp;quot;notranslate&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return option;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var vnum = name;&lt;br /&gt;
&lt;br /&gt;
  if (isMonster) {&lt;br /&gt;
    name = getMonsterName(name);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (isMonster &amp;amp;&amp;amp; monsterData[vnum][1]) {&lt;br /&gt;
    // pass&lt;br /&gt;
  } else {&lt;br /&gt;
    battle.attackerSelection.appendChild(createOption(name, vnum));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  battle.victimSelection.appendChild(createOption(name, vnum));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateBattleChoice(characters, battle) {&lt;br /&gt;
  var keys = Object.keys(characters.savedCharacters);&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; keys.length; index++) {&lt;br /&gt;
    var pseudo = keys[index];&lt;br /&gt;
    addBattleChoice(battle, pseudo);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  characters.savedMonsters.forEach(function (monsterVnum) {&lt;br /&gt;
    addBattleChoice(battle, monsterVnum, true);&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isPC(character) {&lt;br /&gt;
  if (character.race === 0 || character.race === 1) {&lt;br /&gt;
    return false;&lt;br /&gt;
  }&lt;br /&gt;
  return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isBoss(character) {&lt;br /&gt;
  return character.race === 0 &amp;amp;&amp;amp; character.rank &amp;gt;= 5;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isStone(character) {&lt;br /&gt;
  return character.race === 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isMeleeAttacker(monster) {&lt;br /&gt;
  return monster.attack == 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isRangeAttacker(monster) {&lt;br /&gt;
  return monster.attack == 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isMagicAttacker(monster) {&lt;br /&gt;
  return monster.attack == 2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isMagicClass(character) {&lt;br /&gt;
  return character.race === &amp;quot;shaman&amp;quot; || character.class === &amp;quot;black_magic&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isDispell(character, skillId) {&lt;br /&gt;
  return character.class === &amp;quot;weaponary&amp;quot; &amp;amp;&amp;amp; skillId === 6;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isPolymorph(character) {&lt;br /&gt;
  return character.state === &amp;quot;polymorph&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isRiding(character) {&lt;br /&gt;
  return character.state === &amp;quot;horse&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isBow(weapon) {&lt;br /&gt;
  return weapon.type === 2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcAttackFactor(attacker, victim) {&lt;br /&gt;
  function calcCoeffK(dex, level) {&lt;br /&gt;
    return Math.min(90, Math.floor((2 * dex + level) / 3));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var K1 = calcCoeffK(attacker.polymorphDex, attacker.level);&lt;br /&gt;
  var K2 = calcCoeffK(victim.polymorphDex, attacker.level);&lt;br /&gt;
&lt;br /&gt;
  var AR = (K1 + 210) / 300;&lt;br /&gt;
  var ER = (((2 * K2 + 5) / (K2 + 95)) * 3) / 10;&lt;br /&gt;
&lt;br /&gt;
  return truncateNumber(AR - ER, 8);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcMainAttackValue(attacker) {&lt;br /&gt;
  var leadership = 0;&lt;br /&gt;
  var rawWeaponAttackValue = 0;&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker)) {&lt;br /&gt;
    var weaponUpgrades = attacker.weapon.upgrades;&lt;br /&gt;
    var maxUpgrade = weaponUpgrades.length - 1;&lt;br /&gt;
&lt;br /&gt;
    if (attacker.hasOwnProperty(&amp;quot;weaponUpgrade&amp;quot;)) {&lt;br /&gt;
      rawWeaponAttackValue =&lt;br /&gt;
        weaponUpgrades[Math.min(attacker.weaponUpgrade, maxUpgrade)];&lt;br /&gt;
&lt;br /&gt;
      // rare bug when weaponUpgrade is deleted&lt;br /&gt;
    } else {&lt;br /&gt;
      console.log(&amp;quot;Warming: weaponUpgrade is missing.&amp;quot;);&lt;br /&gt;
      rawWeaponAttackValue = weaponUpgrades[maxUpgrade];&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    leadership = attacker.leadership;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return 2 * (attacker.level + rawWeaponAttackValue) + leadership;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcStatAttackValue(character) {&lt;br /&gt;
  switch (character.race) {&lt;br /&gt;
    case &amp;quot;warrior&amp;quot;:&lt;br /&gt;
    case &amp;quot;sura&amp;quot;:&lt;br /&gt;
      return 2 * character.str;&lt;br /&gt;
    case &amp;quot;ninja&amp;quot;:&lt;br /&gt;
      return Math.floor((1 / 4) * (character.str + 7 * character.dex));&lt;br /&gt;
    case &amp;quot;shaman&amp;quot;:&lt;br /&gt;
      return Math.floor((1 / 3) * (5 * character.int + character.dex));&lt;br /&gt;
    case &amp;quot;lycan&amp;quot;:&lt;br /&gt;
      return character.vit + 2 * character.dex;&lt;br /&gt;
    default:&lt;br /&gt;
      return 2 * character.str;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcSecondaryAttackValue(attacker) {&lt;br /&gt;
  var attackValueOther = 0;&lt;br /&gt;
&lt;br /&gt;
  var minAttackValue = 0;&lt;br /&gt;
  var maxAttackValue = 0;&lt;br /&gt;
&lt;br /&gt;
  var minAttackValueSlash = 0;&lt;br /&gt;
  var maxAttackValueSlash = 0;&lt;br /&gt;
&lt;br /&gt;
  var attackerWeapon = attacker.weapon;&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker)) {&lt;br /&gt;
    if (attackerWeapon.isSerpent) {&lt;br /&gt;
      var rawAttackValue = attackerWeapon.upgrades[attacker.weaponUpgrade];&lt;br /&gt;
&lt;br /&gt;
      minAttackValue = attacker.minAttackValueRandom - rawAttackValue;&lt;br /&gt;
      maxAttackValue = attacker.maxAttackValueRandom - rawAttackValue;&lt;br /&gt;
&lt;br /&gt;
      minAttackValue = Math.max(0, minAttackValue);&lt;br /&gt;
      maxAttackValue = Math.max(minAttackValue, maxAttackValue);&lt;br /&gt;
    } else {&lt;br /&gt;
      minAttackValue = attackerWeapon.minAttackValue;&lt;br /&gt;
      maxAttackValue = attackerWeapon.maxAttackValue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    minAttackValueSlash = Math.min(&lt;br /&gt;
      attacker.minAttackValueSlash,&lt;br /&gt;
      attacker.maxAttackValueSlash&lt;br /&gt;
    );&lt;br /&gt;
    maxAttackValueSlash = Math.max(&lt;br /&gt;
      attacker.minAttackValueSlash,&lt;br /&gt;
      attacker.maxAttackValueSlash&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    attackValueOther += attacker.attackValue;&lt;br /&gt;
&lt;br /&gt;
    if (isBow(attackerWeapon) &amp;amp;&amp;amp; !isPolymorph(attacker)) {&lt;br /&gt;
      attackValueOther += 25;&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    minAttackValue = attacker.minAttackValue;&lt;br /&gt;
    maxAttackValue = attacker.maxAttackValue;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  minAttackValue += attacker.minAttackValuePolymorph;&lt;br /&gt;
  maxAttackValue += attacker.maxAttackValuePolymorph;&lt;br /&gt;
&lt;br /&gt;
  attackValueOther += attacker.statAttackValue;&lt;br /&gt;
  attackValueOther += attacker.horseAttackValue;&lt;br /&gt;
&lt;br /&gt;
  var weaponInterval = maxAttackValue - minAttackValue + 1;&lt;br /&gt;
  var slashInterval = maxAttackValueSlash - minAttackValueSlash + 1;&lt;br /&gt;
&lt;br /&gt;
  var totalCardinal = weaponInterval * slashInterval * 1_000_000;&lt;br /&gt;
  var minInterval = Math.min(weaponInterval, slashInterval);&lt;br /&gt;
&lt;br /&gt;
  minAttackValue += minAttackValueSlash;&lt;br /&gt;
  maxAttackValue += maxAttackValueSlash;&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    minAttackValue: minAttackValue,&lt;br /&gt;
    maxAttackValue: maxAttackValue,&lt;br /&gt;
    attackValueOther: attackValueOther,&lt;br /&gt;
    totalCardinal: totalCardinal,&lt;br /&gt;
    weights: calcWeights(minAttackValue, maxAttackValue, minInterval),&lt;br /&gt;
    possibleDamagesCount: maxAttackValue - minAttackValue + 1,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcMagicAttackValue(attacker) {&lt;br /&gt;
  var minMagicAttackValue = 0;&lt;br /&gt;
  var maxMagicAttackValue = 0;&lt;br /&gt;
&lt;br /&gt;
  var minMagicAttackValueSlash = 0;&lt;br /&gt;
  var maxMagicAttackValueSlash = 0;&lt;br /&gt;
&lt;br /&gt;
  var attackerWeapon = attacker.weapon;&lt;br /&gt;
&lt;br /&gt;
  if (attackerWeapon.isSerpent) {&lt;br /&gt;
    minMagicAttackValue = attacker.minMagicAttackValueRandom;&lt;br /&gt;
    maxMagicAttackValue = attacker.maxMagicAttackValueRandom;&lt;br /&gt;
&lt;br /&gt;
    maxMagicAttackValue = Math.max(minMagicAttackValue, maxMagicAttackValue);&lt;br /&gt;
  } else {&lt;br /&gt;
    var rawWeaponAttackValue = attackerWeapon.upgrades[attacker.weaponUpgrade];&lt;br /&gt;
&lt;br /&gt;
    if (!rawWeaponAttackValue) {&lt;br /&gt;
      rawWeaponAttackValue = 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    minMagicAttackValue =&lt;br /&gt;
      attackerWeapon.minMagicAttackValue + rawWeaponAttackValue;&lt;br /&gt;
    maxMagicAttackValue =&lt;br /&gt;
      attackerWeapon.maxMagicAttackValue + rawWeaponAttackValue;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  minMagicAttackValueSlash = Math.min(&lt;br /&gt;
    attacker.minMagicAttackValueSlash,&lt;br /&gt;
    attacker.maxMagicAttackValueSlash&lt;br /&gt;
  );&lt;br /&gt;
  maxMagicAttackValueSlash = Math.max(&lt;br /&gt;
    attacker.minMagicAttackValueSlash,&lt;br /&gt;
    attacker.maxMagicAttackValueSlash&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  var weaponInterval = maxMagicAttackValue - minMagicAttackValue + 1;&lt;br /&gt;
  var slashInterval = maxMagicAttackValueSlash - minMagicAttackValueSlash + 1;&lt;br /&gt;
&lt;br /&gt;
  var totalCardinal = weaponInterval * slashInterval * 1_000_000;&lt;br /&gt;
  var minInterval = Math.min(weaponInterval, slashInterval);&lt;br /&gt;
&lt;br /&gt;
  minMagicAttackValue += minMagicAttackValueSlash;&lt;br /&gt;
  maxMagicAttackValue += maxMagicAttackValueSlash;&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    minMagicAttackValue: minMagicAttackValue,&lt;br /&gt;
    maxMagicAttackValue: maxMagicAttackValue,&lt;br /&gt;
    magicAttackValueAugmentation: getMagicAttackValueAugmentation(&lt;br /&gt;
      minMagicAttackValue,&lt;br /&gt;
      maxMagicAttackValue,&lt;br /&gt;
      attacker.magicAttackValue&lt;br /&gt;
    ),&lt;br /&gt;
    totalCardinal: totalCardinal,&lt;br /&gt;
    weights: calcWeights(minMagicAttackValue, maxMagicAttackValue, minInterval),&lt;br /&gt;
    possibleDamagesCount: maxMagicAttackValue - minMagicAttackValue + 1,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getPolymorphPower(polymorphPoint, polymorphPowerTable) {&lt;br /&gt;
  return polymorphPowerTable[polymorphPoint];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSkillPower(skillPoint, skillPowerTable) {&lt;br /&gt;
  return skillPowerTable[skillPoint];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getMarriageBonusValue(character, marriageTable, itemName) {&lt;br /&gt;
  var index;&lt;br /&gt;
  var lovePoint = character.lovePoint;&lt;br /&gt;
&lt;br /&gt;
  if (lovePoint &amp;lt; 65) {&lt;br /&gt;
    index = 0;&lt;br /&gt;
  } else if (lovePoint &amp;lt; 80) {&lt;br /&gt;
    index = 1;&lt;br /&gt;
  } else if (lovePoint &amp;lt; 100) {&lt;br /&gt;
    index = 2;&lt;br /&gt;
  } else {&lt;br /&gt;
    index = 3;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return marriageTable[itemName][index];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcDamageWithPrimaryBonuses(damages, bonusValues) {&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.attackValueCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  damages += bonusValues.attackValueMarriage;&lt;br /&gt;
&lt;br /&gt;
  damages = Math.floor(&lt;br /&gt;
    (damages * bonusValues.monsterResistanceMarriageCoeff) / 100&lt;br /&gt;
  );&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.monsterResistanceCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  damages += Math.floor((damages * bonusValues.typeBonusCoeff) / 100);&lt;br /&gt;
  damages +=&lt;br /&gt;
    Math.floor((damages * bonusValues.raceBonusCoeff) / 100) -&lt;br /&gt;
    Math.floor((damages * bonusValues.raceResistanceCoeff) / 100);&lt;br /&gt;
  damages += Math.floor((damages * bonusValues.stoneBonusCoeff) / 100);&lt;br /&gt;
  damages += Math.floor((damages * bonusValues.monsterBonusCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  var elementBonusCoeff = bonusValues.elementBonusCoeff;&lt;br /&gt;
&lt;br /&gt;
  damages +=&lt;br /&gt;
    Math.trunc((damages * elementBonusCoeff[0]) / 10000) +&lt;br /&gt;
    Math.trunc((damages * elementBonusCoeff[1]) / 10000) +&lt;br /&gt;
    Math.trunc((damages * elementBonusCoeff[2]) / 10000) +&lt;br /&gt;
    Math.trunc((damages * elementBonusCoeff[3]) / 10000) +&lt;br /&gt;
    Math.trunc((damages * elementBonusCoeff[4]) / 10000) +&lt;br /&gt;
    Math.trunc((damages * elementBonusCoeff[5]) / 10000);&lt;br /&gt;
&lt;br /&gt;
  damages = Math.floor(damages * bonusValues.damageMultiplier);&lt;br /&gt;
&lt;br /&gt;
  return damages;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcDamageWithSecondaryBonuses(&lt;br /&gt;
  damages,&lt;br /&gt;
  bonusValues,&lt;br /&gt;
  damagesType,&lt;br /&gt;
  minPiercingDamages,&lt;br /&gt;
  damagesWithPrimaryBonuses&lt;br /&gt;
) {&lt;br /&gt;
  damages = Math.floor(damages * bonusValues.magicResistanceCoeff);&lt;br /&gt;
  damages = Math.trunc((damages * bonusValues.weaponDefenseCoeff) / 100);&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.tigerStrengthCoeff) / 100);&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.blessingBonusCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  if (damagesType.criticalHit) {&lt;br /&gt;
    damages *= 2;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (damagesType.piercingHit) {&lt;br /&gt;
    damages += bonusValues.defenseBoost + Math.min(0, minPiercingDamages);&lt;br /&gt;
    damages += Math.floor(&lt;br /&gt;
      (damagesWithPrimaryBonuses * bonusValues.extraPiercingHitCoeff) / 1000&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.averageDamageCoeff) / 100);&lt;br /&gt;
  damages = Math.floor(&lt;br /&gt;
    (damages * bonusValues.averageDamageResistanceCoeff) / 100&lt;br /&gt;
  );&lt;br /&gt;
  damages = Math.floor(&lt;br /&gt;
    (damages * bonusValues.skillDamageResistanceCoeff) / 100&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.rankBonusCoeff) / 100);&lt;br /&gt;
  damages = Math.max(0, damages + bonusValues.defensePercent);&lt;br /&gt;
  damages += Math.min(&lt;br /&gt;
    300,&lt;br /&gt;
    Math.floor((damages * bonusValues.damageBonusCoeff) / 100)&lt;br /&gt;
  );&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.empireMalusCoeff) / 10);&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.sungMaStrBonusCoeff) / 10000);&lt;br /&gt;
  damages -= Math.floor(damages * bonusValues.sungmaStrMalusCoeff);&lt;br /&gt;
&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.whiteDragonElixirCoeff) / 100);&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.steelDragonElixirCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  return damages;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcSkillDamageWithSecondaryBonuses(&lt;br /&gt;
  damages,&lt;br /&gt;
  bonusValues,&lt;br /&gt;
  damagesType,&lt;br /&gt;
  minPiercingDamages&lt;br /&gt;
) {&lt;br /&gt;
  damages = Math.floor(damages * bonusValues.magicResistanceCoeff);&lt;br /&gt;
  damages = Math.trunc((damages * bonusValues.weaponDefenseCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  damages -= bonusValues.defense;&lt;br /&gt;
&lt;br /&gt;
  damages = floorMultiplication(damages, bonusValues.skillWardCoeff);&lt;br /&gt;
  damages = floorMultiplication(damages, bonusValues.skillBonusCoeff);&lt;br /&gt;
&lt;br /&gt;
  var tempDamages = Math.floor(&lt;br /&gt;
    (damages * bonusValues.skillBonusByBonusCoeff) / 100&lt;br /&gt;
  );&lt;br /&gt;
  &lt;br /&gt;
  damages = Math.floor(&lt;br /&gt;
    (tempDamages * bonusValues.magicAttackValueCoeff) / 100 + 0.5&lt;br /&gt;
  );&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.tigerStrengthCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  if (damagesType.criticalHit) {&lt;br /&gt;
    damages *= 2;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (damagesType.piercingHit) {&lt;br /&gt;
    damages += bonusValues.defenseBoost + Math.min(0, minPiercingDamages);&lt;br /&gt;
    damages += Math.floor(&lt;br /&gt;
      (tempDamages * bonusValues.extraPiercingHitCoeff) / 1000&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.skillDamageCoeff) / 100);&lt;br /&gt;
  damages = Math.floor(&lt;br /&gt;
    (damages * bonusValues.skillDamageResistanceCoeff) / 100&lt;br /&gt;
  );&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.rankBonusCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  damages = Math.max(0, damages + bonusValues.defensePercent);&lt;br /&gt;
  damages += Math.min(&lt;br /&gt;
    300,&lt;br /&gt;
    Math.floor((damages * bonusValues.damageBonusCoeff) / 100)&lt;br /&gt;
  );&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.empireMalusCoeff) / 10);&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.sungMaStrBonusCoeff) / 10000);&lt;br /&gt;
  damages -= Math.floor(damages * bonusValues.sungmaStrMalusCoeff);&lt;br /&gt;
&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.whiteDragonElixirCoeff) / 100);&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.steelDragonElixirCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  return damages;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function computePolymorphPoint(attacker, victim, polymorphPowerTable) {&lt;br /&gt;
  attacker.statAttackValue = 0;&lt;br /&gt;
&lt;br /&gt;
  attacker.polymorphDex = attacker.dex;&lt;br /&gt;
  victim.polymorphDex = victim.dex;&lt;br /&gt;
&lt;br /&gt;
  attacker.minAttackValuePolymorph = 0;&lt;br /&gt;
  attacker.maxAttackValuePolymorph = 0;&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker) &amp;amp;&amp;amp; isPolymorph(attacker)) {&lt;br /&gt;
    var polymorphPowerPct =&lt;br /&gt;
      getPolymorphPower(attacker.polymorphPoint, polymorphPowerTable) / 100;&lt;br /&gt;
    var polymorphMonster = createMonster(attacker.polymorphMonster);&lt;br /&gt;
&lt;br /&gt;
    var polymorphStr = floorMultiplication(&lt;br /&gt;
      polymorphPowerPct,&lt;br /&gt;
      polymorphMonster.str&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    attacker.polymorphDex += floorMultiplication(&lt;br /&gt;
      polymorphPowerPct,&lt;br /&gt;
      polymorphMonster.dex&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    attacker.minAttackValuePolymorph = floorMultiplication(&lt;br /&gt;
      polymorphPowerPct,&lt;br /&gt;
      polymorphMonster.minAttackValue&lt;br /&gt;
    );&lt;br /&gt;
    attacker.maxAttackValuePolymorph = floorMultiplication(&lt;br /&gt;
      polymorphPowerPct,&lt;br /&gt;
      polymorphMonster.maxAttackValue&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    if (!attacker.weapon) {&lt;br /&gt;
      attacker.maxAttackValuePolymorph += 1;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    attacker.attackValue = 0;&lt;br /&gt;
&lt;br /&gt;
    if (isMagicClass(attacker)) {&lt;br /&gt;
      attacker.statAttackValue = 2 * (polymorphStr + attacker.int);&lt;br /&gt;
    } else {&lt;br /&gt;
      attacker.statAttackValue = 2 * (polymorphStr + attacker.str);&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    attacker.statAttackValue = calcStatAttackValue(attacker);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function computeHorse(attacker) {&lt;br /&gt;
  attacker.horseAttackValue = 0;&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker) &amp;amp;&amp;amp; isRiding(attacker)) {&lt;br /&gt;
    var horseConstant = 30;&lt;br /&gt;
&lt;br /&gt;
    if (attacker.class === &amp;quot;weaponary&amp;quot;) {&lt;br /&gt;
      horseConstant = 60;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    attacker.horseAttackValue = floorMultiplication(&lt;br /&gt;
      2 * attacker.level + attacker.statAttackValue,&lt;br /&gt;
      attacker.horsePoint / horseConstant&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getRankBonus(attacker) {&lt;br /&gt;
  if (attacker.lowRank !== &amp;quot;on&amp;quot;) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  switch (attacker.playerRank) {&lt;br /&gt;
    case &amp;quot;aggressive&amp;quot;:&lt;br /&gt;
      return 1;&lt;br /&gt;
    case &amp;quot;fraudulent&amp;quot;:&lt;br /&gt;
      return 2;&lt;br /&gt;
    case &amp;quot;malicious&amp;quot;:&lt;br /&gt;
      return 3;&lt;br /&gt;
    case &amp;quot;cruel&amp;quot;:&lt;br /&gt;
      return 5;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcElementCoeffPvP(elementBonus, mapping, attacker, victim) {&lt;br /&gt;
  var minElementMalus = 0;&lt;br /&gt;
  var maxDifference = 0;&lt;br /&gt;
  var savedElementDifferences = [];&lt;br /&gt;
  var elementBonusIndex = 0;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; elementBonus.length; index++) {&lt;br /&gt;
    if (!attacker[mapping.elementBonus[index]]) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var elementDifference =&lt;br /&gt;
      attacker[mapping.elementBonus[index]] -&lt;br /&gt;
      victim[mapping.elementResistance[index]];&lt;br /&gt;
&lt;br /&gt;
    if (elementDifference &amp;gt;= 0) {&lt;br /&gt;
      elementBonus[elementBonusIndex] = 10 * elementDifference;&lt;br /&gt;
      minElementMalus -= elementDifference;&lt;br /&gt;
      maxDifference = Math.max(maxDifference, elementDifference);&lt;br /&gt;
      elementBonusIndex++;&lt;br /&gt;
    } else {&lt;br /&gt;
      savedElementDifferences.push(elementDifference);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (!savedElementDifferences.length) {&lt;br /&gt;
    return;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  minElementMalus += maxDifference;&lt;br /&gt;
  savedElementDifferences.sort(compareNumbers);&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; savedElementDifferences.length; index++) {&lt;br /&gt;
    var elementDifference = savedElementDifferences[index];&lt;br /&gt;
&lt;br /&gt;
    elementBonus[elementBonusIndex + index] =&lt;br /&gt;
      10 * Math.max(minElementMalus, elementDifference);&lt;br /&gt;
&lt;br /&gt;
    minElementMalus = Math.min(&lt;br /&gt;
      0,&lt;br /&gt;
      Math.max(minElementMalus, minElementMalus - elementDifference)&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function skillChanceReduction(value) {&lt;br /&gt;
  if (value &amp;lt;= 9) {&lt;br /&gt;
    return Math.floor(value / 2);&lt;br /&gt;
  }&lt;br /&gt;
  return 5 + Math.floor((value - 10) / 4);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function magicResistanceToCoeff(magicResistance) {&lt;br /&gt;
  if (magicResistance) {&lt;br /&gt;
    return 2000 / (6 * magicResistance + 1000) - 1;&lt;br /&gt;
  }&lt;br /&gt;
  return 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createBattleValues(attacker, victim, battle, skillType) {&lt;br /&gt;
  var { mapping, constants } = battle;&lt;br /&gt;
  var calcAttackValues;&lt;br /&gt;
&lt;br /&gt;
  var missPercentage = 0;&lt;br /&gt;
  var attackValueMeleeMagic = 0;&lt;br /&gt;
  var attackValueMarriage = 0;&lt;br /&gt;
  var monsterResistanceMarriage = 0;&lt;br /&gt;
  var monsterResistance = 0;&lt;br /&gt;
  var typeBonus = 0;&lt;br /&gt;
  var raceBonus = 0;&lt;br /&gt;
  var raceResistance = 0;&lt;br /&gt;
  var stoneBonus = 0;&lt;br /&gt;
  var monsterBonus = 0;&lt;br /&gt;
  var elementBonus = [0, 0, 0, 0, 0, 0]; // fire, ice, lightning, earth, darkness, wind, order doesn't matter&lt;br /&gt;
  var defenseMarriage = 0;&lt;br /&gt;
  var damageMultiplier = 1;&lt;br /&gt;
  var useDamages = 1;&lt;br /&gt;
  var defense = victim.defense;&lt;br /&gt;
  var defenseBoost = defense;&lt;br /&gt;
  var magicResistance = 0;&lt;br /&gt;
  var weaponDefense = 0;&lt;br /&gt;
  var tigerStrength = 0;&lt;br /&gt;
  var blessingBonus = 0;&lt;br /&gt;
  var magicAttackValueMeleeMagic = 0;&lt;br /&gt;
  var criticalHitPercentage = attacker.criticalHit;&lt;br /&gt;
  var piercingHitPercentage = attacker.piercingHit;&lt;br /&gt;
  var extraPiercingHitPercentage = Math.max(0, piercingHitPercentage - 100);&lt;br /&gt;
  var averageDamage = 0;&lt;br /&gt;
  var averageDamageResistance = 0;&lt;br /&gt;
  var skillDamage = 0;&lt;br /&gt;
  var skillDamageResistance = 0;&lt;br /&gt;
  var rankBonus = 0;&lt;br /&gt;
  var defensePercent = 0;&lt;br /&gt;
  var damageBonus = 0;&lt;br /&gt;
  var empireMalus = 0;&lt;br /&gt;
  var sungMaStrBonus = 0;&lt;br /&gt;
  var sungmaStrMalus = 0;&lt;br /&gt;
  var whiteDragonElixir = 0;&lt;br /&gt;
  var steelDragonElixir = 0;&lt;br /&gt;
&lt;br /&gt;
  computePolymorphPoint(attacker, victim, constants.polymorphPowerTable);&lt;br /&gt;
  computeHorse(attacker);&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker)) {&lt;br /&gt;
    if (weaponData.hasOwnProperty(attacker.weapon)) {&lt;br /&gt;
      attacker.weapon = createWeapon(attacker.weapon);&lt;br /&gt;
    } else {&lt;br /&gt;
      attacker.weapon = createWeapon(0);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    attackValueMeleeMagic =&lt;br /&gt;
      attacker.attackValuePercent + Math.min(100, attacker.attackMeleeMagic);&lt;br /&gt;
&lt;br /&gt;
    var weaponType = attacker.weapon.type;&lt;br /&gt;
&lt;br /&gt;
    if (skillType &amp;amp;&amp;amp; attacker.class === &amp;quot;archery&amp;quot;) {&lt;br /&gt;
      if (weaponType !== 2) {&lt;br /&gt;
        useDamages = 0;&lt;br /&gt;
        weaponType = 2;&lt;br /&gt;
      }&lt;br /&gt;
      defense = 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var weaponDefenseName = mapping.defenseWeapon[weaponType];&lt;br /&gt;
    var weaponDefenseBreakName = mapping.breakWeapon[weaponType];&lt;br /&gt;
&lt;br /&gt;
    if (victim.hasOwnProperty(weaponDefenseName)) {&lt;br /&gt;
      weaponDefense = victim[weaponDefenseName];&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isChecked(attacker.whiteDragonElixir)) {&lt;br /&gt;
      whiteDragonElixir = 10;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isPC(victim)) {&lt;br /&gt;
      if (!skillType) {&lt;br /&gt;
        if (weaponType === 2 &amp;amp;&amp;amp; !isPolymorph(attacker)) {&lt;br /&gt;
          missPercentage = victim.arrowBlock;&lt;br /&gt;
        } else {&lt;br /&gt;
          missPercentage = victim.meleeBlock;&lt;br /&gt;
        }&lt;br /&gt;
        missPercentage +=&lt;br /&gt;
          victim.meleeArrowBlock -&lt;br /&gt;
          (missPercentage * victim.meleeArrowBlock) / 100;&lt;br /&gt;
&lt;br /&gt;
        blessingBonus = calcBlessingBonus(constants.skillPowerTable, victim);&lt;br /&gt;
        averageDamageResistance = victim.averageDamageResistance;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      typeBonus = Math.max(1, attacker.humanBonus - victim.humanResistance);&lt;br /&gt;
      raceBonus = attacker[mapping.raceBonus[victim.race]];&lt;br /&gt;
      raceResistance = victim[mapping.raceResistance[attacker.race]];&lt;br /&gt;
&lt;br /&gt;
      calcElementCoeffPvP(elementBonus, mapping, attacker, victim);&lt;br /&gt;
&lt;br /&gt;
      if (weaponType !== 2 &amp;amp;&amp;amp; attacker.hasOwnProperty(weaponDefenseBreakName)) {&lt;br /&gt;
        weaponDefense -= attacker[weaponDefenseBreakName];&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      criticalHitPercentage = 0;&lt;br /&gt;
    } else {&lt;br /&gt;
      if (isChecked(attacker.isMarried)) {&lt;br /&gt;
        if (isChecked(attacker.loveNecklace)) {&lt;br /&gt;
          attackValueMarriage = getMarriageBonusValue(&lt;br /&gt;
            attacker,&lt;br /&gt;
            constants.marriageTable,&lt;br /&gt;
            &amp;quot;loveNecklace&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isChecked(attacker.loveEarrings)) {&lt;br /&gt;
          criticalHitPercentage += getMarriageBonusValue(&lt;br /&gt;
            attacker,&lt;br /&gt;
            constants.marriageTable,&lt;br /&gt;
            &amp;quot;loveEarrings&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isChecked(attacker.harmonyEarrings)) {&lt;br /&gt;
          piercingHitPercentage += getMarriageBonusValue(&lt;br /&gt;
            attacker,&lt;br /&gt;
            constants.marriageTable,&lt;br /&gt;
            &amp;quot;harmonyEarrings&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (isChecked(attacker.tigerStrength)) {&lt;br /&gt;
        tigerStrength = 40;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      for (var index = 0; index &amp;lt; elementBonus.length; index++) {&lt;br /&gt;
        var elementBonusName = mapping.elementBonus[index];&lt;br /&gt;
        var elementResistanceName = mapping.elementResistance[index];&lt;br /&gt;
&lt;br /&gt;
        if (attacker[elementBonusName] &amp;amp;&amp;amp; victim[elementBonusName]) {&lt;br /&gt;
          elementBonus[index] =&lt;br /&gt;
            50 * (attacker[elementBonusName] - victim[elementResistanceName]);&lt;br /&gt;
        } else {&lt;br /&gt;
          elementBonus[index] = 5 * attacker[elementBonusName];&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      var victimType = victim.type;&lt;br /&gt;
&lt;br /&gt;
      if (victimType !== -1) {&lt;br /&gt;
        typeBonus = attacker[mapping.typeFlag[victimType]];&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      monsterBonus = attacker.monsterBonus;&lt;br /&gt;
&lt;br /&gt;
      if (isStone(victim)) {&lt;br /&gt;
        stoneBonus = attacker.stoneBonus;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (isBoss(victim)) {&lt;br /&gt;
        if (skillType) {&lt;br /&gt;
          skillDamage += attacker.skillBossDamage;&lt;br /&gt;
        } else {&lt;br /&gt;
          averageDamage += attacker.bossDamage;&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (isChecked(attacker.onYohara)) {&lt;br /&gt;
        var sungmaStrDifference = attacker.sungmaStr - attacker.sungmaStrMalus;&lt;br /&gt;
&lt;br /&gt;
        if (sungmaStrDifference &amp;gt;= 0) {&lt;br /&gt;
          sungMaStrBonus = sungmaStrDifference;&lt;br /&gt;
        } else {&lt;br /&gt;
          sungmaStrMalus = 0.5;&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (skillType) {&lt;br /&gt;
      skillDamage += attacker.skillDamage;&lt;br /&gt;
    } else {&lt;br /&gt;
      averageDamage += attacker.averageDamage;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    rankBonus = getRankBonus(attacker);&lt;br /&gt;
    damageBonus = attacker.damageBonus;&lt;br /&gt;
&lt;br /&gt;
    if (isChecked(attacker.empireMalus)) {&lt;br /&gt;
      empireMalus = 1;&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    if (isPC(victim)) {&lt;br /&gt;
      if (isChecked(victim.isMarried)) {&lt;br /&gt;
        if (isChecked(victim.harmonyBracelet)) {&lt;br /&gt;
          monsterResistanceMarriage = getMarriageBonusValue(&lt;br /&gt;
            victim,&lt;br /&gt;
            constants.marriageTable,&lt;br /&gt;
            &amp;quot;harmonyBracelet&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isChecked(victim.harmonyNecklace) &amp;amp;&amp;amp; !skillType) {&lt;br /&gt;
          defenseMarriage = getMarriageBonusValue(&lt;br /&gt;
            victim,&lt;br /&gt;
            constants.marriageTable,&lt;br /&gt;
            &amp;quot;harmonyNecklace&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      monsterResistance = victim.monsterResistance;&lt;br /&gt;
&lt;br /&gt;
      for (var index = 0; index &amp;lt; elementBonus.length; index++) {&lt;br /&gt;
        var elementBonusName = mapping.elementBonus[index];&lt;br /&gt;
        var elementResistanceName = mapping.elementResistance[index];&lt;br /&gt;
&lt;br /&gt;
        if (attacker[elementBonusName]) {&lt;br /&gt;
          elementBonus[index] =&lt;br /&gt;
            80 * (attacker[elementBonusName] - victim[elementResistanceName]);&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (!skillType) {&lt;br /&gt;
        if (isMeleeAttacker(attacker)) {&lt;br /&gt;
          missPercentage = victim.meleeBlock;&lt;br /&gt;
          averageDamageResistance = victim.averageDamageResistance;&lt;br /&gt;
          blessingBonus = calcBlessingBonus(constants.skillPowerTable, victim);&lt;br /&gt;
        } else if (isRangeAttacker(attacker)) {&lt;br /&gt;
          missPercentage = victim.arrowBlock;&lt;br /&gt;
          weaponDefense = victim.arrowDefense;&lt;br /&gt;
          averageDamageResistance = victim.averageDamageResistance;&lt;br /&gt;
          blessingBonus = calcBlessingBonus(constants.skillPowerTable, victim);&lt;br /&gt;
        } else if (isMagicAttacker(attacker)) {&lt;br /&gt;
          missPercentage = victim.arrowBlock;&lt;br /&gt;
          skillDamageResistance = victim.skillDamageResistance;&lt;br /&gt;
          magicResistance = victim.magicResistance;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        missPercentage +=&lt;br /&gt;
          victim.meleeArrowBlock -&lt;br /&gt;
          (missPercentage * victim.meleeArrowBlock) / 100;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    typeBonus = 1;&lt;br /&gt;
    damageMultiplier = attacker.damageMultiplier;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillType) {&lt;br /&gt;
    criticalHitPercentage = skillChanceReduction(criticalHitPercentage);&lt;br /&gt;
    piercingHitPercentage = skillChanceReduction(piercingHitPercentage);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (isPC(victim)) {&lt;br /&gt;
    if (!skillType &amp;amp;&amp;amp; isChecked(victim.biologist70)) {&lt;br /&gt;
      defenseBoost = Math.floor((defenseBoost * 110) / 100);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    criticalHitPercentage = Math.max(&lt;br /&gt;
      0,&lt;br /&gt;
      criticalHitPercentage - victim.criticalHitResistance&lt;br /&gt;
    );&lt;br /&gt;
    piercingHitPercentage = Math.max(&lt;br /&gt;
      0,&lt;br /&gt;
      piercingHitPercentage - victim.piercingHitResistance&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    if (skillType) {&lt;br /&gt;
      skillDamageResistance = victim.skillDamageResistance;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isMagicClass(victim)) {&lt;br /&gt;
      defensePercent = (-2 * victim.magicDefense * victim.defensePercent) / 100;&lt;br /&gt;
    } else {&lt;br /&gt;
      defensePercent = (-2 * defenseBoost * victim.defensePercent) / 100;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isChecked(victim.steelDragonElixir)) {&lt;br /&gt;
      steelDragonElixir = 10;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillType === &amp;quot;magic&amp;quot;) {&lt;br /&gt;
    attackValueMeleeMagic = 0;&lt;br /&gt;
    magicAttackValueMeleeMagic =&lt;br /&gt;
      attacker.attackMagic + Math.min(100, attacker.attackMeleeMagic);&lt;br /&gt;
    attackValueMarriage = 0;&lt;br /&gt;
    defense = 0;&lt;br /&gt;
    if (!isDispell(attacker, 6)) {&lt;br /&gt;
      magicResistance = victim.magicResistance;&lt;br /&gt;
    }&lt;br /&gt;
    weaponDefense = 0;&lt;br /&gt;
    calcAttackValues = calcMagicAttackValue;&lt;br /&gt;
  } else {&lt;br /&gt;
    calcAttackValues = calcSecondaryAttackValue;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  missPercentage = Math.min(100, missPercentage);&lt;br /&gt;
&lt;br /&gt;
  var bonusValues = {&lt;br /&gt;
    missPercentage: missPercentage,&lt;br /&gt;
    weaponBonusCoeff: 1,&lt;br /&gt;
    attackValueCoeff: 100 + attackValueMeleeMagic,&lt;br /&gt;
    attackValueMarriage: attackValueMarriage,&lt;br /&gt;
    monsterResistanceMarriageCoeff: 100 - monsterResistanceMarriage,&lt;br /&gt;
    monsterResistanceCoeff: 100 - monsterResistance,&lt;br /&gt;
    typeBonusCoeff: typeBonus,&lt;br /&gt;
    raceBonusCoeff: raceBonus,&lt;br /&gt;
    raceResistanceCoeff: raceResistance,&lt;br /&gt;
    stoneBonusCoeff: stoneBonus,&lt;br /&gt;
    monsterBonusCoeff: monsterBonus,&lt;br /&gt;
    elementBonusCoeff: elementBonus,&lt;br /&gt;
    damageMultiplier: damageMultiplier,&lt;br /&gt;
    useDamages: useDamages,&lt;br /&gt;
    defense: defense,&lt;br /&gt;
    defenseBoost: defenseBoost,&lt;br /&gt;
    defenseMarriage: defenseMarriage,&lt;br /&gt;
    tigerStrengthCoeff: 100 + tigerStrength,&lt;br /&gt;
    magicResistanceCoeff: magicResistanceToCoeff(magicResistance),&lt;br /&gt;
    weaponDefenseCoeff: 100 - weaponDefense,&lt;br /&gt;
    blessingBonusCoeff: 100 - blessingBonus,&lt;br /&gt;
    magicAttackValueCoeff: 100 + magicAttackValueMeleeMagic,&lt;br /&gt;
    extraPiercingHitCoeff: 5 * extraPiercingHitPercentage,&lt;br /&gt;
    averageDamageCoeff: 100 + averageDamage,&lt;br /&gt;
    averageDamageResistanceCoeff: 100 - Math.min(99, averageDamageResistance),&lt;br /&gt;
    skillDamageCoeff: 100 + skillDamage,&lt;br /&gt;
    skillDamageResistanceCoeff: 100 - Math.min(99, skillDamageResistance),&lt;br /&gt;
    rankBonusCoeff: 100 + rankBonus,&lt;br /&gt;
    defensePercent: Math.floor(defensePercent),&lt;br /&gt;
    damageBonusCoeff: damageBonus,&lt;br /&gt;
    empireMalusCoeff: 10 - empireMalus,&lt;br /&gt;
    sungMaStrBonusCoeff: 10000 + sungMaStrBonus,&lt;br /&gt;
    sungmaStrMalusCoeff: sungmaStrMalus,&lt;br /&gt;
    whiteDragonElixirCoeff: 100 + whiteDragonElixir,&lt;br /&gt;
    steelDragonElixirCoeff: 100 - steelDragonElixir,&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  criticalHitPercentage = Math.min(criticalHitPercentage, 100);&lt;br /&gt;
  piercingHitPercentage = Math.min(piercingHitPercentage, 100);&lt;br /&gt;
&lt;br /&gt;
  var damagesTypeCombinaison = [&lt;br /&gt;
    {&lt;br /&gt;
      criticalHit: false,&lt;br /&gt;
      piercingHit: false,&lt;br /&gt;
      weight:&lt;br /&gt;
        (100 - criticalHitPercentage) *&lt;br /&gt;
        (100 - piercingHitPercentage) *&lt;br /&gt;
        (100 - missPercentage),&lt;br /&gt;
      name: &amp;quot;normalHit&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      criticalHit: true,&lt;br /&gt;
      piercingHit: false,&lt;br /&gt;
      weight:&lt;br /&gt;
        criticalHitPercentage *&lt;br /&gt;
        (100 - piercingHitPercentage) *&lt;br /&gt;
        (100 - missPercentage),&lt;br /&gt;
      name: &amp;quot;criticalHit&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      criticalHit: false,&lt;br /&gt;
      piercingHit: true,&lt;br /&gt;
      weight:&lt;br /&gt;
        (100 - criticalHitPercentage) *&lt;br /&gt;
        piercingHitPercentage *&lt;br /&gt;
        (100 - missPercentage),&lt;br /&gt;
      name: &amp;quot;piercingHit&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      criticalHit: true,&lt;br /&gt;
      piercingHit: true,&lt;br /&gt;
      weight:&lt;br /&gt;
        criticalHitPercentage * piercingHitPercentage * (100 - missPercentage),&lt;br /&gt;
      name: &amp;quot;criticalPiercingHit&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
  ];&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    attacker: attacker,&lt;br /&gt;
    victim: victim,&lt;br /&gt;
    attackFactor: calcAttackFactor(attacker, victim),&lt;br /&gt;
    mainAttackValue: calcMainAttackValue(attacker),&lt;br /&gt;
    attackValues: calcAttackValues(attacker),&lt;br /&gt;
    bonusValues: bonusValues,&lt;br /&gt;
    damagesTypeCombinaison: damagesTypeCombinaison,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateBattleValues(battleValues, skillFormula, skillInfo) {&lt;br /&gt;
  var weaponBonus = 0;&lt;br /&gt;
  var skillWard = 0;&lt;br /&gt;
  var skillBonus = 0;&lt;br /&gt;
  var skillBonusByBonus = 0;&lt;br /&gt;
  var { attacker: attacker, bonusValues: bonusValues } = battleValues;&lt;br /&gt;
  var {&lt;br /&gt;
    range: [minVariation, maxVariation],&lt;br /&gt;
  } = skillInfo;&lt;br /&gt;
  var variationLength = maxVariation - minVariation + 1;&lt;br /&gt;
&lt;br /&gt;
  if (skillInfo.hasOwnProperty(&amp;quot;weaponBonus&amp;quot;)) {&lt;br /&gt;
    var [weaponType, weaponBonusValue] = skillInfo.weaponBonus;&lt;br /&gt;
&lt;br /&gt;
    if (weaponType === attacker.weapon.type) {&lt;br /&gt;
      weaponBonus = weaponBonusValue;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillInfo.skillBonus) {&lt;br /&gt;
    skillBonus = skillInfo.skillBonus;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillInfo.skillWard) {&lt;br /&gt;
    skillWard = skillInfo.skillWard;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillInfo.skillBonusByBonus) {&lt;br /&gt;
    skillBonusByBonus = skillInfo.skillBonusByBonus;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillInfo.removeWeaponReduction) {&lt;br /&gt;
    bonusValues.weaponDefenseCoeff = 100;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  bonusValues.weaponBonusCoeff = 100 + weaponBonus;&lt;br /&gt;
  bonusValues.skillWardCoeff = 1 - skillWard / 100;&lt;br /&gt;
  bonusValues.skillBonusCoeff = 1 + skillBonus / 100;&lt;br /&gt;
  bonusValues.skillBonusByBonusCoeff = 100 + skillBonusByBonus;&lt;br /&gt;
&lt;br /&gt;
  battleValues.skillFormula = skillFormula;&lt;br /&gt;
  battleValues.skillRange = skillInfo.range;&lt;br /&gt;
  battleValues.attackValues.totalCardinal *= variationLength;&lt;br /&gt;
  battleValues.attackValues.possibleDamagesCount *= variationLength;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcWeights(minValue, maxValue, minInterval) {&lt;br /&gt;
  var firstWeightLimit = minValue + minInterval - 1;&lt;br /&gt;
  var lastWeightsLimit = maxValue - minInterval + 1;&lt;br /&gt;
  var weights = [];&lt;br /&gt;
&lt;br /&gt;
  for (var value = minValue; value &amp;lt; firstWeightLimit; value++) {&lt;br /&gt;
    weights.push(value - minValue + 1);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (var value = firstWeightLimit; value &amp;lt;= lastWeightsLimit; value++) {&lt;br /&gt;
    weights.push(minInterval);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (var value = lastWeightsLimit + 1; value &amp;lt;= maxValue; value++) {&lt;br /&gt;
    weights.push(maxValue - value + 1);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return weights;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcBlessingBonus(skillPowerTable, victim) {&lt;br /&gt;
  if (victim.isBlessed !== &amp;quot;on&amp;quot;) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var int = victim.intBlessing;&lt;br /&gt;
  var dex = victim.dexBlessing;&lt;br /&gt;
  var skillPower = getSkillPower(victim[&amp;quot;skillBlessing&amp;quot;], skillPowerTable);&lt;br /&gt;
&lt;br /&gt;
  if (!skillPower) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var blessingBonus = floorMultiplication(&lt;br /&gt;
    ((int * 0.3 + 5) * (2 * skillPower + 0.5) + 0.3 * dex) / (skillPower + 2.3),&lt;br /&gt;
    1&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  if (victim.class === &amp;quot;dragon&amp;quot; &amp;amp;&amp;amp; isChecked(ictim.blessingOnself)) {&lt;br /&gt;
    blessingBonus = floorMultiplication(blessingBonus, 1.1);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return blessingBonus;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSkillFormula(battle, skillId, battleValues, removeSkillVariation) {&lt;br /&gt;
  var { attacker, victim, attackFactor } = battleValues;&lt;br /&gt;
  var skillPowerTable = battle.constants.skillPowerTable;&lt;br /&gt;
&lt;br /&gt;
  var skillFormula;&lt;br /&gt;
  var skillInfo = { range: [0, 0] };&lt;br /&gt;
&lt;br /&gt;
  var { class: attackerClass, level: lv, vit, str, int, dex } = attacker;&lt;br /&gt;
&lt;br /&gt;
  if (skillId &amp;lt;= 9) {&lt;br /&gt;
    var skillPower = getSkillPower(&lt;br /&gt;
      attacker[&amp;quot;attackSkill&amp;quot; + skillId],&lt;br /&gt;
      skillPowerTable&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    var improvedBySkillBonus = false;&lt;br /&gt;
    var improvedByBonus = false;&lt;br /&gt;
&lt;br /&gt;
    if (attackerClass === &amp;quot;body&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Triple lacération&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.1 * atk + (0.5 * atk + 1.5 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Moulinet à l'épée&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              3 * atk + (0.8 * atk + 5 * str + 3 * dex + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Accélération&lt;br /&gt;
        case 5:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * atk + (atk + dex * 3 + str * 7 + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Volonté de vivre&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              (3 * atk + (atk + 1.5 * str) * skillPower) * 1.07,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          break;&lt;br /&gt;
        // Tremblement de terre&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              3 * atk +&lt;br /&gt;
                (0.9 * atk + variation + 5 * str + 3 * dex + lv) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;mental&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Attaque de l'esprit&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2.3 * atk + (4 * atk + 4 * str + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Attaque de la paume&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2.3 * atk + (3 * atk + 4 * str + 3 * vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Charge&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * atk + (2 * atk + 2 * dex + 2 * vit + 4 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          break;&lt;br /&gt;
        // Coup d'épée&lt;br /&gt;
        case 5:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * atk + (atk + 3 * dex + 5 * str + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Orbe de l'épée&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              (2 * atk + (2 * atk + 2 * dex + 2 * vit + 4 * str) * skillPower) *&lt;br /&gt;
                1.1,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          break;&lt;br /&gt;
        // Tremblement de terre&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              3 * atk +&lt;br /&gt;
                (0.9 * atk + variation + 5 * str + 3 * dex + lv) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;blade_fight&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Embuscade&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk + (1.2 * atk + variation + 4 * dex + 4 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [1, 50];&lt;br /&gt;
          skillInfo.range = [500, 700];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Attaque rapide&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk + (1.6 * atk + variation + 7 * dex + 7 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [1, 35];&lt;br /&gt;
          skillInfo.range = [200, 300];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Dague filante&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * atk + (0.5 * atk + 9 * dex + 7 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Brume empoisonnée&lt;br /&gt;
        case 5:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * lv + (atk + 3 * str + 18 * dex) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Poison insidieux&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              (2 * lv + (atk + 3 * str + 18 * dex) * skillPower) * 1.1,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          break;&lt;br /&gt;
        // Étoiles brillantes&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk + (1.7 * atk + variation + 6 * dex + 5 * lv) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;archery&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Tir à répétition&lt;br /&gt;
        // case 1:&lt;br /&gt;
        //   skillFormula = function (atk) {&lt;br /&gt;
        //     return floorMultiplication(&lt;br /&gt;
        //       atk + 0.2 * atk * Math.floor(2 + 6 * skillPower) + (0.8 * atk + 8 * dex * attackFactor + 2 * int) * skillPower,&lt;br /&gt;
        //       1&lt;br /&gt;
        //     );&lt;br /&gt;
        //   };&lt;br /&gt;
        //   improvedByBonus = true;&lt;br /&gt;
        //   break;&lt;br /&gt;
        // Pluie de flèches&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk + (1.7 * atk + 5 * dex + str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Flèche de feu&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.5 * atk + (2.6 * atk + 0.9 * int + variation) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [100, 300];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Foulée de plume&lt;br /&gt;
        case 4:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              (3 * dex + 200 + 2 * str + 2 * int) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.removeWeaponReduction = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Flèche empoisonnée&lt;br /&gt;
        case 5:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk +&lt;br /&gt;
                (1.4 * atk + variation + 7 * dex + 4 * str + 4 * int) *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [100, 200];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Coup étincelant&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              (atk +&lt;br /&gt;
                (1.2 * atk + variation + 6 * dex + 3 * str + 3 * int) *&lt;br /&gt;
                  skillPower) *&lt;br /&gt;
                1.2,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [100, 200];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Tir tempête&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.9 * atk + (2.6 * atk + variation) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;weaponary&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Toucher brûlant&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk +&lt;br /&gt;
                2 * lv +&lt;br /&gt;
                2 * int +&lt;br /&gt;
                (2 * atk + 4 * str + 14 * int) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Tourbillon du dragon&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.1 * atk +&lt;br /&gt;
                2 * lv +&lt;br /&gt;
                2 * int +&lt;br /&gt;
                (1.5 * atk + str + 12 * int) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Contre-sort&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              40 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                2 * int +&lt;br /&gt;
                (10 * int + 7 * mav + variation) * attackFactor * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [50, 100];&lt;br /&gt;
          break;&lt;br /&gt;
        // Coup démoniaque&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.9 * atk + (2.6 * atk + variation) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;black_magic&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Attaque des ténèbres&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              40 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                2 * int +&lt;br /&gt;
                (13 * int + 6 * mav + variation) * attackFactor * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [50, 100];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Attaque de flammes&lt;br /&gt;
        // case 2:&lt;br /&gt;
        //   skillFormula = function (mav, variation) {&lt;br /&gt;
        //     return floorMultiplication(&lt;br /&gt;
        //       5 * lv + 2 * int + (7 * int + 8 * mav + 4 * str + 2 * vit + variation) * skillPower,&lt;br /&gt;
        //       1&lt;br /&gt;
        //     );&lt;br /&gt;
        //   };&lt;br /&gt;
        //   skillInfo.range = [180, 100];&lt;br /&gt;
        //   improvedByBonus = true;&lt;br /&gt;
        //   break;&lt;br /&gt;
        // Esprit de flammes&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              30 +&lt;br /&gt;
                2 * lv +&lt;br /&gt;
                2 * int +&lt;br /&gt;
                (7 * int + 6 * mav + variation) * attackFactor * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [200, 500];&lt;br /&gt;
          break;&lt;br /&gt;
        // Frappe de l'esprit&lt;br /&gt;
        // case 5:&lt;br /&gt;
        //   skillFormula = function (mav, variation) {&lt;br /&gt;
        //     return floorMultiplication(&lt;br /&gt;
        //       40 + 2 * lv + 2 * int + (2 * vit + 2 * dex + 13 * int + 6 * mav + variation) * attackFactor * skillPower,&lt;br /&gt;
        //       1&lt;br /&gt;
        //     );&lt;br /&gt;
        //   };&lt;br /&gt;
        //   skillInfo.range = [180, 200];&lt;br /&gt;
        //   break;&lt;br /&gt;
        // Orbe des ténèbres&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (mav) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              120 +&lt;br /&gt;
                6 * lv +&lt;br /&gt;
                (5 * vit + 5 * dex + 29 * int + 9 * mav) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Vague mortelle&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              120 +&lt;br /&gt;
                6 * lv +&lt;br /&gt;
                (5 * vit + 5 * dex + 30 * int + variation + 9 * mav) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;dragon&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Talisman volant&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (mav) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              70 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                (18 * int + 7 * str + 5 * mav + 50) * attackFactor * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [4, 10];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Dragon chassant&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (mav) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              60 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                (16 * int + 6 * dex + 6 * mav + 120) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [4, 10];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Rugissement du dragon&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (mav) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              70 +&lt;br /&gt;
                3 * lv +&lt;br /&gt;
                (20 * int + 3 * str + 10 * mav + 100) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [4, 10];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Météore&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              120 +&lt;br /&gt;
                6 * lv +&lt;br /&gt;
                (5 * vit + 5 * dex + 30 * int + variation + 9 * mav) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;heal&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Jet de foudre&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              60 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                (8 * int + 2 * dex + 8 * mav + variation) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [6, 10];&lt;br /&gt;
          skillInfo.range = [5 * int, 15 * int];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Invocation de foudre&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              40 +&lt;br /&gt;
                4 * lv +&lt;br /&gt;
                (13 * int + 2 * str + 10 * mav + variation) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [6, 10];&lt;br /&gt;
          skillInfo.range = [5 * int, 16 * int];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Griffe de foudre&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              50 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                (8 * int + 2 * str + 8 * mav + variation) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 800];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;lycan&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Déchiqueter&lt;br /&gt;
        // case 1:&lt;br /&gt;
        //   skillFormula = function (atk) {&lt;br /&gt;
        //     return floorMultiplication(&lt;br /&gt;
        //       1.1 * atk + (0.3 * atk + 1.5 * str) * skillPower,&lt;br /&gt;
        //       1&lt;br /&gt;
        //     );&lt;br /&gt;
        //   };&lt;br /&gt;
        //   skillInfo.weaponBonus = [5, 54];&lt;br /&gt;
        //   improvedByBonus = true;&lt;br /&gt;
        //   break;&lt;br /&gt;
        // Souffle de loup&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * atk + (atk + 3 * dex + 5 * str + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [5, 35];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Bond de loup&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk + (1.6 * atk + 200 + 7 * dex + 7 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [5, 35];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Griffe de loup&lt;br /&gt;
        case 4:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              3 * atk + (0.8 * atk + 6 * str + 2 * dex + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Tempête cinglante&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.8 * atk +&lt;br /&gt;
                (atk + 6 * dex + variation + 3 * str + lv) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
    if (improvedBySkillBonus) {&lt;br /&gt;
      skillInfo.skillBonus =&lt;br /&gt;
        16 * getSkillPower(attacker.skillBonus, skillPowerTable);&lt;br /&gt;
&lt;br /&gt;
      var skillWardChoice = victim.skillWardChoice;&lt;br /&gt;
&lt;br /&gt;
      if (skillWardChoice &amp;amp;&amp;amp; skillWardChoice === attackerClass) {&lt;br /&gt;
        skillInfo.skillWard =&lt;br /&gt;
          24 * getSkillPower(victim.skillWard, skillPowerTable);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (improvedByBonus) {&lt;br /&gt;
      skillInfo.skillBonusByBonus = attacker[&amp;quot;skillBonus&amp;quot; + skillId];&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (removeSkillVariation) {&lt;br /&gt;
      var averageVariation = (skillInfo.range[0] + skillInfo.range[0]) / 2;&lt;br /&gt;
      skillInfo.range = [averageVariation, averageVariation];&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    var skillPower = getSkillPower(&lt;br /&gt;
      attacker[&amp;quot;horseSkill&amp;quot; + skillId],&lt;br /&gt;
      skillPowerTable&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    switch (skillId) {&lt;br /&gt;
      // Combat équestre&lt;br /&gt;
      case 137:&lt;br /&gt;
        skillFormula = function (atk) {&lt;br /&gt;
          return floorMultiplication(atk + 2 * atk * skillPower, 1);&lt;br /&gt;
        };&lt;br /&gt;
        break;&lt;br /&gt;
      // Charge à cheval&lt;br /&gt;
      case 138:&lt;br /&gt;
        skillFormula = function (atk) {&lt;br /&gt;
          return floorMultiplication(&lt;br /&gt;
            2.4 * (200 + 1.5 * lv) + 600 * skillPower,&lt;br /&gt;
            1&lt;br /&gt;
          );&lt;br /&gt;
        };&lt;br /&gt;
        break;&lt;br /&gt;
      // Vague de Pouvoir&lt;br /&gt;
      case 139:&lt;br /&gt;
        skillFormula = function (atk) {&lt;br /&gt;
          return floorMultiplication(&lt;br /&gt;
            2 * (200 + 1.5 * lv) + 600 * skillPower,&lt;br /&gt;
            1&lt;br /&gt;
          );&lt;br /&gt;
        };&lt;br /&gt;
        break;&lt;br /&gt;
      // Grêle de flèches&lt;br /&gt;
      case 140:&lt;br /&gt;
        skillFormula = function (atk) {&lt;br /&gt;
          return floorMultiplication(atk + 2 * atk * skillPower, 1);&lt;br /&gt;
        };&lt;br /&gt;
        break;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  updateBattleValues(battleValues, skillFormula, skillInfo);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcMagicAttackValueAugmentation(&lt;br /&gt;
  magicAttackValueWeapon,&lt;br /&gt;
  magicAttackValueBonus&lt;br /&gt;
) {&lt;br /&gt;
  if (magicAttackValueBonus) {&lt;br /&gt;
    return Math.max(&lt;br /&gt;
      1,&lt;br /&gt;
      0.0025056 *&lt;br /&gt;
        magicAttackValueBonus ** 0.602338 *&lt;br /&gt;
        magicAttackValueWeapon ** 1.20476&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
  return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getMagicAttackValueAugmentation(&lt;br /&gt;
  minMagicAttackValue,&lt;br /&gt;
  maxMagicAttackValue,&lt;br /&gt;
  magicAttackValueBonus&lt;br /&gt;
) {&lt;br /&gt;
  var magicAttackValueAugmentation = [];&lt;br /&gt;
&lt;br /&gt;
  for (&lt;br /&gt;
    var magicAttackValue = minMagicAttackValue;&lt;br /&gt;
    magicAttackValue &amp;lt;= maxMagicAttackValue;&lt;br /&gt;
    magicAttackValue++&lt;br /&gt;
  ) {&lt;br /&gt;
    magicAttackValueAugmentation.push(&lt;br /&gt;
      calcMagicAttackValueAugmentation(magicAttackValue, magicAttackValueBonus)&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return magicAttackValueAugmentation;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcPhysicalDamages(battleValues) {&lt;br /&gt;
  var {&lt;br /&gt;
    attackFactor,&lt;br /&gt;
    mainAttackValue,&lt;br /&gt;
    attackValues: { minAttackValue, maxAttackValue, attackValueOther, weights },&lt;br /&gt;
    bonusValues,&lt;br /&gt;
    damagesTypeCombinaison,&lt;br /&gt;
  } = battleValues;&lt;br /&gt;
&lt;br /&gt;
  var damagesWeightedByType = {};&lt;br /&gt;
&lt;br /&gt;
  if (bonusValues.missPercentage) {&lt;br /&gt;
    damagesWeightedByType.miss = bonusValues.missPercentage / 100;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (var damagesType of damagesTypeCombinaison) {&lt;br /&gt;
    if (!damagesType.weight) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var damagesWeighted = {};&lt;br /&gt;
    damagesWeightedByType[damagesType.name] = damagesWeighted;&lt;br /&gt;
&lt;br /&gt;
    for (&lt;br /&gt;
      var attackValue = minAttackValue;&lt;br /&gt;
      attackValue &amp;lt;= maxAttackValue;&lt;br /&gt;
      attackValue++&lt;br /&gt;
    ) {&lt;br /&gt;
      var weight = weights[attackValue - minAttackValue] * damagesType.weight;&lt;br /&gt;
&lt;br /&gt;
      var secondaryAttackValue = 2 * attackValue + attackValueOther;&lt;br /&gt;
      var rawDamages =&lt;br /&gt;
        mainAttackValue +&lt;br /&gt;
        floorMultiplication(attackFactor, secondaryAttackValue);&lt;br /&gt;
&lt;br /&gt;
      var damagesWithPrimaryBonuses = calcDamageWithPrimaryBonuses(&lt;br /&gt;
        rawDamages,&lt;br /&gt;
        bonusValues&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      var minPiercingDamages =&lt;br /&gt;
        damagesWithPrimaryBonuses -&lt;br /&gt;
        bonusValues.defenseBoost +&lt;br /&gt;
        bonusValues.defenseMarriage;&lt;br /&gt;
&lt;br /&gt;
      if (minPiercingDamages &amp;lt;= 2) {&lt;br /&gt;
        for (var damages = 1; damages &amp;lt;= 5; damages++) {&lt;br /&gt;
          var finalDamages = calcDamageWithSecondaryBonuses(&lt;br /&gt;
            damages,&lt;br /&gt;
            bonusValues,&lt;br /&gt;
            damagesType,&lt;br /&gt;
            minPiercingDamages,&lt;br /&gt;
            damagesWithPrimaryBonuses&lt;br /&gt;
          );&lt;br /&gt;
&lt;br /&gt;
          addKeyValue(damagesWeighted, finalDamages, weight / 5);&lt;br /&gt;
        }&lt;br /&gt;
      } else {&lt;br /&gt;
        var finalDamages = calcDamageWithSecondaryBonuses(&lt;br /&gt;
          minPiercingDamages,&lt;br /&gt;
          bonusValues,&lt;br /&gt;
          damagesType,&lt;br /&gt;
          minPiercingDamages,&lt;br /&gt;
          damagesWithPrimaryBonuses&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        addKeyValue(damagesWeighted, finalDamages, weight);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return damagesWeightedByType;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcPhysicalSkillDamages(battleValues) {&lt;br /&gt;
  var {&lt;br /&gt;
    attackFactor,&lt;br /&gt;
    mainAttackValue,&lt;br /&gt;
    attackValues: { minAttackValue, maxAttackValue, attackValueOther, weights },&lt;br /&gt;
    bonusValues,&lt;br /&gt;
    damagesTypeCombinaison,&lt;br /&gt;
    skillFormula,&lt;br /&gt;
    skillRange: [minVariation, maxVariation],&lt;br /&gt;
  } = battleValues;&lt;br /&gt;
&lt;br /&gt;
  var damagesWeightedByType = {};&lt;br /&gt;
&lt;br /&gt;
  for (var damagesType of damagesTypeCombinaison) {&lt;br /&gt;
    if (!damagesType.weight) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var damagesWeighted = {};&lt;br /&gt;
    var savedDamages = {};&lt;br /&gt;
&lt;br /&gt;
    damagesWeightedByType[damagesType.name] = damagesWeighted;&lt;br /&gt;
&lt;br /&gt;
    for (&lt;br /&gt;
      var attackValue = minAttackValue;&lt;br /&gt;
      attackValue &amp;lt;= maxAttackValue;&lt;br /&gt;
      attackValue++&lt;br /&gt;
    ) {&lt;br /&gt;
      var weight = weights[attackValue - minAttackValue] * damagesType.weight;&lt;br /&gt;
&lt;br /&gt;
      var secondaryAttackValue = 2 * attackValue + attackValueOther;&lt;br /&gt;
      var rawDamages =&lt;br /&gt;
        mainAttackValue +&lt;br /&gt;
        floorMultiplication(attackFactor, secondaryAttackValue);&lt;br /&gt;
&lt;br /&gt;
      var damagesWithPrimaryBonuses = calcDamageWithPrimaryBonuses(&lt;br /&gt;
        rawDamages,&lt;br /&gt;
        bonusValues&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      for (&lt;br /&gt;
        var variation = minVariation;&lt;br /&gt;
        variation &amp;lt;= maxVariation;&lt;br /&gt;
        variation++&lt;br /&gt;
      ) {&lt;br /&gt;
        if (damagesWithPrimaryBonuses &amp;lt;= 2) {&lt;br /&gt;
          for (var damages = 1; damages &amp;lt;= 5; damages++) {&lt;br /&gt;
            damages *= bonusValues.useDamages;&lt;br /&gt;
&lt;br /&gt;
            var damagesWithFormula = skillFormula(damages, variation);&lt;br /&gt;
&lt;br /&gt;
            damagesWithFormula = Math.floor(&lt;br /&gt;
              (damagesWithFormula * bonusValues.weaponBonusCoeff) / 100&lt;br /&gt;
            );&lt;br /&gt;
&lt;br /&gt;
            var finalDamages = calcSkillDamageWithSecondaryBonuses(&lt;br /&gt;
              damagesWithFormula,&lt;br /&gt;
              bonusValues,&lt;br /&gt;
              damagesType,&lt;br /&gt;
              damagesWithPrimaryBonuses&lt;br /&gt;
            );&lt;br /&gt;
&lt;br /&gt;
            addKeyValue(damagesWeighted, finalDamages, weight / 5);&lt;br /&gt;
          }&lt;br /&gt;
        } else {&lt;br /&gt;
          damagesWithPrimaryBonuses *= bonusValues.useDamages;&lt;br /&gt;
&lt;br /&gt;
          var damagesWithFormula = skillFormula(&lt;br /&gt;
            damagesWithPrimaryBonuses,&lt;br /&gt;
            variation&lt;br /&gt;
          );&lt;br /&gt;
&lt;br /&gt;
          if (savedDamages.hasOwnProperty(damagesWithFormula)) {&lt;br /&gt;
            var finalDamages = savedDamages[damagesWithFormula];&lt;br /&gt;
            damagesWeighted[finalDamages] += weight;&lt;br /&gt;
            continue;&lt;br /&gt;
          }&lt;br /&gt;
&lt;br /&gt;
          var finalDamages = Math.floor(&lt;br /&gt;
            (damagesWithFormula * bonusValues.weaponBonusCoeff) / 100&lt;br /&gt;
          );&lt;br /&gt;
&lt;br /&gt;
          finalDamages = calcSkillDamageWithSecondaryBonuses(&lt;br /&gt;
            finalDamages,&lt;br /&gt;
            bonusValues,&lt;br /&gt;
            damagesType,&lt;br /&gt;
            damagesWithPrimaryBonuses&lt;br /&gt;
          );&lt;br /&gt;
&lt;br /&gt;
          savedDamages[damagesWithFormula] = finalDamages;&lt;br /&gt;
          addKeyValue(damagesWeighted, finalDamages, weight);&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return damagesWeightedByType;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcMagicSkillDamages(battleValues) {&lt;br /&gt;
  var {&lt;br /&gt;
    attackValues: {&lt;br /&gt;
      minMagicAttackValue,&lt;br /&gt;
      maxMagicAttackValue,&lt;br /&gt;
      magicAttackValueAugmentation,&lt;br /&gt;
      weights,&lt;br /&gt;
    },&lt;br /&gt;
    bonusValues,&lt;br /&gt;
    damagesTypeCombinaison,&lt;br /&gt;
    skillFormula,&lt;br /&gt;
    skillRange: [minVariation, maxVariation],&lt;br /&gt;
  } = battleValues;&lt;br /&gt;
&lt;br /&gt;
  var damagesWeightedByType = {};&lt;br /&gt;
&lt;br /&gt;
  for (var damagesType of damagesTypeCombinaison) {&lt;br /&gt;
    if (!damagesType.weight) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var damagesWeighted = {};&lt;br /&gt;
    var savedDamages = {};&lt;br /&gt;
&lt;br /&gt;
    damagesWeightedByType[damagesType.name] = damagesWeighted;&lt;br /&gt;
&lt;br /&gt;
    for (&lt;br /&gt;
      var magicAttackValue = minMagicAttackValue;&lt;br /&gt;
      magicAttackValue &amp;lt;= maxMagicAttackValue;&lt;br /&gt;
      magicAttackValue++&lt;br /&gt;
    ) {&lt;br /&gt;
      var index = magicAttackValue - minMagicAttackValue;&lt;br /&gt;
      var weight = weights[index] * damagesType.weight;&lt;br /&gt;
&lt;br /&gt;
      for (&lt;br /&gt;
        var variation = minVariation;&lt;br /&gt;
        variation &amp;lt;= maxVariation;&lt;br /&gt;
        variation++&lt;br /&gt;
      ) {&lt;br /&gt;
        var rawDamages = skillFormula(&lt;br /&gt;
          magicAttackValue + magicAttackValueAugmentation[index],&lt;br /&gt;
          variation&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        if (savedDamages.hasOwnProperty(rawDamages)) {&lt;br /&gt;
          var finalDamages = savedDamages[rawDamages];&lt;br /&gt;
          damagesWeighted[finalDamages] += weight;&lt;br /&gt;
          continue;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var damagesWithPrimaryBonuses = Math.floor(&lt;br /&gt;
          (rawDamages * bonusValues.weaponBonusCoeff) / 100&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        damagesWithPrimaryBonuses = calcDamageWithPrimaryBonuses(&lt;br /&gt;
          damagesWithPrimaryBonuses,&lt;br /&gt;
          bonusValues&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        if (damagesWithPrimaryBonuses &amp;lt;= 2) {&lt;br /&gt;
          for (var damages = 1; damages &amp;lt;= 5; damages++) {&lt;br /&gt;
            var finalDamages = calcSkillDamageWithSecondaryBonuses(&lt;br /&gt;
              damages,&lt;br /&gt;
              bonusValues,&lt;br /&gt;
              damagesType,&lt;br /&gt;
              damagesWithPrimaryBonuses&lt;br /&gt;
            );&lt;br /&gt;
            addKeyValue(damagesWeighted, finalDamages, weight / 5);&lt;br /&gt;
          }&lt;br /&gt;
        } else {&lt;br /&gt;
          var finalDamages = calcSkillDamageWithSecondaryBonuses(&lt;br /&gt;
            damagesWithPrimaryBonuses,&lt;br /&gt;
            bonusValues,&lt;br /&gt;
            damagesType,&lt;br /&gt;
            damagesWithPrimaryBonuses&lt;br /&gt;
          );&lt;br /&gt;
&lt;br /&gt;
          savedDamages[rawDamages] = finalDamages;&lt;br /&gt;
          addKeyValue(damagesWeighted, finalDamages, weight);&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return damagesWeightedByType;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcDamages(&lt;br /&gt;
  attacker,&lt;br /&gt;
  victim,&lt;br /&gt;
  attackType,&lt;br /&gt;
  battle,&lt;br /&gt;
  removeSkillVariation&lt;br /&gt;
) {&lt;br /&gt;
  var damagesCalculator, skillId, skillType;&lt;br /&gt;
&lt;br /&gt;
  if (attackType === &amp;quot;physical&amp;quot;) {&lt;br /&gt;
    damagesCalculator = calcPhysicalDamages;&lt;br /&gt;
  } else if (attackType.startsWith(&amp;quot;attackSkill&amp;quot;)) {&lt;br /&gt;
    skillId = Number(attackType.split(&amp;quot;attackSkill&amp;quot;)[1]);&lt;br /&gt;
&lt;br /&gt;
    if (isMagicClass(attacker) || isDispell(attacker, skillId)) {&lt;br /&gt;
      skillType = &amp;quot;magic&amp;quot;;&lt;br /&gt;
      damagesCalculator = calcMagicSkillDamages;&lt;br /&gt;
    } else {&lt;br /&gt;
      skillType = &amp;quot;physical&amp;quot;;&lt;br /&gt;
      damagesCalculator = calcPhysicalSkillDamages;&lt;br /&gt;
    }&lt;br /&gt;
  } else if (attackType.startsWith(&amp;quot;horseSkill&amp;quot;)) {&lt;br /&gt;
    skillType = &amp;quot;physical&amp;quot;;&lt;br /&gt;
    skillId = Number(attackType.split(&amp;quot;horseSkill&amp;quot;)[1]);&lt;br /&gt;
    damagesCalculator = calcPhysicalSkillDamages;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var battleValues = createBattleValues(attacker, victim, battle, skillType);&lt;br /&gt;
&lt;br /&gt;
  if (skillId) {&lt;br /&gt;
    getSkillFormula(battle, skillId, battleValues, removeSkillVariation);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var {&lt;br /&gt;
    attackValues: { totalCardinal, possibleDamagesCount },&lt;br /&gt;
  } = battleValues;&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    damagesWeightedByType: damagesCalculator(battleValues),&lt;br /&gt;
    totalCardinal: totalCardinal,&lt;br /&gt;
    possibleDamagesCount: possibleDamagesCount,&lt;br /&gt;
    skillType: skillType,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function damagesWithoutVariation(&lt;br /&gt;
  attacker,&lt;br /&gt;
  victim,&lt;br /&gt;
  attackType,&lt;br /&gt;
  battle,&lt;br /&gt;
  characters&lt;br /&gt;
) {&lt;br /&gt;
  startDamagesTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
  var {&lt;br /&gt;
    damagesWeightedByType,&lt;br /&gt;
    totalCardinal,&lt;br /&gt;
    possibleDamagesCount,&lt;br /&gt;
    skillType,&lt;br /&gt;
  } = calcDamages(attacker, victim, attackType, battle);&lt;br /&gt;
&lt;br /&gt;
  endDamagesTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
  possibleDamagesCount = displayResults(&lt;br /&gt;
    possibleDamagesCount,&lt;br /&gt;
    totalCardinal,&lt;br /&gt;
    damagesWeightedByType,&lt;br /&gt;
    battle,&lt;br /&gt;
    attacker.name,&lt;br /&gt;
    victim.name&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  endDisplayTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
  displayFightInfo(&lt;br /&gt;
    possibleDamagesCount,&lt;br /&gt;
    endDamagesTime - startDamagesTime,&lt;br /&gt;
    endDisplayTime - endDamagesTime,&lt;br /&gt;
    battle&lt;br /&gt;
  );&lt;br /&gt;
  addPotentialErrorInformation(&lt;br /&gt;
    battle.errorInformation,&lt;br /&gt;
    attacker,&lt;br /&gt;
    victim,&lt;br /&gt;
    skillType,&lt;br /&gt;
    characters&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  hideElement(battle.bonusVariationResultContainer);&lt;br /&gt;
  showElement(battle.fightResultContainer);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function damagesWithVariation(&lt;br /&gt;
  attacker,&lt;br /&gt;
  victim,&lt;br /&gt;
  attackType,&lt;br /&gt;
  battle,&lt;br /&gt;
  entity,&lt;br /&gt;
  entityVariation&lt;br /&gt;
) {&lt;br /&gt;
  startTime = performance.now();&lt;br /&gt;
  var damagesByBonus = [];&lt;br /&gt;
  var augmentationByBonus = [];&lt;br /&gt;
  var {&lt;br /&gt;
    bonusVariationMinValue: minVariation,&lt;br /&gt;
    bonusVariationMaxValue: maxVariation,&lt;br /&gt;
  } = entity;&lt;br /&gt;
  var step = Math.ceil((maxVariation - minVariation + 1) / 500);&lt;br /&gt;
  var simulationCount = 0;&lt;br /&gt;
  var simulationTime;&lt;br /&gt;
&lt;br /&gt;
  for (&lt;br /&gt;
    var bonusValue = minVariation;&lt;br /&gt;
    bonusValue &amp;lt;= maxVariation;&lt;br /&gt;
    bonusValue += step&lt;br /&gt;
  ) {&lt;br /&gt;
    entity[entityVariation] = bonusValue;&lt;br /&gt;
&lt;br /&gt;
    var { damagesWeightedByType, totalCardinal } = calcDamages(&lt;br /&gt;
      copyObject(attacker),&lt;br /&gt;
      copyObject(victim),&lt;br /&gt;
      attackType,&lt;br /&gt;
      battle,&lt;br /&gt;
      true&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    var meanDamages = calcMeanDamages(damagesWeightedByType, totalCardinal);&lt;br /&gt;
&lt;br /&gt;
    if (bonusValue === minVariation) {&lt;br /&gt;
      var firstDamages = Math.max(meanDamages, 1e-3);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    damagesByBonus.push({ x: bonusValue, y: meanDamages });&lt;br /&gt;
    augmentationByBonus.push({&lt;br /&gt;
      x: bonusValue,&lt;br /&gt;
      y: meanDamages / firstDamages - 1,&lt;br /&gt;
    });&lt;br /&gt;
    simulationCount++;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  endTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
  battle.damagesByBonus = damagesByBonus.concat(entityVariation);&lt;br /&gt;
&lt;br /&gt;
  addToBonusVariationChart(&lt;br /&gt;
    damagesByBonus,&lt;br /&gt;
    augmentationByBonus,&lt;br /&gt;
    entity.bonusVariationDisplay,&lt;br /&gt;
    battle.bonusVariationChart&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  simulationCount = battle.numberFormats.default.format(simulationCount);&lt;br /&gt;
  simulationTime = battle.numberFormats.second.format(&lt;br /&gt;
    (endTime - startTime) / 1000&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  battle.simulationCounter.textContent = simulationCount;&lt;br /&gt;
  battle.simulationTime.textContent = simulationTime;&lt;br /&gt;
&lt;br /&gt;
  hideElement(battle.fightResultContainer);&lt;br /&gt;
  showElement(battle.bonusVariationResultContainer);&lt;br /&gt;
&lt;br /&gt;
  if (&lt;br /&gt;
    isChecked(attacker.bonusVariationActivation) &amp;amp;&amp;amp;&lt;br /&gt;
    isChecked(victim.bonusVariationActivation)&lt;br /&gt;
  ) {&lt;br /&gt;
    showElement(battle.errorInformation[&amp;quot;attacker-victim-variation&amp;quot;]);&lt;br /&gt;
  } else {&lt;br /&gt;
    hideElement(battle.errorInformation[&amp;quot;attacker-victim-variation&amp;quot;]);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function changeMonsterValues(monster, instance, attacker) {&lt;br /&gt;
  switch (instance) {&lt;br /&gt;
    case &amp;quot;SungMahiTower&amp;quot;:&lt;br /&gt;
      var sungMahiFloor = 1;&lt;br /&gt;
      var sungMahiStep = 1;&lt;br /&gt;
      var rawDefense = 120;&lt;br /&gt;
&lt;br /&gt;
      if (isPC(attacker)) {&lt;br /&gt;
        sungMahiFloor = attacker.sungMahiFloor;&lt;br /&gt;
        sungMahiStep = attacker.sungMahiStep;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (monster.rank === 5) {&lt;br /&gt;
        monster.level = 121;&lt;br /&gt;
        monster.dex = 75;&lt;br /&gt;
        rawDefense += 1;&lt;br /&gt;
      } else if (monster.rank === 6) {&lt;br /&gt;
        monster.level = 123;&lt;br /&gt;
        monster.dex = 75;&lt;br /&gt;
        rawDefense += 1;&lt;br /&gt;
      } else {&lt;br /&gt;
        monster.level = 120;&lt;br /&gt;
        monster.dex = 68;&lt;br /&gt;
      }&lt;br /&gt;
      monster.vit = 100;&lt;br /&gt;
      monster.rawDefense = rawDefense + (sungMahiStep - 1) * 6;&lt;br /&gt;
      monster.fistDefense = 0;&lt;br /&gt;
      monster.swordDefense = 0;&lt;br /&gt;
      monster.twoHandedSwordDefense = 0;&lt;br /&gt;
      monster.daggerDefense = 0;&lt;br /&gt;
      monster.bellDefense = 0;&lt;br /&gt;
      monster.fanDefense = 0;&lt;br /&gt;
      monster.arrowDefense = 0;&lt;br /&gt;
      monster.clawDefense = 0;&lt;br /&gt;
      monster.magicResistance = 0;&lt;br /&gt;
      monster.fireResistance = -20;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  // Alastor&lt;br /&gt;
  if (monster.vnum === 6790) {&lt;br /&gt;
    monster.iceResistance = 0;&lt;br /&gt;
    monster.iceBonus = 0,&lt;br /&gt;
    monster.lightningResistance = -10;&lt;br /&gt;
    monster.lightningBonus = 65;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createWeapon(weaponVnum) {&lt;br /&gt;
  var weapon = weaponData[weaponVnum];&lt;br /&gt;
  var weaponName = weapon[0];&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    name: weaponName,&lt;br /&gt;
    type: weapon[1],&lt;br /&gt;
    minAttackValue: weapon[2][2],&lt;br /&gt;
    maxAttackValue: weapon[2][3],&lt;br /&gt;
    minMagicAttackValue: weapon[2][0],&lt;br /&gt;
    maxMagicAttackValue: weapon[2][1],&lt;br /&gt;
    upgrades: weapon[3],&lt;br /&gt;
    isSerpent: isValueInArray(&amp;quot;serpent&amp;quot;, weaponName.toLowerCase()),&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createMonster(monsterVnum, attacker) {&lt;br /&gt;
  var monsterAttributes = monsterData[monsterVnum];&lt;br /&gt;
&lt;br /&gt;
  var monster = {&lt;br /&gt;
    vnum: monsterVnum,&lt;br /&gt;
    name: monsterAttributes[36],&lt;br /&gt;
    rank: monsterAttributes[0],&lt;br /&gt;
    race: monsterAttributes[1],&lt;br /&gt;
    attack: monsterAttributes[2],&lt;br /&gt;
    level: monsterAttributes[3],&lt;br /&gt;
    type: monsterAttributes[4],&lt;br /&gt;
    str: monsterAttributes[5],&lt;br /&gt;
    dex: monsterAttributes[6],&lt;br /&gt;
    vit: monsterAttributes[7],&lt;br /&gt;
    int: monsterAttributes[8],&lt;br /&gt;
    minAttackValue: monsterAttributes[9],&lt;br /&gt;
    maxAttackValue: monsterAttributes[10],&lt;br /&gt;
    rawDefense: monsterAttributes[11],&lt;br /&gt;
    criticalHit: monsterAttributes[12],&lt;br /&gt;
    piercingHit: monsterAttributes[13],&lt;br /&gt;
    fistDefense: monsterAttributes[14],&lt;br /&gt;
    swordDefense: monsterAttributes[15],&lt;br /&gt;
    twoHandedSwordDefense: monsterAttributes[16],&lt;br /&gt;
    daggerDefense: monsterAttributes[17],&lt;br /&gt;
    bellDefense: monsterAttributes[18],&lt;br /&gt;
    fanDefense: monsterAttributes[19],&lt;br /&gt;
    arrowDefense: monsterAttributes[20],&lt;br /&gt;
    clawDefense: monsterAttributes[21],&lt;br /&gt;
    fireResistance: monsterAttributes[22],&lt;br /&gt;
    lightningResistance: monsterAttributes[23],&lt;br /&gt;
    magicResistance: monsterAttributes[24],&lt;br /&gt;
    windResistance: monsterAttributes[25],&lt;br /&gt;
    lightningBonus: monsterAttributes[26],&lt;br /&gt;
    fireBonus: monsterAttributes[27],&lt;br /&gt;
    iceBonus: monsterAttributes[28],&lt;br /&gt;
    windBonus: monsterAttributes[29],&lt;br /&gt;
    earthBonus: monsterAttributes[30],&lt;br /&gt;
    darknessBonus: monsterAttributes[31],&lt;br /&gt;
    darknessResistance: monsterAttributes[32],&lt;br /&gt;
    iceResistance: monsterAttributes[33],&lt;br /&gt;
    earthResistance: monsterAttributes[34],&lt;br /&gt;
    damageMultiplier: monsterAttributes[35],&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  // monster.instance = 0;&lt;br /&gt;
&lt;br /&gt;
  // if (attacker &amp;amp;&amp;amp; monster.instance === 0) {&lt;br /&gt;
  //   changeMonsterValues(monster, &amp;quot;SungMahiTower&amp;quot;, attacker);&lt;br /&gt;
  // }&lt;br /&gt;
&lt;br /&gt;
  changeMonsterValues(monster);&lt;br /&gt;
&lt;br /&gt;
  monster.defense = monster.rawDefense + monster.level + monster.vit;&lt;br /&gt;
&lt;br /&gt;
  return monster;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addPotentialErrorInformation(&lt;br /&gt;
  errorInformation,&lt;br /&gt;
  attacker,&lt;br /&gt;
  victim,&lt;br /&gt;
  skillType,&lt;br /&gt;
  characters&lt;br /&gt;
) {&lt;br /&gt;
  for (var error of Object.values(errorInformation)) {&lt;br /&gt;
    hideElement(error);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker)) {&lt;br /&gt;
    if (isRiding(attacker)) {&lt;br /&gt;
      if (attacker.horsePoint === 0) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;horse-level&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
      showElement(errorInformation[&amp;quot;horse-stat&amp;quot;]);&lt;br /&gt;
    } else if (isPolymorph(attacker)) {&lt;br /&gt;
      if (attacker.polymorphPoint === 0) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;polymorph-level&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (&lt;br /&gt;
        (attacker.polymorphPoint &amp;lt;= 39 &amp;amp;&amp;amp; attacker.attackValuePercent &amp;lt;= 199) ||&lt;br /&gt;
        (attacker.polymorphPoint === 40 &amp;amp;&amp;amp; attacker.attackValuePercent &amp;lt;= 299)&lt;br /&gt;
      ) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;polymorph-bonus&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
    if (skillType === &amp;quot;magic&amp;quot;) {&lt;br /&gt;
      if (attacker.magicAttackValue) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;magic-attack-value-bonus&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
      if (victim.magicResistance) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;magic-resistance&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    showElement(errorInformation[&amp;quot;monster-attacker&amp;quot;]);&lt;br /&gt;
    if (isMagicAttacker(attacker) &amp;amp;&amp;amp; victim.magicResistance) {&lt;br /&gt;
      showElement(errorInformation[&amp;quot;magic-resistance&amp;quot;]);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (isPC(victim)) {&lt;br /&gt;
    if (isRiding(victim)) {&lt;br /&gt;
      showElement(errorInformation[&amp;quot;horse-stat&amp;quot;]);&lt;br /&gt;
    } else if (isPolymorph(victim)) {&lt;br /&gt;
      if (attacker.polymorphPoint === 0) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;polymorph-level&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
      showElement(errorInformation[&amp;quot;polymorph-defense&amp;quot;]);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (characters.unsavedChanges) {&lt;br /&gt;
    showElement(errorInformation[&amp;quot;save&amp;quot;]);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function reduceChartPointsListener(battle) {&lt;br /&gt;
  var {&lt;br /&gt;
    reduceChartPointsContainer,&lt;br /&gt;
    reduceChartPoints,&lt;br /&gt;
    numberFormats: { second: numberFormat },&lt;br /&gt;
    displayTime,&lt;br /&gt;
  } = battle;&lt;br /&gt;
&lt;br /&gt;
  reduceChartPoints.addEventListener(&amp;quot;change&amp;quot;, function () {&lt;br /&gt;
    var startDisplayTime = performance.now();&lt;br /&gt;
    var scatterDataByType = battle.scatterDataByType;&lt;br /&gt;
    var {&lt;br /&gt;
      chart,&lt;br /&gt;
      maxPoints,&lt;br /&gt;
      chart: {&lt;br /&gt;
        data: { datasets },&lt;br /&gt;
      },&lt;br /&gt;
    } = battle.damagesChart;&lt;br /&gt;
    var addAnimations = false;&lt;br /&gt;
&lt;br /&gt;
    for (var index = 0; index &amp;lt; datasets.length; index++) {&lt;br /&gt;
      var dataset = datasets[index];&lt;br /&gt;
      var scatterData = scatterDataByType[dataset.name];&lt;br /&gt;
&lt;br /&gt;
      if (dataset.canBeReduced &amp;amp;&amp;amp; reduceChartPoints.checked) {&lt;br /&gt;
        dataset.data = aggregateDamages(scatterData, maxPoints);&lt;br /&gt;
        addAnimations = true;&lt;br /&gt;
      } else {&lt;br /&gt;
        dataset.data = scatterData;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    handleChartAnimations(chart, addAnimations);&lt;br /&gt;
    chart.update();&lt;br /&gt;
&lt;br /&gt;
    displayTime.textContent = numberFormat.format(&lt;br /&gt;
      (performance.now() - startDisplayTime) / 1000&lt;br /&gt;
    );&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  reduceChartPointsContainer.addEventListener(&amp;quot;pointerup&amp;quot;, function (event) {&lt;br /&gt;
    if (event.pointerType === &amp;quot;mouse&amp;quot;) {&lt;br /&gt;
      reduceChartPoints.click();&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function downloadRawDataListener(battle) {&lt;br /&gt;
  var { downLoadRawData, downLoadRawDataVariation } = battle;&lt;br /&gt;
  var fileType = &amp;quot;text/csv;charset=utf-8;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  downLoadRawData.addEventListener(&amp;quot;click&amp;quot;, function () {&lt;br /&gt;
    var damagesWeightedByType = battle.damagesWeightedByType;&lt;br /&gt;
    var filename = &amp;quot;raw_damages.csv&amp;quot;;&lt;br /&gt;
    var csvContent = &amp;quot;damage,probabilities,damageType\n&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    for (var damagesType in damagesWeightedByType) {&lt;br /&gt;
      var damagesWeighted = damagesWeightedByType[damagesType];&lt;br /&gt;
&lt;br /&gt;
      for (var damages in damagesWeighted) {&lt;br /&gt;
        csvContent +=&lt;br /&gt;
          damages + &amp;quot;,&amp;quot; + damagesWeighted[damages] + &amp;quot;,&amp;quot; + damagesType + &amp;quot;\n&amp;quot;;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    downloadData(csvContent, fileType, filename);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  downLoadRawDataVariation.addEventListener(&amp;quot;click&amp;quot;, function () {&lt;br /&gt;
    var damagesByBonus = battle.damagesByBonus;&lt;br /&gt;
    var damagesByBonusLength = damagesByBonus.length;&lt;br /&gt;
    var filename = &amp;quot;damages_variation.csv&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    if (!damagesByBonusLength) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var csvContent =&lt;br /&gt;
      damagesByBonus[damagesByBonusLength - 1] + &amp;quot;,averageDamage\n&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    for (var index = 0; index &amp;lt; damagesByBonusLength - 1; index++) {&lt;br /&gt;
      var row = damagesByBonus[index];&lt;br /&gt;
&lt;br /&gt;
      csvContent += row.x + &amp;quot;,&amp;quot; + row.y + &amp;quot;\n&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    downloadData(csvContent, fileType, filename);&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function displayResults(&lt;br /&gt;
  possibleDamagesCount,&lt;br /&gt;
  totalCardinal,&lt;br /&gt;
  damagesWeightedByType,&lt;br /&gt;
  battle,&lt;br /&gt;
  attackerName,&lt;br /&gt;
  victimName&lt;br /&gt;
) {&lt;br /&gt;
  var [&lt;br /&gt;
    meanDamages,&lt;br /&gt;
    minDamages,&lt;br /&gt;
    maxDamages,&lt;br /&gt;
    scatterDataByType,&lt;br /&gt;
    possibleDamagesCount,&lt;br /&gt;
    uniqueDamagesCount,&lt;br /&gt;
  ] = prepareDamagesData(&lt;br /&gt;
    damagesWeightedByType,&lt;br /&gt;
    possibleDamagesCount,&lt;br /&gt;
    totalCardinal&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  addToDamagesChart(&lt;br /&gt;
    scatterDataByType,&lt;br /&gt;
    battle.damagesChart,&lt;br /&gt;
    battle.reduceChartPoints.checked&lt;br /&gt;
  );&lt;br /&gt;
  updateDamagesChartDescription(&lt;br /&gt;
    battle.uniqueDamagesCounters,&lt;br /&gt;
    uniqueDamagesCount,&lt;br /&gt;
    battle.numberFormats.default&lt;br /&gt;
  );&lt;br /&gt;
  displayFightResults(&lt;br /&gt;
    battle,&lt;br /&gt;
    attackerName,&lt;br /&gt;
    victimName,&lt;br /&gt;
    meanDamages,&lt;br /&gt;
    minDamages,&lt;br /&gt;
    maxDamages&lt;br /&gt;
  );&lt;br /&gt;
  battle.damagesWeightedByType = damagesWeightedByType;&lt;br /&gt;
  battle.scatterDataByType = scatterDataByType;&lt;br /&gt;
&lt;br /&gt;
  return possibleDamagesCount;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function displayFightResults(&lt;br /&gt;
  battle,&lt;br /&gt;
  attackerName,&lt;br /&gt;
  victimName,&lt;br /&gt;
  meanDamages,&lt;br /&gt;
  minDamages,&lt;br /&gt;
  maxDamages&lt;br /&gt;
) {&lt;br /&gt;
  var {&lt;br /&gt;
    tableResultFight,&lt;br /&gt;
    tableResultHistory,&lt;br /&gt;
    attackTypeSelection,&lt;br /&gt;
    savedFights,&lt;br /&gt;
    numberFormats: { default: numberFormat },&lt;br /&gt;
    deleteFightTemplate,&lt;br /&gt;
  } = battle;&lt;br /&gt;
&lt;br /&gt;
  hideElement(tableResultHistory.rows[1]);&lt;br /&gt;
&lt;br /&gt;
  var valuesToDisplay = [&lt;br /&gt;
    attackerName,&lt;br /&gt;
    victimName,&lt;br /&gt;
    attackTypeSelection.options[attackTypeSelection.selectedIndex].textContent,&lt;br /&gt;
    meanDamages,&lt;br /&gt;
    minDamages,&lt;br /&gt;
    maxDamages,&lt;br /&gt;
  ];&lt;br /&gt;
&lt;br /&gt;
  savedFights.push(valuesToDisplay);&lt;br /&gt;
  updateSavedFights(savedFights);&lt;br /&gt;
&lt;br /&gt;
  editTableResultRow(tableResultFight.rows[1], valuesToDisplay, numberFormat);&lt;br /&gt;
  addRowToTableResultHistory(&lt;br /&gt;
    tableResultHistory,&lt;br /&gt;
    valuesToDisplay,&lt;br /&gt;
    deleteFightTemplate,&lt;br /&gt;
    numberFormat&lt;br /&gt;
  );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function displayFightInfo(&lt;br /&gt;
  possibleDamagesCount,&lt;br /&gt;
  damagesTime,&lt;br /&gt;
  displayTime,&lt;br /&gt;
  battle&lt;br /&gt;
) {&lt;br /&gt;
  var container = battle.possibleDamagesCounter.parentElement;&lt;br /&gt;
&lt;br /&gt;
  if (possibleDamagesCount &amp;lt;= 1) {&lt;br /&gt;
    hideElement(container);&lt;br /&gt;
    return;&lt;br /&gt;
  } else {&lt;br /&gt;
    showElement(container);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  possibleDamagesCount =&lt;br /&gt;
    battle.numberFormats.default.format(possibleDamagesCount);&lt;br /&gt;
  damagesTime = battle.numberFormats.second.format(damagesTime / 1000);&lt;br /&gt;
  displayTime = battle.numberFormats.second.format(displayTime / 1000);&lt;br /&gt;
&lt;br /&gt;
  battle.possibleDamagesCounter.textContent = possibleDamagesCount;&lt;br /&gt;
  battle.damagesTime.textContent = damagesTime;&lt;br /&gt;
  battle.displayTime.textContent = displayTime;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isPseudoSaved(characters, pseudo) {&lt;br /&gt;
  return characters.savedCharacters.hasOwnProperty(pseudo);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createBattle(characters, battle) {&lt;br /&gt;
  battle.battleForm.addEventListener(&amp;quot;submit&amp;quot;, function (event) {&lt;br /&gt;
    event.preventDefault();&lt;br /&gt;
&lt;br /&gt;
    // auto save&lt;br /&gt;
    if (characters.unsavedChanges) {&lt;br /&gt;
      characters.saveButton.click();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var battleInfo = new FormData(event.target);&lt;br /&gt;
    var attackerName = battleInfo.get(&amp;quot;attacker&amp;quot;);&lt;br /&gt;
    var attackType = battleInfo.get(&amp;quot;attackTypeSelection&amp;quot;);&lt;br /&gt;
    var victimName = battleInfo.get(&amp;quot;victim&amp;quot;);&lt;br /&gt;
    var attackerVariation;&lt;br /&gt;
    var victimVariation;&lt;br /&gt;
&lt;br /&gt;
    if (!attackerName &amp;amp;&amp;amp; !attackType &amp;amp;&amp;amp; !victimName) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isPseudoSaved(characters, attackerName)) {&lt;br /&gt;
      var attacker = copyObject(characters.savedCharacters[attackerName]);&lt;br /&gt;
      attackerVariation = attacker.bonusVariation;&lt;br /&gt;
    } else {&lt;br /&gt;
      var attacker = createMonster(attackerName);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isPseudoSaved(characters, victimName)) {&lt;br /&gt;
      var victim = copyObject(characters.savedCharacters[victimName]);&lt;br /&gt;
      victimVariation = victim.bonusVariation;&lt;br /&gt;
    } else {&lt;br /&gt;
      var victim = createMonster(victimName, attacker);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      isChecked(attacker.bonusVariationActivation) &amp;amp;&amp;amp;&lt;br /&gt;
      attacker.hasOwnProperty(attackerVariation) &amp;amp;&amp;amp;&lt;br /&gt;
      attacker.bonusVariationMinValue &amp;lt; attacker.bonusVariationMaxValue&lt;br /&gt;
    ) {&lt;br /&gt;
      damagesWithVariation(&lt;br /&gt;
        attacker,&lt;br /&gt;
        victim,&lt;br /&gt;
        attackType,&lt;br /&gt;
        battle,&lt;br /&gt;
        attacker,&lt;br /&gt;
        attackerVariation&lt;br /&gt;
      );&lt;br /&gt;
    } else if (&lt;br /&gt;
      isChecked(victim.bonusVariationActivation) &amp;amp;&amp;amp;&lt;br /&gt;
      victim.hasOwnProperty(victimVariation) &amp;amp;&amp;amp;&lt;br /&gt;
      victim.bonusVariationMinValue &amp;lt; victim.bonusVariationMaxValue&lt;br /&gt;
    ) {&lt;br /&gt;
      damagesWithVariation(&lt;br /&gt;
        attacker,&lt;br /&gt;
        victim,&lt;br /&gt;
        attackType,&lt;br /&gt;
        battle,&lt;br /&gt;
        victim,&lt;br /&gt;
        victimVariation&lt;br /&gt;
      );&lt;br /&gt;
    } else {&lt;br /&gt;
      damagesWithoutVariation(attacker, victim, attackType, battle, characters);&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createMapping() {&lt;br /&gt;
  mapping = {&lt;br /&gt;
    typeFlag: [&lt;br /&gt;
      &amp;quot;animalBonus&amp;quot;, // 0&lt;br /&gt;
      &amp;quot;humanBonus&amp;quot;, // 1&lt;br /&gt;
      &amp;quot;orcBonus&amp;quot;, // 2&lt;br /&gt;
      &amp;quot;mysticBonus&amp;quot;, // 3&lt;br /&gt;
      &amp;quot;undeadBonus&amp;quot;, // 4&lt;br /&gt;
      &amp;quot;insectBonus&amp;quot;, // 5&lt;br /&gt;
      &amp;quot;desertBonus&amp;quot;, // 6&lt;br /&gt;
      &amp;quot;devilBonus&amp;quot;, // 7&lt;br /&gt;
    ],&lt;br /&gt;
    raceBonus: {&lt;br /&gt;
      warrior: &amp;quot;warriorBonus&amp;quot;,&lt;br /&gt;
      sura: &amp;quot;suraBonus&amp;quot;,&lt;br /&gt;
      ninja: &amp;quot;ninjaBonus&amp;quot;,&lt;br /&gt;
      shaman: &amp;quot;shamanBonus&amp;quot;,&lt;br /&gt;
      lycan: &amp;quot;lycanBonus&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    raceResistance: {&lt;br /&gt;
      warrior: &amp;quot;warriorResistance&amp;quot;,&lt;br /&gt;
      sura: &amp;quot;suraResistance&amp;quot;,&lt;br /&gt;
      ninja: &amp;quot;ninjaResistance&amp;quot;,&lt;br /&gt;
      shaman: &amp;quot;shamanResistance&amp;quot;,&lt;br /&gt;
      lycan: &amp;quot;lycanResistance&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    defenseWeapon: [&lt;br /&gt;
      &amp;quot;swordDefense&amp;quot;, // 0&lt;br /&gt;
      &amp;quot;daggerDefense&amp;quot;, // 1&lt;br /&gt;
      &amp;quot;arrowDefense&amp;quot;, // 2&lt;br /&gt;
      &amp;quot;twoHandedSwordDefense&amp;quot;, // 3&lt;br /&gt;
      &amp;quot;bellDefense&amp;quot;, // 4&lt;br /&gt;
      &amp;quot;clawDefense&amp;quot;, // 5&lt;br /&gt;
      &amp;quot;fanDefense&amp;quot;, // 6&lt;br /&gt;
      &amp;quot;swordDefense&amp;quot;, // 7&lt;br /&gt;
      &amp;quot;fistDefense&amp;quot;, // 8&lt;br /&gt;
    ],&lt;br /&gt;
    breakWeapon: [&lt;br /&gt;
      &amp;quot;breakSwordDefense&amp;quot;, // 0&lt;br /&gt;
      &amp;quot;breakDaggerDefense&amp;quot;, // 1&lt;br /&gt;
      &amp;quot;breakArrowDefense&amp;quot;, // 2&lt;br /&gt;
      &amp;quot;breakTwoHandedSwordDefense&amp;quot;, // 3&lt;br /&gt;
      &amp;quot;breakBellDefense&amp;quot;, // 4&lt;br /&gt;
      &amp;quot;breakClawDefense&amp;quot;, // 5&lt;br /&gt;
      &amp;quot;breakFanDefense&amp;quot;, // 6&lt;br /&gt;
      &amp;quot;breakSwordDefense&amp;quot;, // 7&lt;br /&gt;
    ],&lt;br /&gt;
    elementBonus: [&lt;br /&gt;
      &amp;quot;fireBonus&amp;quot;, // 0&lt;br /&gt;
      &amp;quot;iceBonus&amp;quot;, // 1&lt;br /&gt;
      &amp;quot;windBonus&amp;quot;, // 2&lt;br /&gt;
      &amp;quot;lightningBonus&amp;quot;, // 3&lt;br /&gt;
      &amp;quot;earthBonus&amp;quot;, // 4&lt;br /&gt;
      &amp;quot;darknessBonus&amp;quot;, // 5&lt;br /&gt;
    ],&lt;br /&gt;
    elementResistance: [&lt;br /&gt;
      &amp;quot;fireResistance&amp;quot;, // 0&lt;br /&gt;
      &amp;quot;iceResistance&amp;quot;, // 1&lt;br /&gt;
      &amp;quot;windResistance&amp;quot;, // 2&lt;br /&gt;
      &amp;quot;lightningResistance&amp;quot;, // 3&lt;br /&gt;
      &amp;quot;earthResistance&amp;quot;, // 4&lt;br /&gt;
      &amp;quot;darknessResistance&amp;quot;, // 5&lt;br /&gt;
    ],&lt;br /&gt;
  };&lt;br /&gt;
  return mapping;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createConstants() {&lt;br /&gt;
  var constants = {&lt;br /&gt;
    polymorphPowerTable: [&lt;br /&gt;
      10, 11, 11, 12, 13, 13, 14, 15, 16, 17, 18, 19, 20, 22, 23, 24, 26, 27,&lt;br /&gt;
      29, 31, 33, 35, 37, 39, 41, 44, 46, 49, 52, 55, 59, 62, 66, 70, 74, 79,&lt;br /&gt;
      84, 89, 94, 100, 0,&lt;br /&gt;
    ],&lt;br /&gt;
    skillPowerTable: [&lt;br /&gt;
      0, 0.05, 0.06, 0.08, 0.1, 0.12, 0.14, 0.16, 0.18, 0.2, 0.22, 0.24, 0.26,&lt;br /&gt;
      0.28, 0.3, 0.32, 0.34, 0.36, 0.38, 0.4, 0.5, 0.52, 0.54, 0.56, 0.58, 0.6,&lt;br /&gt;
      0.63, 0.66, 0.69, 0.72, 0.82, 0.85, 0.88, 0.91, 0.94, 0.98, 1.02, 1.06,&lt;br /&gt;
      1.1, 1.15, 1.25,&lt;br /&gt;
    ],&lt;br /&gt;
    marriageTable: {&lt;br /&gt;
      harmonyEarrings: [4, 5, 6, 8],&lt;br /&gt;
      loveEarrings: [4, 5, 6, 8],&lt;br /&gt;
      harmonyBracelet: [4, 5, 6, 8],&lt;br /&gt;
      loveNecklace: [20, 25, 30, 40],&lt;br /&gt;
      harmonyNecklace: [12, 16, 20, 30],&lt;br /&gt;
    },&lt;br /&gt;
    allowedWeaponsPerRace: {&lt;br /&gt;
      warrior: [0, 3, 8],&lt;br /&gt;
      ninja: [0, 1, 2, 8],&lt;br /&gt;
      sura: [0, 7, 8],&lt;br /&gt;
      shaman: [4, 6, 8],&lt;br /&gt;
      lycan: [5, 8],&lt;br /&gt;
    },&lt;br /&gt;
    translation: {&lt;br /&gt;
      fr: {&lt;br /&gt;
        damages: &amp;quot;Dégâts&amp;quot;,&lt;br /&gt;
        percentage: &amp;quot;Pourcentage&amp;quot;,&lt;br /&gt;
        miss: &amp;quot;Miss&amp;quot;,&lt;br /&gt;
        normalHit: &amp;quot;Coup classique&amp;quot;,&lt;br /&gt;
        criticalHit: &amp;quot;Coup critique&amp;quot;,&lt;br /&gt;
        piercingHit: &amp;quot;Coup perçant&amp;quot;,&lt;br /&gt;
        criticalPiercingHit: &amp;quot;Coup critique perçant&amp;quot;,&lt;br /&gt;
        damagesRepartition: &amp;quot;Distribution des dégâts&amp;quot;,&lt;br /&gt;
        averageDamages: &amp;quot;Dégâts moyens&amp;quot;,&lt;br /&gt;
        damagesAugmentation: &amp;quot;Augmentation des dégâts&amp;quot;,&lt;br /&gt;
        bonusVariationTitle: [&lt;br /&gt;
          &amp;quot;Évolution des dégâts moyens&amp;quot;,&lt;br /&gt;
          &amp;quot;par rapport à la valeur d'un bonus&amp;quot;,&lt;br /&gt;
        ],&lt;br /&gt;
      },&lt;br /&gt;
      en: {&lt;br /&gt;
        damages: &amp;quot;Damage&amp;quot;,&lt;br /&gt;
        percentage: &amp;quot;Percentage&amp;quot;,&lt;br /&gt;
        miss: &amp;quot;Miss&amp;quot;,&lt;br /&gt;
        normalHit: &amp;quot;Normal Hit&amp;quot;,&lt;br /&gt;
        criticalHit: &amp;quot;Critical Hit&amp;quot;,&lt;br /&gt;
        piercingHit: &amp;quot;Piercing Hit&amp;quot;,&lt;br /&gt;
        criticalPiercingHit: &amp;quot;Critical Piercing Hit&amp;quot;,&lt;br /&gt;
        damagesRepartition: &amp;quot;Damage Repartition&amp;quot;,&lt;br /&gt;
        averageDamages: &amp;quot;Average Damage&amp;quot;,&lt;br /&gt;
        damagesAugmentation: &amp;quot;Damage Augmentation&amp;quot;,&lt;br /&gt;
        bonusVariationTitle: [&lt;br /&gt;
          &amp;quot;Evolution of Average Damage&amp;quot;,&lt;br /&gt;
          &amp;quot;Relative to a Bonus Value&amp;quot;,&lt;br /&gt;
        ],&lt;br /&gt;
      },&lt;br /&gt;
      tr: {&lt;br /&gt;
        damages: &amp;quot;Hasar&amp;quot;,&lt;br /&gt;
        percentage: &amp;quot;Yüzde&amp;quot;,&lt;br /&gt;
        miss: &amp;quot;Miss Vuruş&amp;quot;,&lt;br /&gt;
        normalHit: &amp;quot;Düz Vuruş&amp;quot;,&lt;br /&gt;
        criticalHit: &amp;quot;Kritik Vuruş&amp;quot;,&lt;br /&gt;
        piercingHit: &amp;quot;Delici Vuruş&amp;quot;,&lt;br /&gt;
        criticalPiercingHit: &amp;quot;Kritikli Delici Vuruş&amp;quot;,&lt;br /&gt;
        damagesRepartition: &amp;quot;Hasar Dağılımı&amp;quot;,&lt;br /&gt;
        averageDamages: &amp;quot;Ortalama Hasar&amp;quot;,&lt;br /&gt;
        damagesAugmentation: &amp;quot;Ortalama Hasar Artışı&amp;quot;,&lt;br /&gt;
        bonusVariationTitle: [&lt;br /&gt;
          &amp;quot;Bir bonusun değerine kıyasla&amp;quot;,&lt;br /&gt;
          &amp;quot;Ortalama Hasar Çizelgesi&amp;quot;,&lt;br /&gt;
        ],&lt;br /&gt;
      },&lt;br /&gt;
      ro: {&lt;br /&gt;
        damages: &amp;quot;Daune&amp;quot;,&lt;br /&gt;
        percentage: &amp;quot;Procent&amp;quot;,&lt;br /&gt;
        miss: &amp;quot;Miss&amp;quot;,&lt;br /&gt;
        normalHit: &amp;quot;Lovitura normala&amp;quot;,&lt;br /&gt;
        criticalHit: &amp;quot;Lovitura critica&amp;quot;,&lt;br /&gt;
        piercingHit: &amp;quot;Lovitura patrunzatoare&amp;quot;,&lt;br /&gt;
        criticalPiercingHit: &amp;quot;Lovitura critica si patrunzatoare&amp;quot;,&lt;br /&gt;
        damagesRepartition: &amp;quot;Distribuția daunelor&amp;quot;,&lt;br /&gt;
        averageDamages: &amp;quot;Media damageului&amp;quot;,&lt;br /&gt;
        damagesAugmentation: &amp;quot;Damage imbunatatit&amp;quot;,&lt;br /&gt;
        bonusVariationTitle: [&lt;br /&gt;
          &amp;quot;Evolutia mediei damageului&amp;quot;,&lt;br /&gt;
          &amp;quot;relativ la o valoare bonus&amp;quot;,&lt;br /&gt;
        ],&lt;br /&gt;
      },&lt;br /&gt;
      de: {&lt;br /&gt;
        damages: &amp;quot;Schäden&amp;quot;,&lt;br /&gt;
        percentage: &amp;quot;Prozentsatz&amp;quot;,&lt;br /&gt;
        miss: &amp;quot;Verfehlen&amp;quot;,&lt;br /&gt;
        normalHit: &amp;quot;Normaler Treffer&amp;quot;,&lt;br /&gt;
        criticalHit: &amp;quot;Kritischer Treffer&amp;quot;,&lt;br /&gt;
        piercingHit: &amp;quot;Durchdringender Treffer&amp;quot;,&lt;br /&gt;
        criticalPiercingHit: &amp;quot;Kritischer durchdringender Treffer&amp;quot;,&lt;br /&gt;
        damagesRepartition: &amp;quot;Schadensverteilung&amp;quot;,&lt;br /&gt;
        averageDamages: &amp;quot;Durchschnittlicher Schaden&amp;quot;,&lt;br /&gt;
        damagesAugmentation: &amp;quot;Schadenserhöhung&amp;quot;,&lt;br /&gt;
        bonusVariationTitle: [&lt;br /&gt;
          &amp;quot;Entwicklung des durchschnittlichen Schadens&amp;quot;,&lt;br /&gt;
          &amp;quot;im Verhältnis zu einem Bonus&amp;quot;,&lt;br /&gt;
        ],&lt;br /&gt;
      },&lt;br /&gt;
      pt: {&lt;br /&gt;
        damages: &amp;quot;Dano&amp;quot;,&lt;br /&gt;
        percentage: &amp;quot;Percentagem&amp;quot;,&lt;br /&gt;
        miss: &amp;quot;Miss&amp;quot;,&lt;br /&gt;
        normalHit: &amp;quot;Dano normal&amp;quot;,&lt;br /&gt;
        criticalHit: &amp;quot;Dano crítico&amp;quot;,&lt;br /&gt;
        piercingHit: &amp;quot;Dano perfurante&amp;quot;,&lt;br /&gt;
        criticalPiercingHit: &amp;quot;Dano crítico perfurante&amp;quot;,&lt;br /&gt;
        damagesRepartition: &amp;quot;Repartição de dano&amp;quot;,&lt;br /&gt;
        averageDamages: &amp;quot;Dano médio&amp;quot;,&lt;br /&gt;
        damagesAugmentation: &amp;quot;Aumento de dano&amp;quot;,&lt;br /&gt;
        bonusVariationTitle: [&amp;quot;Evolução do dano médio&amp;quot;, &amp;quot;relativo a um bónus&amp;quot;],&lt;br /&gt;
      },&lt;br /&gt;
      // es: {&lt;br /&gt;
      //   damages: &amp;quot;Daño&amp;quot;,&lt;br /&gt;
      //   percentage: &amp;quot;Porcentaje&amp;quot;,&lt;br /&gt;
      //   miss: &amp;quot;Miss&amp;quot;,&lt;br /&gt;
      //   normalHit: &amp;quot;Daño normal&amp;quot;,&lt;br /&gt;
      //   criticalHit: &amp;quot;Daño crítico&amp;quot;,&lt;br /&gt;
      //   piercingHit: &amp;quot;Daño perforante&amp;quot;,&lt;br /&gt;
      //   criticalPiercingHit: &amp;quot;Daño crítico perforante&amp;quot;,&lt;br /&gt;
      //   damagesRepartition: &amp;quot;Repartición de daños&amp;quot;,&lt;br /&gt;
      //   averageDamages: &amp;quot;Daño medio&amp;quot;,&lt;br /&gt;
      //   damagesAugmentation: &amp;quot;Aumento de daño&amp;quot;,&lt;br /&gt;
      //   bonusVariationTitle: [&amp;quot;Evolución del daño medio&amp;quot;, &amp;quot;Relativo a una bonificación&amp;quot;]&lt;br /&gt;
      // },&lt;br /&gt;
    },&lt;br /&gt;
  };&lt;br /&gt;
  return constants;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initResultTableHistory(battle) {&lt;br /&gt;
  var {&lt;br /&gt;
    tableResultHistory,&lt;br /&gt;
    savedFights,&lt;br /&gt;
    deleteFightTemplate,&lt;br /&gt;
    numberFormats: { default: numberFormat },&lt;br /&gt;
  } = battle;&lt;br /&gt;
  var startIndex = 3;&lt;br /&gt;
&lt;br /&gt;
  if (savedFights.length) {&lt;br /&gt;
    hideElement(tableResultHistory.rows[1]);&lt;br /&gt;
&lt;br /&gt;
    for (var savedFight of savedFights) {&lt;br /&gt;
      addRowToTableResultHistory(&lt;br /&gt;
        tableResultHistory,&lt;br /&gt;
        savedFight,&lt;br /&gt;
        deleteFightTemplate,&lt;br /&gt;
        numberFormat&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  tableResultHistory.addEventListener(&amp;quot;click&amp;quot;, function (event) {&lt;br /&gt;
    var deleteButton = event.target.closest(&amp;quot;.svg-icon-delete&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (deleteButton) {&lt;br /&gt;
      var row = deleteButton.closest(&amp;quot;tr&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
      if (row) {&lt;br /&gt;
        savedFights.splice(row.rowIndex - startIndex, 1);&lt;br /&gt;
        updateSavedFights(savedFights);&lt;br /&gt;
&lt;br /&gt;
        row.remove();&lt;br /&gt;
&lt;br /&gt;
        if (tableResultHistory.rows.length === startIndex) {&lt;br /&gt;
          showElement(tableResultHistory.rows[1]);&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initDamagesChart(battle) {&lt;br /&gt;
  var { translation, reduceChartPointsContainer, reduceChartPoints } = battle;&lt;br /&gt;
  var percentFormat = battle.numberFormats.percent;&lt;br /&gt;
  var customPlugins = {&lt;br /&gt;
    id: &amp;quot;customPlugins&amp;quot;,&lt;br /&gt;
    afterDraw(chart) {&lt;br /&gt;
      var missPercentage = chart.data.missPercentage;&lt;br /&gt;
&lt;br /&gt;
      if (!missPercentage) {&lt;br /&gt;
        return;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      var {&lt;br /&gt;
        ctx,&lt;br /&gt;
        chartArea: { top, right },&lt;br /&gt;
      } = chart;&lt;br /&gt;
      ctx.save();&lt;br /&gt;
      var text =&lt;br /&gt;
        translation.miss + &amp;quot; : &amp;quot; + percentFormat.format(missPercentage);&lt;br /&gt;
      var padding = 4;&lt;br /&gt;
      var fontSize = 14;&lt;br /&gt;
&lt;br /&gt;
      ctx.font = fontSize + &amp;quot;px Helvetica Neue&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
      var textWidth = ctx.measureText(text).width;&lt;br /&gt;
      var xPosition = right - textWidth - 5;&lt;br /&gt;
      var yPosition = top + 5;&lt;br /&gt;
&lt;br /&gt;
      ctx.fillStyle = &amp;quot;rgba(255, 0, 0, 0.2)&amp;quot;;&lt;br /&gt;
      ctx.fillRect(&lt;br /&gt;
        xPosition - padding,&lt;br /&gt;
        yPosition - padding,&lt;br /&gt;
        textWidth + 2 * padding,&lt;br /&gt;
        fontSize + 2 * padding&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      ctx.strokeStyle = &amp;quot;red&amp;quot;;&lt;br /&gt;
      ctx.strokeRect(&lt;br /&gt;
        xPosition - padding,&lt;br /&gt;
        yPosition - padding,&lt;br /&gt;
        textWidth + 2 * padding,&lt;br /&gt;
        fontSize + 2 * padding&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      ctx.fillStyle = &amp;quot;#666&amp;quot;;&lt;br /&gt;
      ctx.textBaseline = &amp;quot;top&amp;quot;;&lt;br /&gt;
      ctx.fillText(text, xPosition, yPosition + 1);&lt;br /&gt;
&lt;br /&gt;
      ctx.restore();&lt;br /&gt;
    },&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  Chart.register(customPlugins);&lt;br /&gt;
&lt;br /&gt;
  var ctx = battle.plotDamages.getContext(&amp;quot;2d&amp;quot;);&lt;br /&gt;
  var maxLabelsInTooltip = 10;&lt;br /&gt;
  var nullLabelText = &amp;quot; ...&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  var chart = new Chart(ctx, {&lt;br /&gt;
    type: &amp;quot;scatter&amp;quot;,&lt;br /&gt;
    data: {&lt;br /&gt;
      missPercentage: 0,&lt;br /&gt;
      datasets: [],&lt;br /&gt;
    },&lt;br /&gt;
    options: {&lt;br /&gt;
      responsive: true,&lt;br /&gt;
      maintainAspectRatio: false,&lt;br /&gt;
      plugins: {&lt;br /&gt;
        legend: {&lt;br /&gt;
          display: true,&lt;br /&gt;
          onHover: function (e) {&lt;br /&gt;
            e.native.target.style.cursor = &amp;quot;pointer&amp;quot;;&lt;br /&gt;
          },&lt;br /&gt;
          onLeave: function (e) {&lt;br /&gt;
            e.native.target.style.cursor = &amp;quot;default&amp;quot;;&lt;br /&gt;
          },&lt;br /&gt;
          onClick: function (e, legendItem, legend) {&lt;br /&gt;
            var currentIndex = legendItem.datasetIndex;&lt;br /&gt;
            var ci = legend.chart;&lt;br /&gt;
            var isCurrentDatasetVisible = ci.isDatasetVisible(currentIndex);&lt;br /&gt;
            var datasets = ci.data.datasets;&lt;br /&gt;
            var hideReducePoints = true;&lt;br /&gt;
            var isReducePointsChecked = reduceChartPoints.checked;&lt;br /&gt;
&lt;br /&gt;
            datasets[currentIndex].hidden = isCurrentDatasetVisible;&lt;br /&gt;
            legendItem.hidden = isCurrentDatasetVisible;&lt;br /&gt;
&lt;br /&gt;
            for (var index in datasets) {&lt;br /&gt;
              if (ci.isDatasetVisible(index) &amp;amp;&amp;amp; datasets[index].canBeReduced) {&lt;br /&gt;
                showElement(reduceChartPointsContainer);&lt;br /&gt;
                hideReducePoints = false;&lt;br /&gt;
                break;&lt;br /&gt;
              }&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            if (hideReducePoints) {&lt;br /&gt;
              hideElement(reduceChartPointsContainer);&lt;br /&gt;
              handleChartAnimations(ci, true);&lt;br /&gt;
            } else {&lt;br /&gt;
              handleChartAnimations(ci, isReducePointsChecked);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            ci.update();&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        title: {&lt;br /&gt;
          display: true,&lt;br /&gt;
          text: translation.damagesRepartition,&lt;br /&gt;
          font: {&lt;br /&gt;
            size: 20,&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        tooltip: {&lt;br /&gt;
          callbacks: {&lt;br /&gt;
            label: function (context) {&lt;br /&gt;
              if (context.label === null) {&lt;br /&gt;
                return nullLabelText;&lt;br /&gt;
              }&lt;br /&gt;
&lt;br /&gt;
              var xValue = battle.numberFormats.default.format(&lt;br /&gt;
                context.parsed.x&lt;br /&gt;
              );&lt;br /&gt;
              var yValue = battle.numberFormats.percent.format(&lt;br /&gt;
                context.parsed.y&lt;br /&gt;
              );&lt;br /&gt;
&lt;br /&gt;
              label =&lt;br /&gt;
                &amp;quot; &amp;quot; +&lt;br /&gt;
                context.dataset.label +&lt;br /&gt;
                &amp;quot; : (&amp;quot; +&lt;br /&gt;
                xValue +&lt;br /&gt;
                &amp;quot;, &amp;quot; +&lt;br /&gt;
                yValue +&lt;br /&gt;
                &amp;quot;)&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
              return label;&lt;br /&gt;
            },&lt;br /&gt;
            beforeBody: function (tooltipItems) {&lt;br /&gt;
              if (tooltipItems.length &amp;gt; maxLabelsInTooltip + 1) {&lt;br /&gt;
                tooltipItems.splice(maxLabelsInTooltip + 1);&lt;br /&gt;
                tooltipItems[maxLabelsInTooltip].label = null;&lt;br /&gt;
              }&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          caretPadding: 10,&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
      scales: {&lt;br /&gt;
        x: {&lt;br /&gt;
          type: &amp;quot;linear&amp;quot;,&lt;br /&gt;
          position: &amp;quot;bottom&amp;quot;,&lt;br /&gt;
          title: {&lt;br /&gt;
            display: true,&lt;br /&gt;
            text: translation.damages,&lt;br /&gt;
            font: {&lt;br /&gt;
              size: 16,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        y: {&lt;br /&gt;
          title: {&lt;br /&gt;
            display: true,&lt;br /&gt;
            text: translation.percentage,&lt;br /&gt;
            font: {&lt;br /&gt;
              size: 16,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          ticks: {&lt;br /&gt;
            format: {&lt;br /&gt;
              style: &amp;quot;percent&amp;quot;,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
      elements: {&lt;br /&gt;
        point: {&lt;br /&gt;
          borderWidth: 1,&lt;br /&gt;
          radius: 3,&lt;br /&gt;
          hitRadius: 3,&lt;br /&gt;
          hoverRadius: 6,&lt;br /&gt;
          hoverBorderWidth: 2,&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
    },&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  var datasetsStyle = [&lt;br /&gt;
    {&lt;br /&gt;
      name: &amp;quot;normalHit&amp;quot;,&lt;br /&gt;
      canBeReduced: false,&lt;br /&gt;
      label: translation.normalHit,&lt;br /&gt;
      backgroundColor: &amp;quot;rgba(75, 192, 192, 0.2)&amp;quot;,&lt;br /&gt;
      borderColor: &amp;quot;rgba(75, 192, 192, 1)&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      name: &amp;quot;piercingHit&amp;quot;,&lt;br /&gt;
      canBeReduced: false,&lt;br /&gt;
      label: translation.piercingHit,&lt;br /&gt;
      backgroundColor: &amp;quot;rgba(192, 192, 75, 0.2)&amp;quot;,&lt;br /&gt;
      borderColor: &amp;quot;rgba(192, 192, 75, 1)&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      name: &amp;quot;criticalHit&amp;quot;,&lt;br /&gt;
      canBeReduced: false,&lt;br /&gt;
      label: translation.criticalHit,&lt;br /&gt;
      backgroundColor: &amp;quot;rgba(192, 75, 192, 0.2)&amp;quot;,&lt;br /&gt;
      borderColor: &amp;quot;rgba(192, 75, 192, 1)&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      name: &amp;quot;criticalPiercingHit&amp;quot;,&lt;br /&gt;
      canBeReduced: false,&lt;br /&gt;
      label: translation.criticalPiercingHit,&lt;br /&gt;
      backgroundColor: &amp;quot;rgba(75, 75, 192, 0.2)&amp;quot;,&lt;br /&gt;
      borderColor: &amp;quot;rgba(75, 75, 192, 1)&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
  ];&lt;br /&gt;
  battle.damagesChart = {&lt;br /&gt;
    chart: chart,&lt;br /&gt;
    datasetsStyle: datasetsStyle,&lt;br /&gt;
    maxPoints: 500,&lt;br /&gt;
    reduceChartPointsContainer: reduceChartPointsContainer,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initBonusVariationChart(battle) {&lt;br /&gt;
  var translation = battle.translation;&lt;br /&gt;
&lt;br /&gt;
  var ctx = battle.plotBonusVariation.getContext(&amp;quot;2d&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  var chart = new Chart(ctx, {&lt;br /&gt;
    type: &amp;quot;line&amp;quot;,&lt;br /&gt;
    data: {&lt;br /&gt;
      datasets: [&lt;br /&gt;
        {&lt;br /&gt;
          label: translation.averageDamages,&lt;br /&gt;
          backgroundColor: &amp;quot;rgba(75, 192, 192, 0.2)&amp;quot;,&lt;br /&gt;
          borderColor: &amp;quot;rgba(75, 192, 192, 1)&amp;quot;,&lt;br /&gt;
          fill: true,&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          label: translation.damagesAugmentation,&lt;br /&gt;
          backgroundColor: &amp;quot;rgba(192, 192, 75, 0.2)&amp;quot;,&lt;br /&gt;
          borderColor: &amp;quot;rgba(192, 192, 75, 1)&amp;quot;,&lt;br /&gt;
          hidden: true,&lt;br /&gt;
          yTicksFormat: { style: &amp;quot;percent&amp;quot; },&lt;br /&gt;
          fill: true,&lt;br /&gt;
        },&lt;br /&gt;
      ],&lt;br /&gt;
    },&lt;br /&gt;
    options: {&lt;br /&gt;
      responsive: true,&lt;br /&gt;
      maintainAspectRatio: false,&lt;br /&gt;
      plugins: {&lt;br /&gt;
        legend: {&lt;br /&gt;
          display: true,&lt;br /&gt;
          onHover: function (e) {&lt;br /&gt;
            e.native.target.style.cursor = &amp;quot;pointer&amp;quot;;&lt;br /&gt;
          },&lt;br /&gt;
          onLeave: function (e) {&lt;br /&gt;
            e.native.target.style.cursor = &amp;quot;default&amp;quot;;&lt;br /&gt;
          },&lt;br /&gt;
          onClick: function (e, legendItem, legend) {&lt;br /&gt;
            var currentIndex = legendItem.datasetIndex;&lt;br /&gt;
            var ci = legend.chart;&lt;br /&gt;
            var datasets = ci.data.datasets;&lt;br /&gt;
            var isCurrentDatasetVisible = ci.isDatasetVisible(currentIndex);&lt;br /&gt;
            var yAxis = ci.options.scales.y;&lt;br /&gt;
&lt;br /&gt;
            var otherIndex = currentIndex === 0 ? 1 : 0;&lt;br /&gt;
            var visibleDataset = isCurrentDatasetVisible&lt;br /&gt;
              ? datasets[otherIndex]&lt;br /&gt;
              : datasets[currentIndex];&lt;br /&gt;
&lt;br /&gt;
            datasets[currentIndex].hidden = isCurrentDatasetVisible;&lt;br /&gt;
            datasets[otherIndex].hidden = !isCurrentDatasetVisible;&lt;br /&gt;
&lt;br /&gt;
            yAxis.title.text = visibleDataset.label;&lt;br /&gt;
            yAxis.ticks.format = visibleDataset.yTicksFormat;&lt;br /&gt;
&lt;br /&gt;
            ci.update();&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        title: {&lt;br /&gt;
          display: true,&lt;br /&gt;
          text: translation.bonusVariationTitle,&lt;br /&gt;
          font: {&lt;br /&gt;
            size: 18,&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        tooltip: {&lt;br /&gt;
          caretPadding: 10,&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
      scales: {&lt;br /&gt;
        x: {&lt;br /&gt;
          type: &amp;quot;linear&amp;quot;,&lt;br /&gt;
          position: &amp;quot;bottom&amp;quot;,&lt;br /&gt;
          title: {&lt;br /&gt;
            display: true,&lt;br /&gt;
            text: &amp;quot;Bonus&amp;quot;,&lt;br /&gt;
            font: {&lt;br /&gt;
              size: 16,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          ticks: {&lt;br /&gt;
            callback: function (value) {&lt;br /&gt;
              if (Number.isInteger(value)) {&lt;br /&gt;
                return Number(value);&lt;br /&gt;
              }&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        y: {&lt;br /&gt;
          title: {&lt;br /&gt;
            display: true,&lt;br /&gt;
            text: translation.averageDamages,&lt;br /&gt;
            font: {&lt;br /&gt;
              size: 16,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
      elements: {&lt;br /&gt;
        point: {&lt;br /&gt;
          borderWidth: 1,&lt;br /&gt;
          radius: 3,&lt;br /&gt;
          hitRadius: 3,&lt;br /&gt;
          hoverRadius: 6,&lt;br /&gt;
          hoverBorderWidth: 2,&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
    },&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  battle.bonusVariationChart = chart;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function attackSelectonListener(&lt;br /&gt;
  characters,&lt;br /&gt;
  attackerSelection,&lt;br /&gt;
  attackTypeSelection&lt;br /&gt;
) {&lt;br /&gt;
  attackerSelection.addEventListener(&amp;quot;change&amp;quot;, function (event) {&lt;br /&gt;
    var attackerName = event.target.value;&lt;br /&gt;
&lt;br /&gt;
    if (isPseudoSaved(characters, attackerName)) {&lt;br /&gt;
      var attacker = characters.savedCharacters[attackerName];&lt;br /&gt;
      filterAttackTypeSelection(attacker, attackTypeSelection);&lt;br /&gt;
    } else {&lt;br /&gt;
      filterAttackTypeSelectionMonster(attackTypeSelection);&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getTranslation(translation) {&lt;br /&gt;
  var userLanguage = navigator.language;&lt;br /&gt;
  var langToUse = &amp;quot;en&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  for (var lang in translation) {&lt;br /&gt;
    if (userLanguage.startsWith(lang)) {&lt;br /&gt;
      langToUse = lang;&lt;br /&gt;
      break;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return translation[langToUse];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createDamageCalculatorInformation(chartSource) {&lt;br /&gt;
  var characters = {&lt;br /&gt;
    unsavedChanges: false,&lt;br /&gt;
    savedCharacters: {},&lt;br /&gt;
    currentCharacter: null,&lt;br /&gt;
    savedMonsters: getSavedMonsters(),&lt;br /&gt;
    characterCreation: document.getElementById(&amp;quot;character-creation&amp;quot;),&lt;br /&gt;
    addNewCharacterButton: document.getElementById(&amp;quot;add-new-character&amp;quot;),&lt;br /&gt;
    dropZone: document.getElementById(&amp;quot;character-drop-zone&amp;quot;),&lt;br /&gt;
    characterInput: document.getElementById(&amp;quot;character-input&amp;quot;),&lt;br /&gt;
    newCharacterTemplate: document.getElementById(&amp;quot;new-character-template&amp;quot;)&lt;br /&gt;
      .children[0],&lt;br /&gt;
    charactersContainer: document.getElementById(&amp;quot;characters-container&amp;quot;),&lt;br /&gt;
    newMonsterTemplate: document.getElementById(&amp;quot;new-monster-template&amp;quot;)&lt;br /&gt;
      .children[0],&lt;br /&gt;
    monstersContainer: document.getElementById(&amp;quot;monsters-container&amp;quot;),&lt;br /&gt;
    monsterListForm: document.getElementById(&amp;quot;monster-list-form&amp;quot;),&lt;br /&gt;
    searchMonster: document.getElementById(&amp;quot;search-monster&amp;quot;),&lt;br /&gt;
    monsterList: document.getElementById(&amp;quot;monster-list&amp;quot;),&lt;br /&gt;
    saveButton: document.getElementById(&amp;quot;save-character&amp;quot;),&lt;br /&gt;
    weaponCategory: document.getElementById(&amp;quot;weapon-category&amp;quot;),&lt;br /&gt;
    weaponDisplay: document.getElementById(&amp;quot;weapon-display&amp;quot;),&lt;br /&gt;
    randomAttackValue: document.getElementById(&amp;quot;random-attack-value&amp;quot;),&lt;br /&gt;
    randomMagicAttackValue: document.getElementById(&lt;br /&gt;
      &amp;quot;random-magic-attack-value&amp;quot;&lt;br /&gt;
    ),&lt;br /&gt;
    yoharaCreation: document.getElementById(&amp;quot;yohara-creation&amp;quot;),&lt;br /&gt;
    blessingCreation: document.getElementById(&amp;quot;blessing-creation&amp;quot;),&lt;br /&gt;
    marriageCreation: document.getElementById(&amp;quot;marriage-creation&amp;quot;),&lt;br /&gt;
    bonusVariation: {&lt;br /&gt;
      tab: document.getElementById(&amp;quot;Variation&amp;quot;),&lt;br /&gt;
      activation: document.getElementById(&amp;quot;bonus-variation-activation&amp;quot;),&lt;br /&gt;
      input: document.getElementById(&amp;quot;bonus-variation&amp;quot;),&lt;br /&gt;
      inputDisplay: document.getElementById(&amp;quot;bonus-variation-display&amp;quot;),&lt;br /&gt;
      container: document.getElementById(&amp;quot;bonus-variation-range&amp;quot;),&lt;br /&gt;
      minValue: document.getElementById(&amp;quot;bonus-variation-min-value&amp;quot;),&lt;br /&gt;
      maxValue: document.getElementById(&amp;quot;bonus-variation-max-value&amp;quot;),&lt;br /&gt;
    },&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  characters.bonusVariation.inputDisplay.setAttribute(&amp;quot;readonly&amp;quot;, &amp;quot;&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  for (var [pseudo, character] of Object.entries(getSavedCharacters())) {&lt;br /&gt;
    characters.savedCharacters[pseudo] = character;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var skillContainer = document.getElementById(&amp;quot;skill-container&amp;quot;);&lt;br /&gt;
  characters.skillElementsToFilter =&lt;br /&gt;
    skillContainer.querySelectorAll(&amp;quot;[data-class]&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  var mapping = createMapping();&lt;br /&gt;
  var constants = createConstants();&lt;br /&gt;
&lt;br /&gt;
  var battle = {&lt;br /&gt;
    resetAttackType: false,&lt;br /&gt;
    savedFights: getSavedFights(),&lt;br /&gt;
    battleForm: document.getElementById(&amp;quot;create-battle&amp;quot;),&lt;br /&gt;
    attackerSelection: document.getElementById(&amp;quot;attacker-selection&amp;quot;),&lt;br /&gt;
    attackTypeSelection: document.getElementById(&amp;quot;attack-type-selection&amp;quot;),&lt;br /&gt;
    victimSelection: document.getElementById(&amp;quot;victim-selection&amp;quot;),&lt;br /&gt;
    damagesWeightedByType: {},&lt;br /&gt;
    scatterDataByType: {},&lt;br /&gt;
    damagesByBonus: [],&lt;br /&gt;
    tableResultFight: document.getElementById(&amp;quot;result-table-fight&amp;quot;),&lt;br /&gt;
    tableResultHistory: document.getElementById(&amp;quot;result-table-history&amp;quot;),&lt;br /&gt;
    deleteFightTemplate: document.getElementById(&amp;quot;delete-fight-template&amp;quot;)&lt;br /&gt;
      .children[0],&lt;br /&gt;
    errorInformation: {},&lt;br /&gt;
    fightResultContainer: document.getElementById(&amp;quot;fight-result-container&amp;quot;),&lt;br /&gt;
    downLoadRawData: document.getElementById(&amp;quot;download-raw-data&amp;quot;),&lt;br /&gt;
    downLoadRawDataVariation: document.getElementById(&lt;br /&gt;
      &amp;quot;download-raw-data-variation&amp;quot;&lt;br /&gt;
    ),&lt;br /&gt;
    bonusVariationResultContainer: document.getElementById(&lt;br /&gt;
      &amp;quot;bonus-variation-result-container&amp;quot;&lt;br /&gt;
    ),&lt;br /&gt;
    reduceChartPointsContainer: document.getElementById(&lt;br /&gt;
      &amp;quot;reduce-chart-points-container&amp;quot;&lt;br /&gt;
    ),&lt;br /&gt;
    reduceChartPoints: document.getElementById(&amp;quot;reduce-chart-points&amp;quot;),&lt;br /&gt;
    plotDamages: document.getElementById(&amp;quot;plot-damages&amp;quot;),&lt;br /&gt;
    plotBonusVariation: document.getElementById(&amp;quot;plot-bonus-variation&amp;quot;),&lt;br /&gt;
    uniqueDamagesCounters: document.querySelectorAll(&amp;quot;.unique-damages-counter&amp;quot;),&lt;br /&gt;
    possibleDamagesCounter: document.getElementById(&amp;quot;possible-damages-counter&amp;quot;),&lt;br /&gt;
    damagesTime: document.getElementById(&amp;quot;damages-time&amp;quot;),&lt;br /&gt;
    displayTime: document.getElementById(&amp;quot;display-time&amp;quot;),&lt;br /&gt;
    simulationCounter: document.getElementById(&amp;quot;simulation-counter&amp;quot;),&lt;br /&gt;
    simulationTime: document.getElementById(&amp;quot;simulation-time&amp;quot;),&lt;br /&gt;
    numberFormats: {&lt;br /&gt;
      default: new Intl.NumberFormat(undefined, {&lt;br /&gt;
        minimumFractionDigits: 0,&lt;br /&gt;
        maximumFractionDigits: 1,&lt;br /&gt;
      }),&lt;br /&gt;
      percent: new Intl.NumberFormat(undefined, {&lt;br /&gt;
        style: &amp;quot;percent&amp;quot;,&lt;br /&gt;
        maximumFractionDigits: 3,&lt;br /&gt;
      }),&lt;br /&gt;
      second: new Intl.NumberFormat(undefined, {&lt;br /&gt;
        style: &amp;quot;unit&amp;quot;,&lt;br /&gt;
        unit: &amp;quot;second&amp;quot;,&lt;br /&gt;
        unitDisplay: &amp;quot;long&amp;quot;,&lt;br /&gt;
        maximumFractionDigits: 3,&lt;br /&gt;
      }),&lt;br /&gt;
    },&lt;br /&gt;
    mapping: mapping,&lt;br /&gt;
    constants: constants,&lt;br /&gt;
    translation: getTranslation(constants.translation),&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  attackSelectonListener(&lt;br /&gt;
    characters,&lt;br /&gt;
    battle.attackerSelection,&lt;br /&gt;
    battle.attackTypeSelection&lt;br /&gt;
  );&lt;br /&gt;
  initResultTableHistory(battle);&lt;br /&gt;
  loadScript(chartSource, function () {&lt;br /&gt;
    initDamagesChart(battle);&lt;br /&gt;
    initBonusVariationChart(battle);&lt;br /&gt;
  });&lt;br /&gt;
  reduceChartPointsListener(battle);&lt;br /&gt;
  downloadRawDataListener(battle);&lt;br /&gt;
&lt;br /&gt;
  var errorElements = document.querySelectorAll(&amp;quot;[data-error]&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; errorElements.length; index++) {&lt;br /&gt;
    var errorElement = errorElements[index];&lt;br /&gt;
    battle.errorInformation[errorElement.dataset.error] = errorElement;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return [characters, battle];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadScript(src, callback) {&lt;br /&gt;
  var script = document.createElement(&amp;quot;script&amp;quot;);&lt;br /&gt;
  script.src = src;&lt;br /&gt;
&lt;br /&gt;
  function onComplete() {&lt;br /&gt;
    if (script.parentNode) {&lt;br /&gt;
      script.parentNode.removeChild(script);&lt;br /&gt;
    }&lt;br /&gt;
    if (callback) {&lt;br /&gt;
      callback();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  document.head.appendChild(script);&lt;br /&gt;
&lt;br /&gt;
  script.onload = onComplete;&lt;br /&gt;
  script.onerror = onComplete;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadStyle(src) {&lt;br /&gt;
  var link = document.createElement(&amp;quot;link&amp;quot;);&lt;br /&gt;
  link.href = src;&lt;br /&gt;
  link.rel = &amp;quot;stylesheet&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  document.head.appendChild(link);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loading() {&lt;br /&gt;
  var mainContainer = document.getElementById(&amp;quot;hide-all&amp;quot;);&lt;br /&gt;
  var loadingAnimation = document.getElementById(&amp;quot;loading-animation&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  mainContainer.classList.remove(&amp;quot;tabber-noactive&amp;quot;);&lt;br /&gt;
  loadingAnimation.classList.add(&amp;quot;tabber-noactive&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
(function () {&lt;br /&gt;
  var javascriptSource =&lt;br /&gt;
    &amp;quot;/index.php?title=Utilisateur:Ankhseram/Calculator.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&amp;quot;;&lt;br /&gt;
  var cssSource =&lt;br /&gt;
    &amp;quot;/index.php?title=Utilisateur:Ankhseram/Style.css&amp;amp;action=raw&amp;amp;ctype=text/css&amp;quot;;&lt;br /&gt;
  var chartSource = &amp;quot;https://cdn.jsdelivr.net/npm/chart.js&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  loadStyle(cssSource);&lt;br /&gt;
&lt;br /&gt;
  function main() {&lt;br /&gt;
    var [characters, battle] = createDamageCalculatorInformation(chartSource);&lt;br /&gt;
&lt;br /&gt;
    characterManagement(characters, battle);&lt;br /&gt;
    monsterManagement(characters, battle);&lt;br /&gt;
&lt;br /&gt;
    updateBattleChoice(characters, battle);&lt;br /&gt;
    createBattle(characters, battle);&lt;br /&gt;
&lt;br /&gt;
    loading();&lt;br /&gt;
  }&lt;br /&gt;
  loadScript(javascriptSource, main);&lt;br /&gt;
})();&lt;/div&gt;</summary>
		<author><name>Dexter</name></author>
		
	</entry>
	<entry>
		<id>https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Script/Calculator.js&amp;diff=105255</id>
		<title>MediaWiki:Script/Calculator.js</title>
		<link rel="alternate" type="text/html" href="https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Script/Calculator.js&amp;diff=105255"/>
		<updated>2024-11-20T16:07:11Z</updated>

		<summary type="html">&lt;p&gt;Dexter : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;function showElement(element) {&lt;br /&gt;
  element.classList.remove(&amp;quot;tabber-noactive&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function hideElement(element) {&lt;br /&gt;
  element.classList.add(&amp;quot;tabber-noactive&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function removeAccent(str) {&lt;br /&gt;
  return str.normalize(&amp;quot;NFD&amp;quot;).replace(/[\u0300-\u036f]/g, &amp;quot;&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function toNormalForm(str) {&lt;br /&gt;
  return removeAccent(str)&lt;br /&gt;
    .replace(&amp;quot;-&amp;quot;, &amp;quot; &amp;quot;)&lt;br /&gt;
    .replace(/[^a-zA-Z0-9 ]/g, &amp;quot;&amp;quot;)&lt;br /&gt;
    .toLowerCase();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function pseudoFormat(str) {&lt;br /&gt;
  return removeAccent(str).replace(/[^A-Za-z0-9 \(\)\+_-]+/g, &amp;quot;&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isValueInArray(value, array) {&lt;br /&gt;
  return array.indexOf(value) !== -1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function copyObject(object) {&lt;br /&gt;
  var copy = {};&lt;br /&gt;
  for (var key in object) {&lt;br /&gt;
    copy[key] = object[key];&lt;br /&gt;
  }&lt;br /&gt;
  return copy;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function compareNumbers(a, b) {&lt;br /&gt;
  return b - a;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isChecked(attribute) {&lt;br /&gt;
  return attribute === &amp;quot;on&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function floorMultiplication(firstFactor, secondFactor) {&lt;br /&gt;
  return Math.floor((firstFactor * secondFactor).toFixed(8));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function truncateNumber(number, precision) {&lt;br /&gt;
  return Math.floor(number * 10 ** precision) / 10 ** precision;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addKeyValue(object, key, value) {&lt;br /&gt;
  if (object.hasOwnProperty(key)) {&lt;br /&gt;
    object[key] += value;&lt;br /&gt;
  } else {&lt;br /&gt;
    object[key] = value;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function editTableResultRow(row, valuesToDisplay, numberFormat) {&lt;br /&gt;
  row.innerHTML = &amp;quot;&amp;quot;;&lt;br /&gt;
  for (var index = 0; index &amp;lt; valuesToDisplay.length; index++) {&lt;br /&gt;
    var cell = row.insertCell();&lt;br /&gt;
    var textContent;&lt;br /&gt;
&lt;br /&gt;
    if (index &amp;gt;= 3) {&lt;br /&gt;
      textContent = numberFormat.format(valuesToDisplay[index]);&lt;br /&gt;
    } else {&lt;br /&gt;
      textContent = valuesToDisplay[index];&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    cell.textContent = textContent;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return row;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addRowToTableResultHistory(&lt;br /&gt;
  tableResultHistory,&lt;br /&gt;
  valuesToDisplay,&lt;br /&gt;
  deleteFightTemplate,&lt;br /&gt;
  numberFormat&lt;br /&gt;
) {&lt;br /&gt;
  var row = tableResultHistory.insertRow();&lt;br /&gt;
  editTableResultRow(row, valuesToDisplay, numberFormat);&lt;br /&gt;
  var cell = row.insertCell();&lt;br /&gt;
  cell.appendChild(deleteFightTemplate.cloneNode(true));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcMeanDamages(damagesWeightedByType, totalCardinal) {&lt;br /&gt;
  var sumDamages = 0;&lt;br /&gt;
&lt;br /&gt;
  for (var damagesTypeName in damagesWeightedByType) {&lt;br /&gt;
    if (damagesTypeName === &amp;quot;miss&amp;quot;) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var damagesWeighted = damagesWeightedByType[damagesTypeName];&lt;br /&gt;
&lt;br /&gt;
    for (var damages in damagesWeighted) {&lt;br /&gt;
      sumDamages += damages * damagesWeighted[damages];&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return sumDamages / totalCardinal;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function prepareDamagesData(&lt;br /&gt;
  damagesWeightedByType,&lt;br /&gt;
  possibleDamagesCountTemp,&lt;br /&gt;
  totalCardinal&lt;br /&gt;
) {&lt;br /&gt;
  var minDamages = Infinity;&lt;br /&gt;
  var maxDamages = 0;&lt;br /&gt;
  var scatterDataByType = {};&lt;br /&gt;
  var sumDamages = 0;&lt;br /&gt;
  var possibleDamagesCount = 0;&lt;br /&gt;
  var uniqueDamagesCount = 0;&lt;br /&gt;
&lt;br /&gt;
  for (var damagesTypeName in damagesWeightedByType) {&lt;br /&gt;
    if (damagesTypeName === &amp;quot;miss&amp;quot;) {&lt;br /&gt;
      scatterDataByType.miss = damagesWeightedByType.miss;&lt;br /&gt;
      possibleDamagesCount++;&lt;br /&gt;
      uniqueDamagesCount++;&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var firstIteration = true;&lt;br /&gt;
    var damagesWeighted = damagesWeightedByType[damagesTypeName];&lt;br /&gt;
    var scatterData = [];&lt;br /&gt;
    scatterDataByType[damagesTypeName] = scatterData;&lt;br /&gt;
&lt;br /&gt;
    for (var damages in damagesWeighted) {&lt;br /&gt;
      damages = +damages;&lt;br /&gt;
&lt;br /&gt;
      if (firstIteration) {&lt;br /&gt;
        if (damages &amp;lt; minDamages) {&lt;br /&gt;
          minDamages = damages;&lt;br /&gt;
        }&lt;br /&gt;
        firstIteration = false;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      var weight = damagesWeighted[damages];&lt;br /&gt;
      var probability = weight / totalCardinal;&lt;br /&gt;
&lt;br /&gt;
      sumDamages += damages * weight;&lt;br /&gt;
      damagesWeighted[damages] = probability;&lt;br /&gt;
      scatterData.push({ x: damages, y: probability });&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var scatterDataLength = scatterData.length;&lt;br /&gt;
&lt;br /&gt;
    possibleDamagesCount += possibleDamagesCountTemp;&lt;br /&gt;
    uniqueDamagesCount += scatterDataLength;&lt;br /&gt;
&lt;br /&gt;
    if (damages &amp;gt; maxDamages) {&lt;br /&gt;
      maxDamages = damages;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (minDamages === Infinity) {&lt;br /&gt;
    minDamages = 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return [&lt;br /&gt;
    sumDamages / totalCardinal,&lt;br /&gt;
    minDamages,&lt;br /&gt;
    maxDamages,&lt;br /&gt;
    scatterDataByType,&lt;br /&gt;
    possibleDamagesCount,&lt;br /&gt;
    uniqueDamagesCount,&lt;br /&gt;
  ];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function aggregateDamages(scatterData, maxPoints) {&lt;br /&gt;
  var dataLength = scatterData.length;&lt;br /&gt;
  var remainingData = dataLength;&lt;br /&gt;
  var aggregateScatterData = [];&lt;br /&gt;
&lt;br /&gt;
  for (var groupIndex = 0; groupIndex &amp;lt; maxPoints; groupIndex++) {&lt;br /&gt;
    var groupLength = Math.floor(remainingData / (maxPoints - groupIndex));&lt;br /&gt;
    var startIndex = dataLength - remainingData;&lt;br /&gt;
    var aggregateDamages = 0;&lt;br /&gt;
    var aggregateProbability = 0;&lt;br /&gt;
&lt;br /&gt;
    for (var index = startIndex; index &amp;lt; startIndex + groupLength; index++) {&lt;br /&gt;
      var { x: damages, y: probability } = scatterData[index];&lt;br /&gt;
      aggregateDamages += damages * probability;&lt;br /&gt;
      aggregateProbability += probability;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    aggregateScatterData.push({&lt;br /&gt;
      x: aggregateDamages / aggregateProbability,&lt;br /&gt;
      y: aggregateProbability,&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    remainingData -= groupLength;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return aggregateScatterData;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addToDamagesChart(&lt;br /&gt;
  scatterDataByType,&lt;br /&gt;
  damagesChart,&lt;br /&gt;
  isReducePointsChecked&lt;br /&gt;
) {&lt;br /&gt;
  var { chart, datasetsStyle, maxPoints, reduceChartPointsContainer } =&lt;br /&gt;
    damagesChart;&lt;br /&gt;
  var isFirstDataset = true;&lt;br /&gt;
  var datasets = chart.data.datasets;&lt;br /&gt;
&lt;br /&gt;
  datasets.length = 0;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; datasetsStyle.length; index++) {&lt;br /&gt;
    var dataset = copyObject(datasetsStyle[index]);&lt;br /&gt;
&lt;br /&gt;
    if (!scatterDataByType.hasOwnProperty(dataset.name)) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var scatterData = scatterDataByType[dataset.name];&lt;br /&gt;
    var canBeReduced = scatterData.length &amp;gt; 2 * maxPoints;&lt;br /&gt;
&lt;br /&gt;
    dataset.hidden = !isFirstDataset;&lt;br /&gt;
    dataset.canBeReduced = canBeReduced;&lt;br /&gt;
&lt;br /&gt;
    if (canBeReduced &amp;amp;&amp;amp; isReducePointsChecked) {&lt;br /&gt;
      dataset.data = aggregateDamages(scatterData, maxPoints);&lt;br /&gt;
    } else {&lt;br /&gt;
      dataset.data = scatterData;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isFirstDataset) {&lt;br /&gt;
      isFirstDataset = false;&lt;br /&gt;
&lt;br /&gt;
      if (canBeReduced) {&lt;br /&gt;
        showElement(reduceChartPointsContainer);&lt;br /&gt;
&lt;br /&gt;
        if (!isReducePointsChecked) {&lt;br /&gt;
          handleChartAnimations(chart, false);&lt;br /&gt;
        }&lt;br /&gt;
      } else {&lt;br /&gt;
        hideElement(reduceChartPointsContainer);&lt;br /&gt;
        handleChartAnimations(chart, true);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    datasets.push(dataset);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  chart.data.missPercentage = scatterDataByType.miss;&lt;br /&gt;
  chart.update();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addToBonusVariationChart(&lt;br /&gt;
  damagesByBonus,&lt;br /&gt;
  augmentationByBonus,&lt;br /&gt;
  xLabel,&lt;br /&gt;
  chart&lt;br /&gt;
) {&lt;br /&gt;
  chart.data.datasets[0].data = damagesByBonus;&lt;br /&gt;
  chart.data.datasets[1].data = augmentationByBonus;&lt;br /&gt;
  chart.options.scales.x.title.text = xLabel;&lt;br /&gt;
  chart.update();&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleChartAnimations(chart, addAnimations) {&lt;br /&gt;
  chart.options.animation = addAnimations;&lt;br /&gt;
  chart.options.animations.colors = addAnimations;&lt;br /&gt;
  chart.options.animations.x = addAnimations;&lt;br /&gt;
  chart.options.transitions.active.animation.duration = addAnimations * 1000;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateDamagesChartDescription(&lt;br /&gt;
  uniqueDamagesCounters,&lt;br /&gt;
  uniqueDamagesCount,&lt;br /&gt;
  formatNumber&lt;br /&gt;
) {&lt;br /&gt;
  uniqueDamagesCounters.forEach(function (element) {&lt;br /&gt;
    if (uniqueDamagesCount &amp;lt;= 1) {&lt;br /&gt;
      hideElement(element.parentElement);&lt;br /&gt;
    } else {&lt;br /&gt;
      showElement(element.parentElement);&lt;br /&gt;
      element.textContent = formatNumber.format(uniqueDamagesCount);&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getMonsterName(monsterVnum) {&lt;br /&gt;
  var monsterAttributes = monsterData[monsterVnum];&lt;br /&gt;
  return monsterAttributes[monsterAttributes.length - 1];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterClass(selectedRace, classChoice, selectValueIsChanged = false) {&lt;br /&gt;
  showElement(classChoice.parentElement);&lt;br /&gt;
&lt;br /&gt;
  for (var option of classChoice.options) {&lt;br /&gt;
    if (option.getAttribute(&amp;quot;data-race&amp;quot;) === selectedRace) {&lt;br /&gt;
      if (!selectValueIsChanged) {&lt;br /&gt;
        classChoice.value = option.value;&lt;br /&gt;
        selectValueIsChanged = true;&lt;br /&gt;
      }&lt;br /&gt;
      showElement(option);&lt;br /&gt;
    } else {&lt;br /&gt;
      hideElement(option);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  if (selectedRace == &amp;quot;lycan&amp;quot;) {&lt;br /&gt;
    hideElement(classChoice.parentElement);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterWeapon(&lt;br /&gt;
  selectedRace,&lt;br /&gt;
  weaponElement,&lt;br /&gt;
  weaponCategory,&lt;br /&gt;
  allowedWeaponsPerRace,&lt;br /&gt;
  selectValueIsChanged = false&lt;br /&gt;
) {&lt;br /&gt;
  var allowedWeapons = allowedWeaponsPerRace[selectedRace];&lt;br /&gt;
&lt;br /&gt;
  if (!selectValueIsChanged) {&lt;br /&gt;
    var weaponType = weaponData[weaponElement.value][1];&lt;br /&gt;
&lt;br /&gt;
    if (!isValueInArray(weaponType, allowedWeapons)) {&lt;br /&gt;
      weaponElement.value = 0;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var children = weaponCategory.children;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; children.length; index++) {&lt;br /&gt;
    var child = children[index];&lt;br /&gt;
&lt;br /&gt;
    if (isValueInArray(index, allowedWeapons)) {&lt;br /&gt;
      showElement(child);&lt;br /&gt;
    } else {&lt;br /&gt;
      hideElement(child);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSelectedWeapon(weaponCategory) {&lt;br /&gt;
  return weaponCategory.querySelector(&amp;quot;input[type='radio']:checked&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleWeaponDisplay(weaponDisplay, newWeapon, weaponVnum) {&lt;br /&gt;
  var newImage = newWeapon.nextElementSibling.cloneNode();&lt;br /&gt;
  var newText = document.createElement(&amp;quot;span&amp;quot;);&lt;br /&gt;
  var oldImage = weaponDisplay.firstChild;&lt;br /&gt;
  var oldText = oldImage.nextElementSibling;&lt;br /&gt;
  var weaponName = createWeapon(weaponVnum).name;&lt;br /&gt;
&lt;br /&gt;
  if (weaponVnum == 0) {&lt;br /&gt;
    newText.textContent = &amp;quot; &amp;quot; + weaponName + &amp;quot; &amp;quot;;&lt;br /&gt;
  } else {&lt;br /&gt;
    var weaponLink = document.createElement(&amp;quot;a&amp;quot;);&lt;br /&gt;
    weaponLink.href = mw.util.getUrl(weaponName);&lt;br /&gt;
    weaponLink.title = weaponName;&lt;br /&gt;
    weaponLink.textContent = weaponName;&lt;br /&gt;
&lt;br /&gt;
    newText.appendChild(document.createTextNode(&amp;quot; &amp;quot;));&lt;br /&gt;
    newText.appendChild(weaponLink);&lt;br /&gt;
    newText.appendChild(document.createTextNode(&amp;quot; &amp;quot;));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  weaponDisplay.replaceChild(newImage, oldImage);&lt;br /&gt;
  weaponDisplay.replaceChild(newText, oldText);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterUpgrade(&lt;br /&gt;
  selectedRace,&lt;br /&gt;
  weaponUpgrade,&lt;br /&gt;
  weaponVnum,&lt;br /&gt;
  randomAttackValue,&lt;br /&gt;
  randomMagicAttackValue,&lt;br /&gt;
  currentUpgrade&lt;br /&gt;
) {&lt;br /&gt;
  var weapon = createWeapon(weaponVnum);&lt;br /&gt;
&lt;br /&gt;
  if (weapon.isSerpent) {&lt;br /&gt;
    showElement(randomAttackValue);&lt;br /&gt;
&lt;br /&gt;
    if (selectedRace === &amp;quot;sura&amp;quot; || selectedRace === &amp;quot;shaman&amp;quot;) {&lt;br /&gt;
      showElement(randomMagicAttackValue);&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    hideElement(randomAttackValue);&lt;br /&gt;
    hideElement(randomMagicAttackValue);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var upgradeNumber = weapon.upgrades.length;&lt;br /&gt;
&lt;br /&gt;
  if (upgradeNumber &amp;lt;= 1) {&lt;br /&gt;
    hideElement(weaponUpgrade.parentElement);&lt;br /&gt;
  } else {&lt;br /&gt;
    showElement(weaponUpgrade.parentElement);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  weaponUpgrade.innerHTML = &amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  for (var upgrade = 0; upgrade &amp;lt; upgradeNumber; upgrade++) {&lt;br /&gt;
    var option = document.createElement(&amp;quot;option&amp;quot;);&lt;br /&gt;
    option.value = upgrade;&lt;br /&gt;
    option.textContent = &amp;quot;+&amp;quot; + upgrade;&lt;br /&gt;
    weaponUpgrade.appendChild(option);&lt;br /&gt;
  }&lt;br /&gt;
  if (currentUpgrade === undefined) {&lt;br /&gt;
    option.selected = true;&lt;br /&gt;
  } else {&lt;br /&gt;
    weaponUpgrade.value = currentUpgrade;&lt;br /&gt;
    currentUpgrade = undefined;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterState(selectedState, polymorphMonster) {&lt;br /&gt;
  if (selectedState === &amp;quot;polymorph&amp;quot;) {&lt;br /&gt;
    showElement(polymorphMonster.parentElement);&lt;br /&gt;
  } else {&lt;br /&gt;
    hideElement(polymorphMonster.parentElement);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterCheckbox(checkbox, element) {&lt;br /&gt;
  if (checkbox.checked) {&lt;br /&gt;
    showElement(element);&lt;br /&gt;
  } else {&lt;br /&gt;
    hideElement(element);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterSkills(selectedClass, skillElementsToFilter) {&lt;br /&gt;
  for (var element of skillElementsToFilter) {&lt;br /&gt;
    if (isValueInArray(selectedClass, element.dataset.class)) {&lt;br /&gt;
      showElement(element);&lt;br /&gt;
    } else {&lt;br /&gt;
      hideElement(element);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterAttackTypeSelection(attacker, attackTypeSelection) {&lt;br /&gt;
  var attackerClass = attacker.class;&lt;br /&gt;
  var selectedOption =&lt;br /&gt;
    attackTypeSelection.options[attackTypeSelection.selectedIndex];&lt;br /&gt;
  var attackerIsNotPolymorph = !isPolymorph(attacker);&lt;br /&gt;
&lt;br /&gt;
  for (var index = 2; index &amp;lt; attackTypeSelection.options.length; index++) {&lt;br /&gt;
    var option = attackTypeSelection.options[index];&lt;br /&gt;
    var optionClass = option.dataset.class;&lt;br /&gt;
    var optionValue = option.value;&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      attackerIsNotPolymorph &amp;amp;&amp;amp;&lt;br /&gt;
      attacker[optionValue] &amp;amp;&amp;amp;&lt;br /&gt;
      (attackerClass === optionClass ||&lt;br /&gt;
        (optionValue.startsWith(&amp;quot;horseSkill&amp;quot;) &amp;amp;&amp;amp;&lt;br /&gt;
          isRiding(attacker) &amp;amp;&amp;amp;&lt;br /&gt;
          (!optionClass || isValueInArray(attackerClass, optionClass))))&lt;br /&gt;
    ) {&lt;br /&gt;
      showElement(option);&lt;br /&gt;
    } else {&lt;br /&gt;
      hideElement(option);&lt;br /&gt;
&lt;br /&gt;
      if (selectedOption === option) {&lt;br /&gt;
        attackTypeSelection.selectedIndex = 0;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterAttackTypeSelectionMonster(attackTypeSelection) {&lt;br /&gt;
  for (var index = 2; index &amp;lt; attackTypeSelection.options.length; index++) {&lt;br /&gt;
    hideElement(attackTypeSelection.options[index]);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (attackTypeSelection.selectedIndex !== 1) {&lt;br /&gt;
    attackTypeSelection.selectedIndex = 0;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function filterForm(characters, battle) {&lt;br /&gt;
  var characterCreation = characters.characterCreation;&lt;br /&gt;
  var allowedWeaponsPerRace = battle.constants.allowedWeaponsPerRace;&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;change&amp;quot;, function (event) {&lt;br /&gt;
    var target = event.target;&lt;br /&gt;
    var targetName = target.name;&lt;br /&gt;
&lt;br /&gt;
    switch (targetName) {&lt;br /&gt;
      case &amp;quot;race&amp;quot;:&lt;br /&gt;
        var selectedRace = target.value;&lt;br /&gt;
        var classChoice = characterCreation.class;&lt;br /&gt;
        var weaponElement = characterCreation.weapon;&lt;br /&gt;
&lt;br /&gt;
        filterClass(selectedRace, classChoice);&lt;br /&gt;
        filterWeapon(&lt;br /&gt;
          selectedRace,&lt;br /&gt;
          weaponElement,&lt;br /&gt;
          characters.weaponCategory,&lt;br /&gt;
          allowedWeaponsPerRace&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        var newWeapon = getSelectedWeapon(characters.weaponCategory);&lt;br /&gt;
        handleWeaponDisplay(&lt;br /&gt;
          characters.weaponDisplay,&lt;br /&gt;
          newWeapon,&lt;br /&gt;
          weaponElement.value&lt;br /&gt;
        );&lt;br /&gt;
        filterUpgrade(&lt;br /&gt;
          selectedRace,&lt;br /&gt;
          characterCreation.weaponUpgrade,&lt;br /&gt;
          weaponElement.value,&lt;br /&gt;
          characters.randomAttackValue,&lt;br /&gt;
          characters.randomMagicAttackValue&lt;br /&gt;
        );&lt;br /&gt;
        filterSkills(classChoice.value, characters.skillElementsToFilter);&lt;br /&gt;
&lt;br /&gt;
        if (characterCreation.name.value === battle.attackerSelection.value) {&lt;br /&gt;
          battle.resetAttackType = true;&lt;br /&gt;
        }&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;class&amp;quot;:&lt;br /&gt;
        filterSkills(target.value, characters.skillElementsToFilter);&lt;br /&gt;
&lt;br /&gt;
        if (characterCreation.name.value === battle.attackerSelection.value) {&lt;br /&gt;
          battle.resetAttackType = true;&lt;br /&gt;
        }&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;weapon&amp;quot;:&lt;br /&gt;
        handleWeaponDisplay(&lt;br /&gt;
          characters.weaponDisplay,&lt;br /&gt;
          target,&lt;br /&gt;
          characterCreation.weapon.value&lt;br /&gt;
        );&lt;br /&gt;
        filterUpgrade(&lt;br /&gt;
          characterCreation.race.value,&lt;br /&gt;
          characterCreation.weaponUpgrade,&lt;br /&gt;
          target.value,&lt;br /&gt;
          characters.randomAttackValue,&lt;br /&gt;
          characters.randomMagicAttackValue&lt;br /&gt;
        );&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;state&amp;quot;:&lt;br /&gt;
        filterState(target.value, characterCreation.polymorphMonster);&lt;br /&gt;
        if (characterCreation.name.value === battle.attackerSelection.value) {&lt;br /&gt;
          battle.resetAttackType = true;&lt;br /&gt;
        }&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;lowRank&amp;quot;:&lt;br /&gt;
        filterCheckbox(target, characterCreation.playerRank.parentElement);&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;isBlessed&amp;quot;:&lt;br /&gt;
        filterCheckbox(target, characters.blessingCreation);&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;onYohara&amp;quot;:&lt;br /&gt;
        filterCheckbox(target, characters.yoharaCreation);&lt;br /&gt;
        break;&lt;br /&gt;
      case &amp;quot;isMarried&amp;quot;:&lt;br /&gt;
        filterCheckbox(target, characters.marriageCreation);&lt;br /&gt;
        break;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      targetName.startsWith(&amp;quot;attackSkill&amp;quot;) ||&lt;br /&gt;
      targetName.startsWith(&amp;quot;horseSkill&amp;quot;)&lt;br /&gt;
    ) {&lt;br /&gt;
      battle.resetAttackType = true;&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addUniquePseudo(characterDataObject, savedCharactersPseudo) {&lt;br /&gt;
  var characterPseudo = String(characterDataObject.name);&lt;br /&gt;
  var originalPseudo = characterPseudo;&lt;br /&gt;
  var count = 0;&lt;br /&gt;
&lt;br /&gt;
  var regex = /(.*)(\d)$/;&lt;br /&gt;
  var match = characterPseudo.match(regex);&lt;br /&gt;
&lt;br /&gt;
  if (match) {&lt;br /&gt;
    originalPseudo = match[1];&lt;br /&gt;
    count = match[2];&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  while (isValueInArray(characterPseudo, savedCharactersPseudo)) {&lt;br /&gt;
    characterPseudo = originalPseudo + count;&lt;br /&gt;
    count++;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  characterDataObject.name = characterPseudo;&lt;br /&gt;
  return [characterDataObject, characterPseudo];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function convertToNumber(value) {&lt;br /&gt;
  var valueNumber = Number(value);&lt;br /&gt;
  return isNaN(valueNumber) ? value : valueNumber;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getLocalStorageValue(key, defaultValue) {&lt;br /&gt;
  var storedValue = localStorage.getItem(key);&lt;br /&gt;
&lt;br /&gt;
  if (storedValue) {&lt;br /&gt;
    return JSON.parse(storedValue);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return defaultValue;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSavedCharacters() {&lt;br /&gt;
  return getLocalStorageValue(&amp;quot;savedCharactersCalculator&amp;quot;, {});&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSavedMonsters() {&lt;br /&gt;
  return getLocalStorageValue(&amp;quot;savedMonstersCalculator&amp;quot;, []).filter(function (&lt;br /&gt;
    num&lt;br /&gt;
  ) {&lt;br /&gt;
    return !isNaN(Number(num));&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSavedFights() {&lt;br /&gt;
  return getLocalStorageValue(&amp;quot;savedFightsCalculator&amp;quot;, []);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveToLocalStorage(key, value) {&lt;br /&gt;
  localStorage.setItem(key, JSON.stringify(value));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateSavedCharacters(savedCharacters) {&lt;br /&gt;
  saveToLocalStorage(&amp;quot;savedCharactersCalculator&amp;quot;, savedCharacters);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateSavedMonsters(savedMonsters) {&lt;br /&gt;
  saveToLocalStorage(&amp;quot;savedMonstersCalculator&amp;quot;, savedMonsters);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateSavedFights(savedFights) {&lt;br /&gt;
  saveToLocalStorage(&amp;quot;savedFightsCalculator&amp;quot;, savedFights);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveCharacter(&lt;br /&gt;
  savedCharacters,&lt;br /&gt;
  characterCreation,&lt;br /&gt;
  battle,&lt;br /&gt;
  newCharacter,&lt;br /&gt;
  characterDataObject&lt;br /&gt;
) {&lt;br /&gt;
  if (!characterDataObject) {&lt;br /&gt;
    var characterData = new FormData(characterCreation);&lt;br /&gt;
    var characterDataObject = {};&lt;br /&gt;
&lt;br /&gt;
    characterData.forEach(function (value, key) {&lt;br /&gt;
      characterDataObject[key] = convertToNumber(value);&lt;br /&gt;
    });&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  savedCharacters[characterDataObject.name] = characterDataObject;&lt;br /&gt;
  updateSavedCharacters(savedCharacters);&lt;br /&gt;
&lt;br /&gt;
  if (newCharacter) {&lt;br /&gt;
    addBattleChoice(battle, characterDataObject.name);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (battle.resetAttackType) {&lt;br /&gt;
    filterAttackTypeSelection(characterDataObject, battle.attackTypeSelection);&lt;br /&gt;
    battle.resetAttackType = false;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveButtonGreen(saveButton) {&lt;br /&gt;
  saveButton.classList.remove(&amp;quot;unsaved-character&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function saveButtonOrange(saveButton) {&lt;br /&gt;
  saveButton.classList.add(&amp;quot;unsaved-character&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function characterCreationListener(characters, battle) {&lt;br /&gt;
  var { characterCreation, saveButton, weaponCategory } = characters;&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;submit&amp;quot;, function (event) {&lt;br /&gt;
    event.preventDefault();&lt;br /&gt;
&lt;br /&gt;
    if (characters.unsavedChanges) {&lt;br /&gt;
      saveCharacter(characters.savedCharacters, characterCreation, battle);&lt;br /&gt;
      saveButtonGreen(saveButton);&lt;br /&gt;
      characters.unsavedChanges = false;&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  document.addEventListener(&amp;quot;keydown&amp;quot;, function (event) {&lt;br /&gt;
    if (event.ctrlKey &amp;amp;&amp;amp; event.key === &amp;quot;s&amp;quot;) {&lt;br /&gt;
      event.preventDefault();&lt;br /&gt;
      saveButton.click();&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  weaponCategory.addEventListener(&amp;quot;mouseover&amp;quot;, function (event) {&lt;br /&gt;
    label = event.target.closest(&amp;quot;label&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (label) {&lt;br /&gt;
      var tooltip = label.lastChild;&lt;br /&gt;
&lt;br /&gt;
      if (tooltip.classList.contains(&amp;quot;popContenu&amp;quot;)) {&lt;br /&gt;
        var tooltipRect = tooltip.getBoundingClientRect();&lt;br /&gt;
        var modalRect = weaponCategory.getBoundingClientRect();&lt;br /&gt;
&lt;br /&gt;
        if (tooltipRect.right &amp;gt; modalRect.right) {&lt;br /&gt;
          tooltip.style.left = &amp;quot;-100%&amp;quot;;&lt;br /&gt;
        } else if (tooltipRect.left &amp;lt; modalRect.left) {&lt;br /&gt;
          tooltip.style.left = &amp;quot;200%&amp;quot;;&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function downloadData(content, type, filename) {&lt;br /&gt;
  var link = document.createElement(&amp;quot;a&amp;quot;);&lt;br /&gt;
  var blob = new Blob([content], { type: type });&lt;br /&gt;
  var blobURL = URL.createObjectURL(blob);&lt;br /&gt;
&lt;br /&gt;
  link.href = blobURL;&lt;br /&gt;
  link.download = filename;&lt;br /&gt;
  document.body.appendChild(link);&lt;br /&gt;
&lt;br /&gt;
  link.click();&lt;br /&gt;
  document.body.removeChild(link);&lt;br /&gt;
  URL.revokeObjectURL(blobURL);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function uploadCharacter(&lt;br /&gt;
  selectedFiles,&lt;br /&gt;
  characters,&lt;br /&gt;
  characterTemplate,&lt;br /&gt;
  charactersContainer,&lt;br /&gt;
  battle&lt;br /&gt;
) {&lt;br /&gt;
  var selectFilesLength = selectedFiles.length;&lt;br /&gt;
&lt;br /&gt;
  for (var fileIndex = 0; fileIndex &amp;lt; selectFilesLength; fileIndex++) {&lt;br /&gt;
    var selectedFile = selectedFiles[fileIndex];&lt;br /&gt;
&lt;br /&gt;
    if (selectedFile.type === &amp;quot;text/plain&amp;quot;) {&lt;br /&gt;
      var reader = new FileReader();&lt;br /&gt;
      reader.onload = function (e) {&lt;br /&gt;
        var fileContent = e.target.result;&lt;br /&gt;
        try {&lt;br /&gt;
          var characterDataObject = JSON.parse(fileContent);&lt;br /&gt;
&lt;br /&gt;
          if (characterDataObject.hasOwnProperty(&amp;quot;name&amp;quot;)) {&lt;br /&gt;
            var characterPseudo = String(characterDataObject.name);&lt;br /&gt;
&lt;br /&gt;
            hideElement(characters.characterCreation);&lt;br /&gt;
            characterPseudo = validPseudo(characterPseudo);&lt;br /&gt;
&lt;br /&gt;
            [characterDataObject, characterPseudo] = addUniquePseudo(&lt;br /&gt;
              characterDataObject,&lt;br /&gt;
              Object.keys(characters.savedCharacters)&lt;br /&gt;
            );&lt;br /&gt;
            var selectedCharacter = handleNewCharacter(&lt;br /&gt;
              characters,&lt;br /&gt;
              characterTemplate,&lt;br /&gt;
              charactersContainer,&lt;br /&gt;
              battle,&lt;br /&gt;
              characterPseudo&lt;br /&gt;
            )[0];&lt;br /&gt;
&lt;br /&gt;
            if (selectFilesLength === 1) {&lt;br /&gt;
              updateForm(&lt;br /&gt;
                characterDataObject,&lt;br /&gt;
                characters.characterCreation,&lt;br /&gt;
                characters,&lt;br /&gt;
                selectedCharacter,&lt;br /&gt;
                battle&lt;br /&gt;
              );&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            saveCharacter(&lt;br /&gt;
              characters.savedCharacters,&lt;br /&gt;
              characters.characterCreation,&lt;br /&gt;
              battle,&lt;br /&gt;
              true,&lt;br /&gt;
              characterDataObject&lt;br /&gt;
            );&lt;br /&gt;
          }&lt;br /&gt;
        } catch (error) {&lt;br /&gt;
          console.log(error);&lt;br /&gt;
          if (error.name === &amp;quot;TypeError&amp;quot;) {&lt;br /&gt;
            // delete the character&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
      };&lt;br /&gt;
      reader.readAsText(selectedFile);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleUploadCharacter(&lt;br /&gt;
  characters,&lt;br /&gt;
  characterTemplate,&lt;br /&gt;
  charactersContainer,&lt;br /&gt;
  battle&lt;br /&gt;
) {&lt;br /&gt;
  var characterInput = characters.characterInput;&lt;br /&gt;
  var dropZone = characters.dropZone;&lt;br /&gt;
&lt;br /&gt;
  characterInput.accept = &amp;quot;.txt&amp;quot;;&lt;br /&gt;
  characterInput.multiple = true;&lt;br /&gt;
  dropZone.setAttribute(&amp;quot;tabindex&amp;quot;, &amp;quot;0&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  dropZone.addEventListener(&amp;quot;click&amp;quot;, function () {&lt;br /&gt;
    characterInput.click();&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  dropZone.addEventListener(&amp;quot;dragover&amp;quot;, function (event) {&lt;br /&gt;
    event.preventDefault();&lt;br /&gt;
    dropZone.classList.add(&amp;quot;drop-zone--dragover&amp;quot;);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  [&amp;quot;dragleave&amp;quot;, &amp;quot;dragend&amp;quot;].forEach(function (type) {&lt;br /&gt;
    dropZone.addEventListener(type, function () {&lt;br /&gt;
      dropZone.classList.remove(&amp;quot;drop-zone--dragover&amp;quot;);&lt;br /&gt;
    });&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  dropZone.addEventListener(&amp;quot;drop&amp;quot;, function (event) {&lt;br /&gt;
    event.preventDefault();&lt;br /&gt;
    uploadCharacter(&lt;br /&gt;
      event.dataTransfer.files,&lt;br /&gt;
      characters,&lt;br /&gt;
      characterTemplate,&lt;br /&gt;
      charactersContainer,&lt;br /&gt;
      battle&lt;br /&gt;
    );&lt;br /&gt;
    dropZone.classList.remove(&amp;quot;drop-zone--dragover&amp;quot;);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  characterInput.addEventListener(&amp;quot;change&amp;quot;, function (event) {&lt;br /&gt;
    uploadCharacter(&lt;br /&gt;
      event.target.files,&lt;br /&gt;
      characters,&lt;br /&gt;
      characterTemplate,&lt;br /&gt;
      charactersContainer,&lt;br /&gt;
      battle&lt;br /&gt;
    );&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function deleteCharacter(characters, pseudo, element, battle) {&lt;br /&gt;
  battle.battleForm.reset();&lt;br /&gt;
  delete characters.savedCharacters[pseudo];&lt;br /&gt;
  element.remove();&lt;br /&gt;
&lt;br /&gt;
  updateSavedCharacters(characters.savedCharacters);&lt;br /&gt;
  removeBattleChoice(battle, pseudo);&lt;br /&gt;
&lt;br /&gt;
  if (&lt;br /&gt;
    !Object.keys(characters.savedCharacters).length ||&lt;br /&gt;
    characters.characterCreation.name.value === pseudo&lt;br /&gt;
  ) {&lt;br /&gt;
    saveButtonGreen(characters.saveButton);&lt;br /&gt;
    characters.unsavedChanges = false;&lt;br /&gt;
    hideElement(characters.characterCreation);&lt;br /&gt;
    showElement(characters.characterCreation.previousElementSibling);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function deleteMonster(characters, monsterVnum, element, battle) {&lt;br /&gt;
  battle.battleForm.reset();&lt;br /&gt;
  characters.savedMonsters.splice(&lt;br /&gt;
    characters.savedMonsters.indexOf(monsterVnum),&lt;br /&gt;
    1&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  if (element) {&lt;br /&gt;
    element.remove();&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  updateSavedMonsters(characters.savedMonsters);&lt;br /&gt;
  removeBattleChoice(battle, monsterVnum);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleStyle(characters, selectedElement) {&lt;br /&gt;
  var currentCharacter = characters.currentCharacter;&lt;br /&gt;
&lt;br /&gt;
  if (currentCharacter) {&lt;br /&gt;
    currentCharacter.classList.remove(&amp;quot;selected-character&amp;quot;);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  selectedElement.classList.add(&amp;quot;selected-character&amp;quot;);&lt;br /&gt;
  characters.currentCharacter = selectedElement;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateForm(&lt;br /&gt;
  formData,&lt;br /&gt;
  characterCreation,&lt;br /&gt;
  characters,&lt;br /&gt;
  selectedElement,&lt;br /&gt;
  battle&lt;br /&gt;
) {&lt;br /&gt;
  saveButtonGreen(characters.saveButton);&lt;br /&gt;
  hideElement(characterCreation.previousElementSibling);&lt;br /&gt;
  showElement(characterCreation);&lt;br /&gt;
  handleStyle(characters, selectedElement);&lt;br /&gt;
&lt;br /&gt;
  characterCreation.reset();&lt;br /&gt;
&lt;br /&gt;
  for (var [name, value] of Object.entries(formData)) {&lt;br /&gt;
    var formElement = characterCreation[name];&lt;br /&gt;
&lt;br /&gt;
    if (!formElement) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (formElement.type === &amp;quot;checkbox&amp;quot;) {&lt;br /&gt;
      if (isChecked(value)) {&lt;br /&gt;
        formElement.checked = true;&lt;br /&gt;
      }&lt;br /&gt;
    } else {&lt;br /&gt;
      formElement.value = value;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
  var selectedRace = characterCreation.race.value;&lt;br /&gt;
  var classChoice = characterCreation.class;&lt;br /&gt;
  var weaponElement = characterCreation.weapon;&lt;br /&gt;
&lt;br /&gt;
  filterClass(selectedRace, classChoice, true);&lt;br /&gt;
  filterWeapon(&lt;br /&gt;
    selectedRace,&lt;br /&gt;
    weaponElement,&lt;br /&gt;
    characters.weaponCategory,&lt;br /&gt;
    battle.constants.allowedWeaponsPerRace,&lt;br /&gt;
    true&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  var newWeapon = getSelectedWeapon(characters.weaponCategory);&lt;br /&gt;
&lt;br /&gt;
  handleWeaponDisplay(characters.weaponDisplay, newWeapon, weaponElement.value);&lt;br /&gt;
  filterUpgrade(&lt;br /&gt;
    selectedRace,&lt;br /&gt;
    characterCreation.weaponUpgrade,&lt;br /&gt;
    weaponElement.value,&lt;br /&gt;
    characters.randomAttackValue,&lt;br /&gt;
    characters.randomMagicAttackValue,&lt;br /&gt;
    formData.weaponUpgrade&lt;br /&gt;
  );&lt;br /&gt;
  filterState(&lt;br /&gt;
    characterCreation.state.value,&lt;br /&gt;
    characterCreation.polymorphMonster&lt;br /&gt;
  );&lt;br /&gt;
  filterCheckbox(&lt;br /&gt;
    characterCreation.lowRank,&lt;br /&gt;
    characterCreation.playerRank.parentElement&lt;br /&gt;
  );&lt;br /&gt;
  filterCheckbox(characterCreation.onYohara, characters.yoharaCreation);&lt;br /&gt;
  filterCheckbox(characterCreation.isBlessed, characters.blessingCreation);&lt;br /&gt;
  filterCheckbox(characterCreation.isMarried, characters.marriageCreation);&lt;br /&gt;
  filterSkills(classChoice.value, characters.skillElementsToFilter);&lt;br /&gt;
  handleBonusVariationUpdate(characterCreation, characters.bonusVariation);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleClickOnCharacter(&lt;br /&gt;
  spanInput,&lt;br /&gt;
  target,&lt;br /&gt;
  characters,&lt;br /&gt;
  characterElement,&lt;br /&gt;
  battle,&lt;br /&gt;
  edition&lt;br /&gt;
) {&lt;br /&gt;
  var displayedPseudo = characters.characterCreation.name.value;&lt;br /&gt;
  var pseudo = spanInput.dataset.name;&lt;br /&gt;
&lt;br /&gt;
  if (edition) {&lt;br /&gt;
    if (!characters.unsavedChanges) {&lt;br /&gt;
      updateForm(&lt;br /&gt;
        characters.savedCharacters[pseudo],&lt;br /&gt;
        characters.characterCreation,&lt;br /&gt;
        characters,&lt;br /&gt;
        characterElement,&lt;br /&gt;
        battle&lt;br /&gt;
      );&lt;br /&gt;
    } else if (displayedPseudo === pseudo) {&lt;br /&gt;
      // pass&lt;br /&gt;
    } else {&lt;br /&gt;
      var result = confirm(&lt;br /&gt;
        &amp;quot;Voulez-vous continuer ? Les dernières modifications ne seront pas sauvegardées.&amp;quot;&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      if (result) {&lt;br /&gt;
        updateForm(&lt;br /&gt;
          characters.savedCharacters[pseudo],&lt;br /&gt;
          characters.characterCreation,&lt;br /&gt;
          characters,&lt;br /&gt;
          characterElement,&lt;br /&gt;
          battle&lt;br /&gt;
        );&lt;br /&gt;
        characters.unsavedChanges = false;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    if (target.tagName === &amp;quot;path&amp;quot;) {&lt;br /&gt;
      target = target.parentElement;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    switch (target.dataset.icon) {&lt;br /&gt;
      case &amp;quot;duplicate&amp;quot;:&lt;br /&gt;
        if (!characters.unsavedChanges) {&lt;br /&gt;
          addNewCharacter(&lt;br /&gt;
            characters,&lt;br /&gt;
            characters.newCharacterTemplate,&lt;br /&gt;
            characters.charactersContainer,&lt;br /&gt;
            battle,&lt;br /&gt;
            pseudo&lt;br /&gt;
          );&lt;br /&gt;
        } else {&lt;br /&gt;
          var result = confirm(&lt;br /&gt;
            &amp;quot;Voulez-vous continuer ? Les dernières modifications ne seront pas sauvegardées.&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
&lt;br /&gt;
          if (result) {&lt;br /&gt;
            addNewCharacter(&lt;br /&gt;
              characters,&lt;br /&gt;
              characters.newCharacterTemplate,&lt;br /&gt;
              characters.charactersContainer,&lt;br /&gt;
              battle,&lt;br /&gt;
              pseudo&lt;br /&gt;
            );&lt;br /&gt;
            saveButtonGreen(characters.saveButton);&lt;br /&gt;
            characters.unsavedChanges = false;&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
        break;&lt;br /&gt;
&lt;br /&gt;
      case &amp;quot;download&amp;quot;:&lt;br /&gt;
        var character = characters.savedCharacters[pseudo];&lt;br /&gt;
        downloadData(&lt;br /&gt;
          JSON.stringify(character),&lt;br /&gt;
          &amp;quot;text/plain&amp;quot;,&lt;br /&gt;
          character.name + &amp;quot;.txt&amp;quot;&lt;br /&gt;
        );&lt;br /&gt;
        break;&lt;br /&gt;
&lt;br /&gt;
      case &amp;quot;delete&amp;quot;:&lt;br /&gt;
        var result = confirm(&lt;br /&gt;
          &amp;quot;Voulez-vous vraiment supprimer définitivement le personnage &amp;quot; +&lt;br /&gt;
            pseudo +&lt;br /&gt;
            &amp;quot; ?&amp;quot;&lt;br /&gt;
        );&lt;br /&gt;
        if (result) {&lt;br /&gt;
          deleteCharacter(characters, pseudo, characterElement, battle);&lt;br /&gt;
        }&lt;br /&gt;
        break;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleNewCharacter(&lt;br /&gt;
  characters,&lt;br /&gt;
  characterTemplate,&lt;br /&gt;
  charactersContainer,&lt;br /&gt;
  battle,&lt;br /&gt;
  pseudo&lt;br /&gt;
) {&lt;br /&gt;
  var newCharacterTemplate = characterTemplate.cloneNode(true);&lt;br /&gt;
  var spanInput = newCharacterTemplate.querySelector(&amp;quot;span.input&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  newCharacterTemplate.setAttribute(&amp;quot;tabindex&amp;quot;, &amp;quot;0&amp;quot;);&lt;br /&gt;
  charactersContainer.appendChild(newCharacterTemplate);&lt;br /&gt;
&lt;br /&gt;
  if (pseudo) {&lt;br /&gt;
    spanInput.textContent = pseudo;&lt;br /&gt;
    spanInput.setAttribute(&amp;quot;data-name&amp;quot;, pseudo);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  newCharacterTemplate.addEventListener(&amp;quot;click&amp;quot;, function (event) {&lt;br /&gt;
    var target = event.target;&lt;br /&gt;
&lt;br /&gt;
    if (target.tagName === &amp;quot;path&amp;quot; || target.tagName === &amp;quot;svg&amp;quot;) {&lt;br /&gt;
      handleClickOnCharacter(&lt;br /&gt;
        spanInput,&lt;br /&gt;
        target,&lt;br /&gt;
        characters,&lt;br /&gt;
        newCharacterTemplate,&lt;br /&gt;
        battle&lt;br /&gt;
      );&lt;br /&gt;
    } else {&lt;br /&gt;
      handleClickOnCharacter(&lt;br /&gt;
        spanInput,&lt;br /&gt;
        null,&lt;br /&gt;
        characters,&lt;br /&gt;
        newCharacterTemplate,&lt;br /&gt;
        battle,&lt;br /&gt;
        true&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  newCharacterTemplate.addEventListener(&amp;quot;keydown&amp;quot;, function (event) {&lt;br /&gt;
    if (event.keyCode === 13) {&lt;br /&gt;
      event.target.click();&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  return [newCharacterTemplate, spanInput];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function validPseudo(pseudo) {&lt;br /&gt;
  var newPseudo = pseudoFormat(pseudo);&lt;br /&gt;
&lt;br /&gt;
  if (!newPseudo) {&lt;br /&gt;
    return &amp;quot;Pseudo&amp;quot;;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return newPseudo;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addNewCharacter(&lt;br /&gt;
  characters,&lt;br /&gt;
  characterTemplate,&lt;br /&gt;
  charactersContainer,&lt;br /&gt;
  battle,&lt;br /&gt;
  pseudoToDuplicate&lt;br /&gt;
) {&lt;br /&gt;
  function editAndSetCharacterPseudoInput(selectedCharacter, spanInput) {&lt;br /&gt;
    var maxPseudoLength = 20;&lt;br /&gt;
&lt;br /&gt;
    var selection = window.getSelection();&lt;br /&gt;
    var range = document.createRange();&lt;br /&gt;
&lt;br /&gt;
    if (pseudoToDuplicate) {&lt;br /&gt;
      spanInput.textContent = pseudoToDuplicate;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    spanInput.contentEditable = true;&lt;br /&gt;
    spanInput.focus();&lt;br /&gt;
    range.selectNodeContents(spanInput);&lt;br /&gt;
    selection.removeAllRanges();&lt;br /&gt;
    selection.addRange(range);&lt;br /&gt;
&lt;br /&gt;
    function pseudoValidation() {&lt;br /&gt;
      var characterPseudo = validPseudo(spanInput.textContent);&lt;br /&gt;
      var characterDataObject = { name: characterPseudo };&lt;br /&gt;
&lt;br /&gt;
      if (pseudoToDuplicate) {&lt;br /&gt;
        characterDataObject = copyObject(&lt;br /&gt;
          characters.savedCharacters[pseudoToDuplicate]&lt;br /&gt;
        );&lt;br /&gt;
        characterDataObject.name = characterPseudo;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      [characterDataObject, characterPseudo] = addUniquePseudo(&lt;br /&gt;
        characterDataObject,&lt;br /&gt;
        Object.keys(characters.savedCharacters)&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      selection.removeAllRanges();&lt;br /&gt;
      spanInput.contentEditable = false;&lt;br /&gt;
      spanInput.textContent = characterPseudo;&lt;br /&gt;
      spanInput.setAttribute(&amp;quot;data-name&amp;quot;, characterPseudo);&lt;br /&gt;
&lt;br /&gt;
      updateForm(&lt;br /&gt;
        characterDataObject,&lt;br /&gt;
        characters.characterCreation,&lt;br /&gt;
        characters,&lt;br /&gt;
        selectedCharacter,&lt;br /&gt;
        battle&lt;br /&gt;
      );&lt;br /&gt;
      saveCharacter(&lt;br /&gt;
        characters.savedCharacters,&lt;br /&gt;
        characters.characterCreation,&lt;br /&gt;
        battle,&lt;br /&gt;
        true&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handleMaxLength(event) {&lt;br /&gt;
      if (spanInput.textContent.length &amp;gt; maxPseudoLength) {&lt;br /&gt;
        spanInput.textContent = spanInput.textContent.slice(0, maxPseudoLength);&lt;br /&gt;
        range.setStart(spanInput.childNodes[0], maxPseudoLength);&lt;br /&gt;
        selection.removeAllRanges();&lt;br /&gt;
        selection.addRange(range);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handleBlur() {&lt;br /&gt;
      spanInput.removeEventListener(&amp;quot;blur&amp;quot;, handleBlur);&lt;br /&gt;
      spanInput.removeEventListener(&amp;quot;input&amp;quot;, handleMaxLength);&lt;br /&gt;
      pseudoValidation();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function handleKeyDown(event) {&lt;br /&gt;
      if (event.key === &amp;quot;Enter&amp;quot;) {&lt;br /&gt;
        event.preventDefault();&lt;br /&gt;
&lt;br /&gt;
        spanInput.removeEventListener(&amp;quot;keydown&amp;quot;, handleKeyDown);&lt;br /&gt;
        spanInput.removeEventListener(&amp;quot;blur&amp;quot;, handleBlur);&lt;br /&gt;
        spanInput.removeEventListener(&amp;quot;input&amp;quot;, handleMaxLength);&lt;br /&gt;
&lt;br /&gt;
        pseudoValidation();&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    spanInput.addEventListener(&amp;quot;input&amp;quot;, handleMaxLength);&lt;br /&gt;
    spanInput.addEventListener(&amp;quot;keydown&amp;quot;, handleKeyDown);&lt;br /&gt;
    spanInput.addEventListener(&amp;quot;blur&amp;quot;, handleBlur);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  hideElement(characters.characterCreation);&lt;br /&gt;
  var [selectedCharacter, spanInput] = handleNewCharacter(&lt;br /&gt;
    characters,&lt;br /&gt;
    characterTemplate,&lt;br /&gt;
    charactersContainer,&lt;br /&gt;
    battle&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  editAndSetCharacterPseudoInput(selectedCharacter, spanInput);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleFocus() {&lt;br /&gt;
  var tooltipLinks = document.querySelectorAll(&amp;quot;div.tooltip a&amp;quot;);&lt;br /&gt;
  tooltipLinks.forEach(function (link) {&lt;br /&gt;
    link.setAttribute(&amp;quot;tabindex&amp;quot;, -1);&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleBonusVariationUpdate(characterCreation, bonusVariation) {&lt;br /&gt;
  var selectedBonus = characterCreation.bonusVariation.value;&lt;br /&gt;
&lt;br /&gt;
  if (characterCreation.hasOwnProperty(selectedBonus)) {&lt;br /&gt;
    handleBonusVariation(characterCreation[selectedBonus], bonusVariation);&lt;br /&gt;
  } else {&lt;br /&gt;
    var { minValue, maxValue } = bonusVariation;&lt;br /&gt;
&lt;br /&gt;
    minValue.removeAttribute(&amp;quot;min&amp;quot;);&lt;br /&gt;
    minValue.removeAttribute(&amp;quot;max&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    maxValue.removeAttribute(&amp;quot;min&amp;quot;);&lt;br /&gt;
    maxValue.removeAttribute(&amp;quot;max&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    hideElement(bonusVariation.container);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getTargetContent(targetParent, targetName, isSkill) {&lt;br /&gt;
  var targetContent = &amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  if (targetParent.children.length &amp;lt;= 1) {&lt;br /&gt;
    targetContent = targetParent.textContent;&lt;br /&gt;
  } else if (targetName === &amp;quot;weaponUpgrade&amp;quot;) {&lt;br /&gt;
    targetContent = targetParent.children[1].textContent;&lt;br /&gt;
  } else if (isSkill) {&lt;br /&gt;
    var container = targetParent.children[1];&lt;br /&gt;
&lt;br /&gt;
    for (var index = 1; index &amp;lt; container.children.length; index++) {&lt;br /&gt;
      var element = container.children[index];&lt;br /&gt;
&lt;br /&gt;
      if (element.checkVisibility()) {&lt;br /&gt;
        targetContent += element.textContent;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    for (var index = 1; index &amp;lt; targetParent.children.length; index++) {&lt;br /&gt;
      var element = targetParent.children[index];&lt;br /&gt;
&lt;br /&gt;
      if (element.checkVisibility()) {&lt;br /&gt;
        targetContent += element.textContent;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return targetContent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleBonusVariation(target, bonusVariation, isSelectedByUser) {&lt;br /&gt;
  var { activation, inputDisplay, minValue, maxValue, container } =&lt;br /&gt;
    bonusVariation;&lt;br /&gt;
&lt;br /&gt;
  var {&lt;br /&gt;
    min: targetMin,&lt;br /&gt;
    max: targetMax,&lt;br /&gt;
    name: targetName,&lt;br /&gt;
    value: targetValue,&lt;br /&gt;
    parentElement: targetParent,&lt;br /&gt;
    tagName,&lt;br /&gt;
  } = target;&lt;br /&gt;
&lt;br /&gt;
  targetMin = Number(targetMin);&lt;br /&gt;
  targetMax = Number(targetMax);&lt;br /&gt;
  targetValue = Number(targetValue);&lt;br /&gt;
&lt;br /&gt;
  var isSkill = tagName === &amp;quot;SELECT&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  if (container.contains(target) || targetName == 0) {&lt;br /&gt;
    if (!isSelectedByUser) {&lt;br /&gt;
      hideElement(container);&lt;br /&gt;
    }&lt;br /&gt;
    return;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (isSkill) {&lt;br /&gt;
    var options = target.options;&lt;br /&gt;
&lt;br /&gt;
    targetMin = options[0].value;&lt;br /&gt;
    targetMax = options[options.length - 1].value;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  minValue.min = targetMin;&lt;br /&gt;
  minValue.max = targetMax;&lt;br /&gt;
&lt;br /&gt;
  maxValue.min = targetMin;&lt;br /&gt;
  maxValue.max = targetMax;&lt;br /&gt;
&lt;br /&gt;
  if (isSelectedByUser) {&lt;br /&gt;
    var { input, tab } = bonusVariation;&lt;br /&gt;
&lt;br /&gt;
    inputDisplay.value = getTargetContent(targetParent, targetName, isSkill);&lt;br /&gt;
&lt;br /&gt;
    input.value = targetName;&lt;br /&gt;
    minValue.value = Math.max(targetValue - 10, targetMin);&lt;br /&gt;
    maxValue.value = Math.min(targetValue + 10, targetMax);&lt;br /&gt;
&lt;br /&gt;
    activation.checked = true;&lt;br /&gt;
&lt;br /&gt;
    tab.click();&lt;br /&gt;
    tab.scrollIntoView(true);&lt;br /&gt;
&lt;br /&gt;
    input.dispatchEvent(new Event(&amp;quot;change&amp;quot;, { bubbles: true }));&lt;br /&gt;
  } else {&lt;br /&gt;
    if (minValue.value &amp;lt; targetMin) {&lt;br /&gt;
      minValue.value = targetMin;&lt;br /&gt;
      minValue.dispatchEvent(new Event(&amp;quot;change&amp;quot;, { bubbles: true }));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (maxValue.value &amp;gt; targetMax) {&lt;br /&gt;
      maxValue.value = targetMax;&lt;br /&gt;
      maxValue.dispatchEvent(new Event(&amp;quot;change&amp;quot;, { bubbles: true }));&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  inputDisplay.style.width = inputDisplay.value.length * 0.55 + &amp;quot;em&amp;quot;;&lt;br /&gt;
  showElement(container);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function characterManagement(characters, battle) {&lt;br /&gt;
  var {&lt;br /&gt;
    newCharacterTemplate: characterTemplate,&lt;br /&gt;
    charactersContainer,&lt;br /&gt;
    addNewCharacterButton,&lt;br /&gt;
    saveButton,&lt;br /&gt;
    characterCreation,&lt;br /&gt;
    bonusVariation,&lt;br /&gt;
  } = characters;&lt;br /&gt;
&lt;br /&gt;
  Object.keys(characters.savedCharacters).forEach(function (pseudo) {&lt;br /&gt;
    handleNewCharacter(&lt;br /&gt;
      characters,&lt;br /&gt;
      characterTemplate,&lt;br /&gt;
      charactersContainer,&lt;br /&gt;
      battle,&lt;br /&gt;
      pseudo&lt;br /&gt;
    );&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  addNewCharacterButton.addEventListener(&amp;quot;click&amp;quot;, function (event) {&lt;br /&gt;
    if (!characters.unsavedChanges) {&lt;br /&gt;
      addNewCharacter(&lt;br /&gt;
        characters,&lt;br /&gt;
        characterTemplate,&lt;br /&gt;
        charactersContainer,&lt;br /&gt;
        battle&lt;br /&gt;
      );&lt;br /&gt;
    } else {&lt;br /&gt;
      var result = confirm(&lt;br /&gt;
        &amp;quot;Voulez-vous continuer ? Les dernières modifications ne seront pas sauvegardées.&amp;quot;&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      if (result) {&lt;br /&gt;
        addNewCharacter(&lt;br /&gt;
          characters,&lt;br /&gt;
          characterTemplate,&lt;br /&gt;
          charactersContainer,&lt;br /&gt;
          battle&lt;br /&gt;
        );&lt;br /&gt;
        saveButtonGreen(saveButton);&lt;br /&gt;
        characters.unsavedChanges = false;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  handleUploadCharacter(&lt;br /&gt;
    characters,&lt;br /&gt;
    characterTemplate,&lt;br /&gt;
    charactersContainer,&lt;br /&gt;
    battle&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;change&amp;quot;, function () {&lt;br /&gt;
    saveButtonOrange(saveButton);&lt;br /&gt;
    characters.unsavedChanges = true;&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  function handleLongPress(target) {&lt;br /&gt;
    if (target.tagName !== &amp;quot;INPUT&amp;quot; &amp;amp;&amp;amp; target.tagName !== &amp;quot;SELECT&amp;quot;) {&lt;br /&gt;
      target = target.querySelector(&amp;quot;input&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      !target ||&lt;br /&gt;
      (target.type !== &amp;quot;number&amp;quot; &amp;amp;&amp;amp;&lt;br /&gt;
        !target.classList.contains(&amp;quot;skill-select&amp;quot;) &amp;amp;&amp;amp;&lt;br /&gt;
        target.name !== &amp;quot;weaponUpgrade&amp;quot;)&lt;br /&gt;
    ) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    handleBonusVariation(target, bonusVariation, true);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;click&amp;quot;, function (event) {&lt;br /&gt;
    if (event.shiftKey || event.ctrlKey) {&lt;br /&gt;
      handleLongPress(event.target);&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  var longPressTimer;&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;touchstart&amp;quot;, function (event) {&lt;br /&gt;
    longPressTimer = setTimeout(function () {&lt;br /&gt;
      handleLongPress(event.target);&lt;br /&gt;
    }, 800);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;touchend&amp;quot;, function () {&lt;br /&gt;
    clearTimeout(longPressTimer);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  characterCreation.addEventListener(&amp;quot;touchmove&amp;quot;, function () {&lt;br /&gt;
    clearTimeout(longPressTimer);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  filterForm(characters, battle);&lt;br /&gt;
  characterCreationListener(characters, battle);&lt;br /&gt;
  handleFocus();&lt;br /&gt;
&lt;br /&gt;
  window.addEventListener(&amp;quot;beforeunload&amp;quot;, function (event) {&lt;br /&gt;
    if (characters.unsavedChanges) {&lt;br /&gt;
      event.preventDefault();&lt;br /&gt;
      return &amp;quot;&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function handleNewMonster(&lt;br /&gt;
  characters,&lt;br /&gt;
  monsterTemplate,&lt;br /&gt;
  monstersContainer,&lt;br /&gt;
  battle,&lt;br /&gt;
  monsterVnum,&lt;br /&gt;
  monsterList&lt;br /&gt;
) {&lt;br /&gt;
  var newMonsterTemplate = monsterTemplate.cloneNode(true);&lt;br /&gt;
  var spanInput = newMonsterTemplate.querySelector(&amp;quot;span.input&amp;quot;);&lt;br /&gt;
  var deleteSvg = newMonsterTemplate.querySelector(&amp;quot;svg&amp;quot;);&lt;br /&gt;
  var monsterName = getMonsterName(monsterVnum);&lt;br /&gt;
&lt;br /&gt;
  var link = document.createElement(&amp;quot;a&amp;quot;);&lt;br /&gt;
  link.href = mw.util.getUrl(monsterName);&lt;br /&gt;
  link.title = monsterName;&lt;br /&gt;
  link.textContent = monsterName;&lt;br /&gt;
&lt;br /&gt;
  spanInput.appendChild(link);&lt;br /&gt;
  monstersContainer.appendChild(newMonsterTemplate);&lt;br /&gt;
&lt;br /&gt;
  newMonsterTemplate.setAttribute(&amp;quot;tabindex&amp;quot;, &amp;quot;0&amp;quot;);&lt;br /&gt;
  newMonsterTemplate.setAttribute(&amp;quot;data-name&amp;quot;, monsterVnum);&lt;br /&gt;
  monstersContainer.appendChild(newMonsterTemplate);&lt;br /&gt;
&lt;br /&gt;
  deleteSvg.addEventListener(&amp;quot;click&amp;quot;, function (event) {&lt;br /&gt;
    deleteMonster(characters, monsterVnum, newMonsterTemplate, battle);&lt;br /&gt;
    var inputMonster = monsterList.querySelector(&lt;br /&gt;
      &amp;quot;input[name='&amp;quot; + monsterVnum + &amp;quot;']&amp;quot;&lt;br /&gt;
    );&lt;br /&gt;
    inputMonster.checked = false;&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function monsterManagement(characters, battle) {&lt;br /&gt;
  function handleDropdown(searchMonster, monsterList) {&lt;br /&gt;
    searchMonster.addEventListener(&amp;quot;focus&amp;quot;, function (event) {&lt;br /&gt;
      showElement(monsterList);&lt;br /&gt;
    });&lt;br /&gt;
&lt;br /&gt;
    document.addEventListener(&amp;quot;mousedown&amp;quot;, function (event) {&lt;br /&gt;
      var target = event.target;&lt;br /&gt;
      if (!monsterList.contains(target) &amp;amp;&amp;amp; !searchMonster.contains(target)) {&lt;br /&gt;
        hideElement(monsterList);&lt;br /&gt;
      }&lt;br /&gt;
    });&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function addMonsterNames(monsterList) {&lt;br /&gt;
    var lastMonsterAttributeIndex = monsterData[101].length - 1;&lt;br /&gt;
&lt;br /&gt;
    for (var monsterVnum in monsterData) {&lt;br /&gt;
      var li = document.createElement(&amp;quot;li&amp;quot;);&lt;br /&gt;
      var label = document.createElement(&amp;quot;label&amp;quot;);&lt;br /&gt;
      var input = document.createElement(&amp;quot;input&amp;quot;);&lt;br /&gt;
      var textNode = document.createTextNode(&lt;br /&gt;
        monsterData[monsterVnum][lastMonsterAttributeIndex]&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      label.htmlFor = &amp;quot;monster&amp;quot; + monsterVnum;&lt;br /&gt;
      input.id = &amp;quot;monster&amp;quot; + monsterVnum;&lt;br /&gt;
      input.type = &amp;quot;checkbox&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
      input.name = monsterVnum;&lt;br /&gt;
&lt;br /&gt;
      label.appendChild(input);&lt;br /&gt;
      label.appendChild(textNode);&lt;br /&gt;
      li.appendChild(label);&lt;br /&gt;
      monsterList.appendChild(li);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  function filterNames(searchMonster, monsterList) {&lt;br /&gt;
    var debounceTimer;&lt;br /&gt;
&lt;br /&gt;
    searchMonster.addEventListener(&amp;quot;input&amp;quot;, function (event) {&lt;br /&gt;
      clearTimeout(debounceTimer);&lt;br /&gt;
      debounceTimer = setTimeout(function () {&lt;br /&gt;
        var value = toNormalForm(event.target.value);&lt;br /&gt;
        for (var element of monsterList.children) {&lt;br /&gt;
          if (!isValueInArray(value, toNormalForm(element.textContent))) {&lt;br /&gt;
            hideElement(element);&lt;br /&gt;
          } else {&lt;br /&gt;
            showElement(element);&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
      }, 500);&lt;br /&gt;
    });&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var monsterTemplate = characters.newMonsterTemplate;&lt;br /&gt;
  var monstersContainer = characters.monstersContainer;&lt;br /&gt;
  var monsterList = characters.monsterList;&lt;br /&gt;
  var searchMonster = characters.searchMonster;&lt;br /&gt;
  var monsterListForm = characters.monsterListForm;&lt;br /&gt;
&lt;br /&gt;
  document&lt;br /&gt;
    .getElementById(&amp;quot;monster-link&amp;quot;)&lt;br /&gt;
    .querySelector(&amp;quot;a&amp;quot;)&lt;br /&gt;
    .setAttribute(&amp;quot;target&amp;quot;, &amp;quot;_blank&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  handleDropdown(searchMonster, monsterList);&lt;br /&gt;
  addMonsterNames(monsterList, characters.monsterListTemplate);&lt;br /&gt;
  filterNames(searchMonster, monsterList);&lt;br /&gt;
&lt;br /&gt;
  characters.savedMonsters.slice().forEach(function (monsterVnum) {&lt;br /&gt;
    var inputMonster = monsterList.querySelector(&lt;br /&gt;
      &amp;quot;input[name='&amp;quot; + monsterVnum + &amp;quot;']&amp;quot;&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    if (inputMonster) {&lt;br /&gt;
      handleNewMonster(&lt;br /&gt;
        characters,&lt;br /&gt;
        monsterTemplate,&lt;br /&gt;
        monstersContainer,&lt;br /&gt;
        battle,&lt;br /&gt;
        monsterVnum,&lt;br /&gt;
        monsterList&lt;br /&gt;
      );&lt;br /&gt;
      inputMonster.checked = true;&lt;br /&gt;
    } else {&lt;br /&gt;
      deleteMonster(characters, monsterVnum, null, battle);&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  monsterListForm.addEventListener(&amp;quot;submit&amp;quot;, function (event) {&lt;br /&gt;
    event.preventDefault();&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  monsterListForm.addEventListener(&amp;quot;change&amp;quot;, function (event) {&lt;br /&gt;
    var target = event.target;&lt;br /&gt;
    var monsterVnum = target.name;&lt;br /&gt;
&lt;br /&gt;
    if (monsterVnum === &amp;quot;search-monster&amp;quot;) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (target.checked) {&lt;br /&gt;
      handleNewMonster(&lt;br /&gt;
        characters,&lt;br /&gt;
        monsterTemplate,&lt;br /&gt;
        monstersContainer,&lt;br /&gt;
        battle,&lt;br /&gt;
        monsterVnum,&lt;br /&gt;
        monsterList&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      characters.savedMonsters.push(monsterVnum);&lt;br /&gt;
      updateSavedMonsters(characters.savedMonsters);&lt;br /&gt;
      addBattleChoice(battle, monsterVnum, true);&lt;br /&gt;
    } else {&lt;br /&gt;
      var currentMonsterTemplate = monstersContainer.querySelector(&lt;br /&gt;
        &amp;quot;[data-name='&amp;quot; + monsterVnum + &amp;quot;']&amp;quot;&lt;br /&gt;
      );&lt;br /&gt;
      deleteMonster(characters, monsterVnum, currentMonsterTemplate, battle);&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  addEventListener(&amp;quot;storage&amp;quot;, function (event) {&lt;br /&gt;
    if (event.key === &amp;quot;newMonsterCalculator&amp;quot;) {&lt;br /&gt;
      var monsterVnum = Number(event.newValue);&lt;br /&gt;
&lt;br /&gt;
      if (!monsterVnum) {&lt;br /&gt;
        return;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      var inputMonster = monsterList.querySelector(&lt;br /&gt;
        &amp;quot;input[name='&amp;quot; + Math.abs(monsterVnum) + &amp;quot;']&amp;quot;&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      if (inputMonster) {&lt;br /&gt;
        if (&lt;br /&gt;
          (monsterVnum &amp;gt; 0 &amp;amp;&amp;amp; !inputMonster.checked) ||&lt;br /&gt;
          (monsterVnum &amp;lt; 0 &amp;amp;&amp;amp; inputMonster.checked)&lt;br /&gt;
        ) {&lt;br /&gt;
          inputMonster.click();&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function removeBattleChoice(battle, name) {&lt;br /&gt;
  var battleSelects = [battle.attackerSelection, battle.victimSelection];&lt;br /&gt;
&lt;br /&gt;
  battleSelects.forEach(function (battleSelect) {&lt;br /&gt;
    for (&lt;br /&gt;
      var optionIndex = 0;&lt;br /&gt;
      optionIndex &amp;lt; battleSelect.options.length;&lt;br /&gt;
      optionIndex++&lt;br /&gt;
    ) {&lt;br /&gt;
      if (battleSelect.options[optionIndex].value === name) {&lt;br /&gt;
        battleSelect.remove(optionIndex);&lt;br /&gt;
        break;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addBattleChoice(battle, name, isMonster = false) {&lt;br /&gt;
  function createOption(text, vnum) {&lt;br /&gt;
    var option = document.createElement(&amp;quot;option&amp;quot;);&lt;br /&gt;
    option.textContent = text;&lt;br /&gt;
    option.value = vnum;&lt;br /&gt;
&lt;br /&gt;
    if (!isMonster) {&lt;br /&gt;
      option.classList.add(&amp;quot;notranslate&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return option;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var vnum = name;&lt;br /&gt;
&lt;br /&gt;
  if (isMonster) {&lt;br /&gt;
    name = getMonsterName(name);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (isMonster &amp;amp;&amp;amp; monsterData[vnum][1]) {&lt;br /&gt;
    // pass&lt;br /&gt;
  } else {&lt;br /&gt;
    battle.attackerSelection.appendChild(createOption(name, vnum));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  battle.victimSelection.appendChild(createOption(name, vnum));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateBattleChoice(characters, battle) {&lt;br /&gt;
  var keys = Object.keys(characters.savedCharacters);&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; keys.length; index++) {&lt;br /&gt;
    var pseudo = keys[index];&lt;br /&gt;
    addBattleChoice(battle, pseudo);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  characters.savedMonsters.forEach(function (monsterVnum) {&lt;br /&gt;
    addBattleChoice(battle, monsterVnum, true);&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isPC(character) {&lt;br /&gt;
  if (character.race === 0 || character.race === 1) {&lt;br /&gt;
    return false;&lt;br /&gt;
  }&lt;br /&gt;
  return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isBoss(character) {&lt;br /&gt;
  return character.race === 0 &amp;amp;&amp;amp; character.rank &amp;gt;= 5;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isStone(character) {&lt;br /&gt;
  return character.race === 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isMeleeAttacker(monster) {&lt;br /&gt;
  return monster.attack == 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isRangeAttacker(monster) {&lt;br /&gt;
  return monster.attack == 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isMagicAttacker(monster) {&lt;br /&gt;
  return monster.attack == 2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isMagicClass(character) {&lt;br /&gt;
  return character.race === &amp;quot;shaman&amp;quot; || character.class === &amp;quot;black_magic&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isDispell(character, skillId) {&lt;br /&gt;
  return character.class === &amp;quot;weaponary&amp;quot; &amp;amp;&amp;amp; skillId === 6;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isPolymorph(character) {&lt;br /&gt;
  return character.state === &amp;quot;polymorph&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isRiding(character) {&lt;br /&gt;
  return character.state === &amp;quot;horse&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isBow(weapon) {&lt;br /&gt;
  return weapon.type === 2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcAttackFactor(attacker, victim) {&lt;br /&gt;
  function calcCoeffK(dex, level) {&lt;br /&gt;
    return Math.min(90, Math.floor((2 * dex + level) / 3));&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var K1 = calcCoeffK(attacker.polymorphDex, attacker.level);&lt;br /&gt;
  var K2 = calcCoeffK(victim.polymorphDex, attacker.level);&lt;br /&gt;
&lt;br /&gt;
  var AR = (K1 + 210) / 300;&lt;br /&gt;
  var ER = (((2 * K2 + 5) / (K2 + 95)) * 3) / 10;&lt;br /&gt;
&lt;br /&gt;
  return truncateNumber(AR - ER, 8);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcMainAttackValue(attacker) {&lt;br /&gt;
  var leadership = 0;&lt;br /&gt;
  var rawWeaponAttackValue = 0;&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker)) {&lt;br /&gt;
    var weaponUpgrades = attacker.weapon.upgrades;&lt;br /&gt;
    var maxUpgrade = weaponUpgrades.length - 1;&lt;br /&gt;
&lt;br /&gt;
    if (attacker.hasOwnProperty(&amp;quot;weaponUpgrade&amp;quot;)) {&lt;br /&gt;
      rawWeaponAttackValue =&lt;br /&gt;
        weaponUpgrades[Math.min(attacker.weaponUpgrade, maxUpgrade)];&lt;br /&gt;
&lt;br /&gt;
      // rare bug when weaponUpgrade is deleted&lt;br /&gt;
    } else {&lt;br /&gt;
      console.log(&amp;quot;Warming: weaponUpgrade is missing.&amp;quot;);&lt;br /&gt;
      rawWeaponAttackValue = weaponUpgrades[maxUpgrade];&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    leadership = attacker.leadership;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return 2 * (attacker.level + rawWeaponAttackValue) + leadership;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcStatAttackValue(character) {&lt;br /&gt;
  switch (character.race) {&lt;br /&gt;
    case &amp;quot;warrior&amp;quot;:&lt;br /&gt;
    case &amp;quot;sura&amp;quot;:&lt;br /&gt;
      return 2 * character.str;&lt;br /&gt;
    case &amp;quot;ninja&amp;quot;:&lt;br /&gt;
      return Math.floor((1 / 4) * (character.str + 7 * character.dex));&lt;br /&gt;
    case &amp;quot;shaman&amp;quot;:&lt;br /&gt;
      return Math.floor((1 / 3) * (5 * character.int + character.dex));&lt;br /&gt;
    case &amp;quot;lycan&amp;quot;:&lt;br /&gt;
      return character.vit + 2 * character.dex;&lt;br /&gt;
    default:&lt;br /&gt;
      return 2 * character.str;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcSecondaryAttackValue(attacker) {&lt;br /&gt;
  var attackValueOther = 0;&lt;br /&gt;
&lt;br /&gt;
  var minAttackValue = 0;&lt;br /&gt;
  var maxAttackValue = 0;&lt;br /&gt;
&lt;br /&gt;
  var minAttackValueSlash = 0;&lt;br /&gt;
  var maxAttackValueSlash = 0;&lt;br /&gt;
&lt;br /&gt;
  var attackerWeapon = attacker.weapon;&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker)) {&lt;br /&gt;
    if (attackerWeapon.isSerpent) {&lt;br /&gt;
      var rawAttackValue = attackerWeapon.upgrades[attacker.weaponUpgrade];&lt;br /&gt;
&lt;br /&gt;
      minAttackValue = attacker.minAttackValueRandom - rawAttackValue;&lt;br /&gt;
      maxAttackValue = attacker.maxAttackValueRandom - rawAttackValue;&lt;br /&gt;
&lt;br /&gt;
      minAttackValue = Math.max(0, minAttackValue);&lt;br /&gt;
      maxAttackValue = Math.max(minAttackValue, maxAttackValue);&lt;br /&gt;
    } else {&lt;br /&gt;
      minAttackValue = attackerWeapon.minAttackValue;&lt;br /&gt;
      maxAttackValue = attackerWeapon.maxAttackValue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    minAttackValueSlash = Math.min(&lt;br /&gt;
      attacker.minAttackValueSlash,&lt;br /&gt;
      attacker.maxAttackValueSlash&lt;br /&gt;
    );&lt;br /&gt;
    maxAttackValueSlash = Math.max(&lt;br /&gt;
      attacker.minAttackValueSlash,&lt;br /&gt;
      attacker.maxAttackValueSlash&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    attackValueOther += attacker.attackValue;&lt;br /&gt;
&lt;br /&gt;
    if (isBow(attackerWeapon) &amp;amp;&amp;amp; !isPolymorph(attacker)) {&lt;br /&gt;
      attackValueOther += 25;&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    minAttackValue = attacker.minAttackValue;&lt;br /&gt;
    maxAttackValue = attacker.maxAttackValue;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  minAttackValue += attacker.minAttackValuePolymorph;&lt;br /&gt;
  maxAttackValue += attacker.maxAttackValuePolymorph;&lt;br /&gt;
&lt;br /&gt;
  attackValueOther += attacker.statAttackValue;&lt;br /&gt;
  attackValueOther += attacker.horseAttackValue;&lt;br /&gt;
&lt;br /&gt;
  var weaponInterval = maxAttackValue - minAttackValue + 1;&lt;br /&gt;
  var slashInterval = maxAttackValueSlash - minAttackValueSlash + 1;&lt;br /&gt;
&lt;br /&gt;
  var totalCardinal = weaponInterval * slashInterval * 1_000_000;&lt;br /&gt;
  var minInterval = Math.min(weaponInterval, slashInterval);&lt;br /&gt;
&lt;br /&gt;
  minAttackValue += minAttackValueSlash;&lt;br /&gt;
  maxAttackValue += maxAttackValueSlash;&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    minAttackValue: minAttackValue,&lt;br /&gt;
    maxAttackValue: maxAttackValue,&lt;br /&gt;
    attackValueOther: attackValueOther,&lt;br /&gt;
    totalCardinal: totalCardinal,&lt;br /&gt;
    weights: calcWeights(minAttackValue, maxAttackValue, minInterval),&lt;br /&gt;
    possibleDamagesCount: maxAttackValue - minAttackValue + 1,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcMagicAttackValue(attacker) {&lt;br /&gt;
  var minMagicAttackValue = 0;&lt;br /&gt;
  var maxMagicAttackValue = 0;&lt;br /&gt;
&lt;br /&gt;
  var minMagicAttackValueSlash = 0;&lt;br /&gt;
  var maxMagicAttackValueSlash = 0;&lt;br /&gt;
&lt;br /&gt;
  var attackerWeapon = attacker.weapon;&lt;br /&gt;
&lt;br /&gt;
  if (attackerWeapon.isSerpent) {&lt;br /&gt;
    minMagicAttackValue = attacker.minMagicAttackValueRandom;&lt;br /&gt;
    maxMagicAttackValue = attacker.maxMagicAttackValueRandom;&lt;br /&gt;
&lt;br /&gt;
    maxMagicAttackValue = Math.max(minMagicAttackValue, maxMagicAttackValue);&lt;br /&gt;
  } else {&lt;br /&gt;
    var rawWeaponAttackValue = attackerWeapon.upgrades[attacker.weaponUpgrade];&lt;br /&gt;
&lt;br /&gt;
    if (!rawWeaponAttackValue) {&lt;br /&gt;
      rawWeaponAttackValue = 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    minMagicAttackValue =&lt;br /&gt;
      attackerWeapon.minMagicAttackValue + rawWeaponAttackValue;&lt;br /&gt;
    maxMagicAttackValue =&lt;br /&gt;
      attackerWeapon.maxMagicAttackValue + rawWeaponAttackValue;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  minMagicAttackValueSlash = Math.min(&lt;br /&gt;
    attacker.minMagicAttackValueSlash,&lt;br /&gt;
    attacker.maxMagicAttackValueSlash&lt;br /&gt;
  );&lt;br /&gt;
  maxMagicAttackValueSlash = Math.max(&lt;br /&gt;
    attacker.minMagicAttackValueSlash,&lt;br /&gt;
    attacker.maxMagicAttackValueSlash&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  var weaponInterval = maxMagicAttackValue - minMagicAttackValue + 1;&lt;br /&gt;
  var slashInterval = maxMagicAttackValueSlash - minMagicAttackValueSlash + 1;&lt;br /&gt;
&lt;br /&gt;
  var totalCardinal = weaponInterval * slashInterval * 1_000_000;&lt;br /&gt;
  var minInterval = Math.min(weaponInterval, slashInterval);&lt;br /&gt;
&lt;br /&gt;
  minMagicAttackValue += minMagicAttackValueSlash;&lt;br /&gt;
  maxMagicAttackValue += maxMagicAttackValueSlash;&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    minMagicAttackValue: minMagicAttackValue,&lt;br /&gt;
    maxMagicAttackValue: maxMagicAttackValue,&lt;br /&gt;
    magicAttackValueAugmentation: getMagicAttackValueAugmentation(&lt;br /&gt;
      minMagicAttackValue,&lt;br /&gt;
      maxMagicAttackValue,&lt;br /&gt;
      attacker.magicAttackValue&lt;br /&gt;
    ),&lt;br /&gt;
    totalCardinal: totalCardinal,&lt;br /&gt;
    weights: calcWeights(minMagicAttackValue, maxMagicAttackValue, minInterval),&lt;br /&gt;
    possibleDamagesCount: maxMagicAttackValue - minMagicAttackValue + 1,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getPolymorphPower(polymorphPoint, polymorphPowerTable) {&lt;br /&gt;
  return polymorphPowerTable[polymorphPoint];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSkillPower(skillPoint, skillPowerTable) {&lt;br /&gt;
  return skillPowerTable[skillPoint];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getMarriageBonusValue(character, marriageTable, itemName) {&lt;br /&gt;
  var index;&lt;br /&gt;
  var lovePoint = character.lovePoint;&lt;br /&gt;
&lt;br /&gt;
  if (lovePoint &amp;lt; 65) {&lt;br /&gt;
    index = 0;&lt;br /&gt;
  } else if (lovePoint &amp;lt; 80) {&lt;br /&gt;
    index = 1;&lt;br /&gt;
  } else if (lovePoint &amp;lt; 100) {&lt;br /&gt;
    index = 2;&lt;br /&gt;
  } else {&lt;br /&gt;
    index = 3;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return marriageTable[itemName][index];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcDamageWithPrimaryBonuses(damages, bonusValues) {&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.attackValueCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  damages += bonusValues.attackValueMarriage;&lt;br /&gt;
&lt;br /&gt;
  damages = Math.floor(&lt;br /&gt;
    (damages * bonusValues.monsterResistanceMarriageCoeff) / 100&lt;br /&gt;
  );&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.monsterResistanceCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  damages += Math.floor((damages * bonusValues.typeBonusCoeff) / 100);&lt;br /&gt;
  damages +=&lt;br /&gt;
    Math.floor((damages * bonusValues.raceBonusCoeff) / 100) -&lt;br /&gt;
    Math.floor((damages * bonusValues.raceResistanceCoeff) / 100);&lt;br /&gt;
  damages += Math.floor((damages * bonusValues.stoneBonusCoeff) / 100);&lt;br /&gt;
  damages += Math.floor((damages * bonusValues.monsterBonusCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  var elementBonusCoeff = bonusValues.elementBonusCoeff;&lt;br /&gt;
&lt;br /&gt;
  damages +=&lt;br /&gt;
    Math.trunc((damages * elementBonusCoeff[0]) / 10000) +&lt;br /&gt;
    Math.trunc((damages * elementBonusCoeff[1]) / 10000) +&lt;br /&gt;
    Math.trunc((damages * elementBonusCoeff[2]) / 10000) +&lt;br /&gt;
    Math.trunc((damages * elementBonusCoeff[3]) / 10000) +&lt;br /&gt;
    Math.trunc((damages * elementBonusCoeff[4]) / 10000) +&lt;br /&gt;
    Math.trunc((damages * elementBonusCoeff[5]) / 10000);&lt;br /&gt;
&lt;br /&gt;
  damages = Math.floor(damages * bonusValues.damageMultiplier);&lt;br /&gt;
&lt;br /&gt;
  return damages;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcDamageWithSecondaryBonuses(&lt;br /&gt;
  damages,&lt;br /&gt;
  bonusValues,&lt;br /&gt;
  damagesType,&lt;br /&gt;
  minPiercingDamages,&lt;br /&gt;
  damagesWithPrimaryBonuses&lt;br /&gt;
) {&lt;br /&gt;
  damages = Math.floor(damages * bonusValues.magicResistanceCoeff);&lt;br /&gt;
  damages = Math.trunc((damages * bonusValues.weaponDefenseCoeff) / 100);&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.tigerStrengthCoeff) / 100);&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.blessingBonusCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  if (damagesType.criticalHit) {&lt;br /&gt;
    damages *= 2;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (damagesType.piercingHit) {&lt;br /&gt;
    damages += bonusValues.defenseBoost + Math.min(0, minPiercingDamages);&lt;br /&gt;
    damages += Math.floor(&lt;br /&gt;
      (damagesWithPrimaryBonuses * bonusValues.extraPiercingHitCoeff) / 1000&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.averageDamageCoeff) / 100);&lt;br /&gt;
  damages = Math.floor(&lt;br /&gt;
    (damages * bonusValues.averageDamageResistanceCoeff) / 100&lt;br /&gt;
  );&lt;br /&gt;
  damages = Math.floor(&lt;br /&gt;
    (damages * bonusValues.skillDamageResistanceCoeff) / 100&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.rankBonusCoeff) / 100);&lt;br /&gt;
  damages = Math.max(0, damages + bonusValues.defensePercent);&lt;br /&gt;
  damages += Math.min(&lt;br /&gt;
    300,&lt;br /&gt;
    Math.floor((damages * bonusValues.damageBonusCoeff) / 100)&lt;br /&gt;
  );&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.empireMalusCoeff) / 10);&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.sungMaStrBonusCoeff) / 10000);&lt;br /&gt;
  damages -= Math.floor(damages * bonusValues.sungmaStrMalusCoeff);&lt;br /&gt;
&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.whiteDragonElixirCoeff) / 100);&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.steelDragonElixirCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  return damages;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcSkillDamageWithSecondaryBonuses(&lt;br /&gt;
  damages,&lt;br /&gt;
  bonusValues,&lt;br /&gt;
  damagesType,&lt;br /&gt;
  minPiercingDamages&lt;br /&gt;
) {&lt;br /&gt;
  damages = Math.floor(damages * bonusValues.magicResistanceCoeff);&lt;br /&gt;
  damages = Math.trunc((damages * bonusValues.weaponDefenseCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  damages -= bonusValues.defense;&lt;br /&gt;
&lt;br /&gt;
  damages = floorMultiplication(damages, bonusValues.skillWardCoeff);&lt;br /&gt;
  damages = floorMultiplication(damages, bonusValues.skillBonusCoeff);&lt;br /&gt;
&lt;br /&gt;
  var tempDamages = Math.floor(&lt;br /&gt;
    (damages * bonusValues.skillBonusByBonusCoeff) / 100&lt;br /&gt;
  );&lt;br /&gt;
  &lt;br /&gt;
  damages = Math.floor(&lt;br /&gt;
    (tempDamages * bonusValues.magicAttackValueCoeff) / 100 + 0.5&lt;br /&gt;
  );&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.tigerStrengthCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  if (damagesType.criticalHit) {&lt;br /&gt;
    damages *= 2;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (damagesType.piercingHit) {&lt;br /&gt;
    damages += bonusValues.defenseBoost + Math.min(0, minPiercingDamages);&lt;br /&gt;
    damages += Math.floor(&lt;br /&gt;
      (tempDamages * bonusValues.extraPiercingHitCoeff) / 1000&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.skillDamageCoeff) / 100);&lt;br /&gt;
  damages = Math.floor(&lt;br /&gt;
    (damages * bonusValues.skillDamageResistanceCoeff) / 100&lt;br /&gt;
  );&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.rankBonusCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  damages = Math.max(0, damages + bonusValues.defensePercent);&lt;br /&gt;
  damages += Math.min(&lt;br /&gt;
    300,&lt;br /&gt;
    Math.floor((damages * bonusValues.damageBonusCoeff) / 100)&lt;br /&gt;
  );&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.empireMalusCoeff) / 10);&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.sungMaStrBonusCoeff) / 10000);&lt;br /&gt;
  damages -= Math.floor(damages * bonusValues.sungmaStrMalusCoeff);&lt;br /&gt;
&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.whiteDragonElixirCoeff) / 100);&lt;br /&gt;
  damages = Math.floor((damages * bonusValues.steelDragonElixirCoeff) / 100);&lt;br /&gt;
&lt;br /&gt;
  return damages;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function computePolymorphPoint(attacker, victim, polymorphPowerTable) {&lt;br /&gt;
  attacker.statAttackValue = 0;&lt;br /&gt;
&lt;br /&gt;
  attacker.polymorphDex = attacker.dex;&lt;br /&gt;
  victim.polymorphDex = victim.dex;&lt;br /&gt;
&lt;br /&gt;
  attacker.minAttackValuePolymorph = 0;&lt;br /&gt;
  attacker.maxAttackValuePolymorph = 0;&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker) &amp;amp;&amp;amp; isPolymorph(attacker)) {&lt;br /&gt;
    var polymorphPowerPct =&lt;br /&gt;
      getPolymorphPower(attacker.polymorphPoint, polymorphPowerTable) / 100;&lt;br /&gt;
    var polymorphMonster = createMonster(attacker.polymorphMonster);&lt;br /&gt;
&lt;br /&gt;
    var polymorphStr = floorMultiplication(&lt;br /&gt;
      polymorphPowerPct,&lt;br /&gt;
      polymorphMonster.str&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    attacker.polymorphDex += floorMultiplication(&lt;br /&gt;
      polymorphPowerPct,&lt;br /&gt;
      polymorphMonster.dex&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    attacker.minAttackValuePolymorph = floorMultiplication(&lt;br /&gt;
      polymorphPowerPct,&lt;br /&gt;
      polymorphMonster.minAttackValue&lt;br /&gt;
    );&lt;br /&gt;
    attacker.maxAttackValuePolymorph = floorMultiplication(&lt;br /&gt;
      polymorphPowerPct,&lt;br /&gt;
      polymorphMonster.maxAttackValue&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    if (!attacker.weapon) {&lt;br /&gt;
      attacker.maxAttackValuePolymorph += 1;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    attacker.attackValue = 0;&lt;br /&gt;
&lt;br /&gt;
    if (isMagicClass(attacker)) {&lt;br /&gt;
      attacker.statAttackValue = 2 * (polymorphStr + attacker.int);&lt;br /&gt;
    } else {&lt;br /&gt;
      attacker.statAttackValue = 2 * (polymorphStr + attacker.str);&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    attacker.statAttackValue = calcStatAttackValue(attacker);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function computeHorse(attacker) {&lt;br /&gt;
  attacker.horseAttackValue = 0;&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker) &amp;amp;&amp;amp; isRiding(attacker)) {&lt;br /&gt;
    var horseConstant = 30;&lt;br /&gt;
&lt;br /&gt;
    if (attacker.class === &amp;quot;weaponary&amp;quot;) {&lt;br /&gt;
      horseConstant = 60;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    attacker.horseAttackValue = floorMultiplication(&lt;br /&gt;
      2 * attacker.level + attacker.statAttackValue,&lt;br /&gt;
      attacker.horsePoint / horseConstant&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getRankBonus(attacker) {&lt;br /&gt;
  if (attacker.lowRank !== &amp;quot;on&amp;quot;) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  switch (attacker.playerRank) {&lt;br /&gt;
    case &amp;quot;aggressive&amp;quot;:&lt;br /&gt;
      return 1;&lt;br /&gt;
    case &amp;quot;fraudulent&amp;quot;:&lt;br /&gt;
      return 2;&lt;br /&gt;
    case &amp;quot;malicious&amp;quot;:&lt;br /&gt;
      return 3;&lt;br /&gt;
    case &amp;quot;cruel&amp;quot;:&lt;br /&gt;
      return 5;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcElementCoeffPvP(elementBonus, mapping, attacker, victim) {&lt;br /&gt;
  var minElementMalus = 0;&lt;br /&gt;
  var maxDifference = 0;&lt;br /&gt;
  var savedElementDifferences = [];&lt;br /&gt;
  var elementBonusIndex = 0;&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; elementBonus.length; index++) {&lt;br /&gt;
    if (!attacker[mapping.elementBonus[index]]) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var elementDifference =&lt;br /&gt;
      attacker[mapping.elementBonus[index]] -&lt;br /&gt;
      victim[mapping.elementResistance[index]];&lt;br /&gt;
&lt;br /&gt;
    if (elementDifference &amp;gt;= 0) {&lt;br /&gt;
      elementBonus[elementBonusIndex] = 10 * elementDifference;&lt;br /&gt;
      minElementMalus -= elementDifference;&lt;br /&gt;
      maxDifference = Math.max(maxDifference, elementDifference);&lt;br /&gt;
      elementBonusIndex++;&lt;br /&gt;
    } else {&lt;br /&gt;
      savedElementDifferences.push(elementDifference);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (!savedElementDifferences.length) {&lt;br /&gt;
    return;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  minElementMalus += maxDifference;&lt;br /&gt;
  savedElementDifferences.sort(compareNumbers);&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; savedElementDifferences.length; index++) {&lt;br /&gt;
    var elementDifference = savedElementDifferences[index];&lt;br /&gt;
&lt;br /&gt;
    elementBonus[elementBonusIndex + index] =&lt;br /&gt;
      10 * Math.max(minElementMalus, elementDifference);&lt;br /&gt;
&lt;br /&gt;
    minElementMalus = Math.min(&lt;br /&gt;
      0,&lt;br /&gt;
      Math.max(minElementMalus, minElementMalus - elementDifference)&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function skillChanceReduction(value) {&lt;br /&gt;
  if (value &amp;lt;= 9) {&lt;br /&gt;
    return Math.floor(value / 2);&lt;br /&gt;
  }&lt;br /&gt;
  return 5 + Math.floor((value - 10) / 4);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function magicResistanceToCoeff(magicResistance) {&lt;br /&gt;
  if (magicResistance) {&lt;br /&gt;
    return 2000 / (6 * magicResistance + 1000) - 1;&lt;br /&gt;
  }&lt;br /&gt;
  return 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createBattleValues(attacker, victim, battle, skillType) {&lt;br /&gt;
  var { mapping, constants } = battle;&lt;br /&gt;
  var calcAttackValues;&lt;br /&gt;
&lt;br /&gt;
  var missPercentage = 0;&lt;br /&gt;
  var attackValueMeleeMagic = 0;&lt;br /&gt;
  var attackValueMarriage = 0;&lt;br /&gt;
  var monsterResistanceMarriage = 0;&lt;br /&gt;
  var monsterResistance = 0;&lt;br /&gt;
  var typeBonus = 0;&lt;br /&gt;
  var raceBonus = 0;&lt;br /&gt;
  var raceResistance = 0;&lt;br /&gt;
  var stoneBonus = 0;&lt;br /&gt;
  var monsterBonus = 0;&lt;br /&gt;
  var elementBonus = [0, 0, 0, 0, 0, 0]; // fire, ice, lightning, earth, darkness, wind, order doesn't matter&lt;br /&gt;
  var defenseMarriage = 0;&lt;br /&gt;
  var damageMultiplier = 1;&lt;br /&gt;
  var useDamages = 1;&lt;br /&gt;
  var defense = victim.defense;&lt;br /&gt;
  var defenseBoost = defense;&lt;br /&gt;
  var magicResistance = 0;&lt;br /&gt;
  var weaponDefense = 0;&lt;br /&gt;
  var tigerStrength = 0;&lt;br /&gt;
  var blessingBonus = 0;&lt;br /&gt;
  var magicAttackValueMeleeMagic = 0;&lt;br /&gt;
  var criticalHitPercentage = attacker.criticalHit;&lt;br /&gt;
  var piercingHitPercentage = attacker.piercingHit;&lt;br /&gt;
  var extraPiercingHitPercentage = Math.max(0, piercingHitPercentage - 100);&lt;br /&gt;
  var averageDamage = 0;&lt;br /&gt;
  var averageDamageResistance = 0;&lt;br /&gt;
  var skillDamage = 0;&lt;br /&gt;
  var skillDamageResistance = 0;&lt;br /&gt;
  var rankBonus = 0;&lt;br /&gt;
  var defensePercent = 0;&lt;br /&gt;
  var damageBonus = 0;&lt;br /&gt;
  var empireMalus = 0;&lt;br /&gt;
  var sungMaStrBonus = 0;&lt;br /&gt;
  var sungmaStrMalus = 0;&lt;br /&gt;
  var whiteDragonElixir = 0;&lt;br /&gt;
  var steelDragonElixir = 0;&lt;br /&gt;
&lt;br /&gt;
  computePolymorphPoint(attacker, victim, constants.polymorphPowerTable);&lt;br /&gt;
  computeHorse(attacker);&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker)) {&lt;br /&gt;
    if (weaponData.hasOwnProperty(attacker.weapon)) {&lt;br /&gt;
      attacker.weapon = createWeapon(attacker.weapon);&lt;br /&gt;
    } else {&lt;br /&gt;
      attacker.weapon = createWeapon(0);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    attackValueMeleeMagic =&lt;br /&gt;
      attacker.attackValuePercent + Math.min(100, attacker.attackMeleeMagic);&lt;br /&gt;
&lt;br /&gt;
    var weaponType = attacker.weapon.type;&lt;br /&gt;
&lt;br /&gt;
    if (skillType &amp;amp;&amp;amp; attacker.class === &amp;quot;archery&amp;quot;) {&lt;br /&gt;
      if (weaponType !== 2) {&lt;br /&gt;
        useDamages = 0;&lt;br /&gt;
        weaponType = 2;&lt;br /&gt;
      }&lt;br /&gt;
      defense = 0;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var weaponDefenseName = mapping.defenseWeapon[weaponType];&lt;br /&gt;
    var weaponDefenseBreakName = mapping.breakWeapon[weaponType];&lt;br /&gt;
&lt;br /&gt;
    if (victim.hasOwnProperty(weaponDefenseName)) {&lt;br /&gt;
      weaponDefense = victim[weaponDefenseName];&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isChecked(attacker.whiteDragonElixir)) {&lt;br /&gt;
      whiteDragonElixir = 10;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isPC(victim)) {&lt;br /&gt;
      if (!skillType) {&lt;br /&gt;
        if (weaponType === 2 &amp;amp;&amp;amp; !isPolymorph(attacker)) {&lt;br /&gt;
          missPercentage = victim.arrowBlock;&lt;br /&gt;
        } else {&lt;br /&gt;
          missPercentage = victim.meleeBlock;&lt;br /&gt;
        }&lt;br /&gt;
        missPercentage +=&lt;br /&gt;
          victim.meleeArrowBlock -&lt;br /&gt;
          (missPercentage * victim.meleeArrowBlock) / 100;&lt;br /&gt;
&lt;br /&gt;
        blessingBonus = calcBlessingBonus(constants.skillPowerTable, victim);&lt;br /&gt;
        averageDamageResistance = victim.averageDamageResistance;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      typeBonus = Math.max(1, attacker.humanBonus - victim.humanResistance);&lt;br /&gt;
      raceBonus = attacker[mapping.raceBonus[victim.race]];&lt;br /&gt;
      raceResistance = victim[mapping.raceResistance[attacker.race]];&lt;br /&gt;
&lt;br /&gt;
      calcElementCoeffPvP(elementBonus, mapping, attacker, victim);&lt;br /&gt;
&lt;br /&gt;
      if (weaponType !== 2 &amp;amp;&amp;amp; attacker.hasOwnProperty(weaponDefenseBreakName)) {&lt;br /&gt;
        weaponDefense -= attacker[weaponDefenseBreakName];&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      criticalHitPercentage = 0;&lt;br /&gt;
    } else {&lt;br /&gt;
      if (isChecked(attacker.isMarried)) {&lt;br /&gt;
        if (isChecked(attacker.loveNecklace)) {&lt;br /&gt;
          attackValueMarriage = getMarriageBonusValue(&lt;br /&gt;
            attacker,&lt;br /&gt;
            constants.marriageTable,&lt;br /&gt;
            &amp;quot;loveNecklace&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isChecked(attacker.loveEarrings)) {&lt;br /&gt;
          criticalHitPercentage += getMarriageBonusValue(&lt;br /&gt;
            attacker,&lt;br /&gt;
            constants.marriageTable,&lt;br /&gt;
            &amp;quot;loveEarrings&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isChecked(attacker.harmonyEarrings)) {&lt;br /&gt;
          piercingHitPercentage += getMarriageBonusValue(&lt;br /&gt;
            attacker,&lt;br /&gt;
            constants.marriageTable,&lt;br /&gt;
            &amp;quot;harmonyEarrings&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (isChecked(attacker.tigerStrength)) {&lt;br /&gt;
        tigerStrength = 40;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      for (var index = 0; index &amp;lt; elementBonus.length; index++) {&lt;br /&gt;
        var elementBonusName = mapping.elementBonus[index];&lt;br /&gt;
        var elementResistanceName = mapping.elementResistance[index];&lt;br /&gt;
&lt;br /&gt;
        if (attacker[elementBonusName] &amp;amp;&amp;amp; victim[elementBonusName]) {&lt;br /&gt;
          elementBonus[index] =&lt;br /&gt;
            50 * (attacker[elementBonusName] - victim[elementResistanceName]);&lt;br /&gt;
        } else {&lt;br /&gt;
          elementBonus[index] = 5 * attacker[elementBonusName];&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      var victimType = victim.type;&lt;br /&gt;
&lt;br /&gt;
      if (victimType !== -1) {&lt;br /&gt;
        typeBonus = attacker[mapping.typeFlag[victimType]];&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      monsterBonus = attacker.monsterBonus;&lt;br /&gt;
&lt;br /&gt;
      if (isStone(victim)) {&lt;br /&gt;
        stoneBonus = attacker.stoneBonus;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (isBoss(victim)) {&lt;br /&gt;
        if (skillType) {&lt;br /&gt;
          skillDamage += attacker.skillBossDamage;&lt;br /&gt;
        } else {&lt;br /&gt;
          averageDamage += attacker.bossDamage;&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (isChecked(attacker.onYohara)) {&lt;br /&gt;
        var sungmaStrDifference = attacker.sungmaStr - attacker.sungmaStrMalus;&lt;br /&gt;
&lt;br /&gt;
        if (sungmaStrDifference &amp;gt;= 0) {&lt;br /&gt;
          sungMaStrBonus = sungmaStrDifference;&lt;br /&gt;
        } else {&lt;br /&gt;
          sungmaStrMalus = 0.5;&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (skillType) {&lt;br /&gt;
      skillDamage += attacker.skillDamage;&lt;br /&gt;
    } else {&lt;br /&gt;
      averageDamage += attacker.averageDamage;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    rankBonus = getRankBonus(attacker);&lt;br /&gt;
    damageBonus = attacker.damageBonus;&lt;br /&gt;
&lt;br /&gt;
    if (isChecked(attacker.empireMalus)) {&lt;br /&gt;
      empireMalus = 1;&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    if (isPC(victim)) {&lt;br /&gt;
      if (isChecked(victim.isMarried)) {&lt;br /&gt;
        if (isChecked(victim.harmonyBracelet)) {&lt;br /&gt;
          monsterResistanceMarriage = getMarriageBonusValue(&lt;br /&gt;
            victim,&lt;br /&gt;
            constants.marriageTable,&lt;br /&gt;
            &amp;quot;harmonyBracelet&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (isChecked(victim.harmonyNecklace) &amp;amp;&amp;amp; !skillType) {&lt;br /&gt;
          defenseMarriage = getMarriageBonusValue(&lt;br /&gt;
            victim,&lt;br /&gt;
            constants.marriageTable,&lt;br /&gt;
            &amp;quot;harmonyNecklace&amp;quot;&lt;br /&gt;
          );&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      monsterResistance = victim.monsterResistance;&lt;br /&gt;
&lt;br /&gt;
      for (var index = 0; index &amp;lt; elementBonus.length; index++) {&lt;br /&gt;
        var elementBonusName = mapping.elementBonus[index];&lt;br /&gt;
        var elementResistanceName = mapping.elementResistance[index];&lt;br /&gt;
&lt;br /&gt;
        if (attacker[elementBonusName]) {&lt;br /&gt;
          elementBonus[index] =&lt;br /&gt;
            80 * (attacker[elementBonusName] - victim[elementResistanceName]);&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (!skillType) {&lt;br /&gt;
        if (isMeleeAttacker(attacker)) {&lt;br /&gt;
          missPercentage = victim.meleeBlock;&lt;br /&gt;
          averageDamageResistance = victim.averageDamageResistance;&lt;br /&gt;
          blessingBonus = calcBlessingBonus(constants.skillPowerTable, victim);&lt;br /&gt;
        } else if (isRangeAttacker(attacker)) {&lt;br /&gt;
          missPercentage = victim.arrowBlock;&lt;br /&gt;
          weaponDefense = victim.arrowDefense;&lt;br /&gt;
          averageDamageResistance = victim.averageDamageResistance;&lt;br /&gt;
          blessingBonus = calcBlessingBonus(constants.skillPowerTable, victim);&lt;br /&gt;
        } else if (isMagicAttacker(attacker)) {&lt;br /&gt;
          missPercentage = victim.arrowBlock;&lt;br /&gt;
          skillDamageResistance = victim.skillDamageResistance;&lt;br /&gt;
          magicResistance = victim.magicResistance;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        missPercentage +=&lt;br /&gt;
          victim.meleeArrowBlock -&lt;br /&gt;
          (missPercentage * victim.meleeArrowBlock) / 100;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    typeBonus = 1;&lt;br /&gt;
    damageMultiplier = attacker.damageMultiplier;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillType) {&lt;br /&gt;
    criticalHitPercentage = skillChanceReduction(criticalHitPercentage);&lt;br /&gt;
    piercingHitPercentage = skillChanceReduction(piercingHitPercentage);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (isPC(victim)) {&lt;br /&gt;
    if (!skillType &amp;amp;&amp;amp; isChecked(victim.biologist70)) {&lt;br /&gt;
      defenseBoost = Math.floor((defenseBoost * 110) / 100);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    criticalHitPercentage = Math.max(&lt;br /&gt;
      0,&lt;br /&gt;
      criticalHitPercentage - victim.criticalHitResistance&lt;br /&gt;
    );&lt;br /&gt;
    piercingHitPercentage = Math.max(&lt;br /&gt;
      0,&lt;br /&gt;
      piercingHitPercentage - victim.piercingHitResistance&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    if (skillType) {&lt;br /&gt;
      skillDamageResistance = victim.skillDamageResistance;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isMagicClass(victim)) {&lt;br /&gt;
      defensePercent = (-2 * victim.magicDefense * victim.defensePercent) / 100;&lt;br /&gt;
    } else {&lt;br /&gt;
      defensePercent = (-2 * defenseBoost * victim.defensePercent) / 100;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isChecked(victim.steelDragonElixir)) {&lt;br /&gt;
      steelDragonElixir = 10;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillType === &amp;quot;magic&amp;quot;) {&lt;br /&gt;
    attackValueMeleeMagic = 0;&lt;br /&gt;
    magicAttackValueMeleeMagic =&lt;br /&gt;
      attacker.attackMagic + Math.min(100, attacker.attackMeleeMagic);&lt;br /&gt;
    attackValueMarriage = 0;&lt;br /&gt;
    defense = 0;&lt;br /&gt;
    if (!isDispell(attacker, 6)) {&lt;br /&gt;
      magicResistance = victim.magicResistance;&lt;br /&gt;
    }&lt;br /&gt;
    weaponDefense = 0;&lt;br /&gt;
    calcAttackValues = calcMagicAttackValue;&lt;br /&gt;
  } else {&lt;br /&gt;
    calcAttackValues = calcSecondaryAttackValue;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  missPercentage = Math.min(100, missPercentage);&lt;br /&gt;
&lt;br /&gt;
  var bonusValues = {&lt;br /&gt;
    missPercentage: missPercentage,&lt;br /&gt;
    weaponBonusCoeff: 1,&lt;br /&gt;
    attackValueCoeff: 100 + attackValueMeleeMagic,&lt;br /&gt;
    attackValueMarriage: attackValueMarriage,&lt;br /&gt;
    monsterResistanceMarriageCoeff: 100 - monsterResistanceMarriage,&lt;br /&gt;
    monsterResistanceCoeff: 100 - monsterResistance,&lt;br /&gt;
    typeBonusCoeff: typeBonus,&lt;br /&gt;
    raceBonusCoeff: raceBonus,&lt;br /&gt;
    raceResistanceCoeff: raceResistance,&lt;br /&gt;
    stoneBonusCoeff: stoneBonus,&lt;br /&gt;
    monsterBonusCoeff: monsterBonus,&lt;br /&gt;
    elementBonusCoeff: elementBonus,&lt;br /&gt;
    damageMultiplier: damageMultiplier,&lt;br /&gt;
    useDamages: useDamages,&lt;br /&gt;
    defense: defense,&lt;br /&gt;
    defenseBoost: defenseBoost,&lt;br /&gt;
    defenseMarriage: defenseMarriage,&lt;br /&gt;
    tigerStrengthCoeff: 100 + tigerStrength,&lt;br /&gt;
    magicResistanceCoeff: magicResistanceToCoeff(magicResistance),&lt;br /&gt;
    weaponDefenseCoeff: 100 - weaponDefense,&lt;br /&gt;
    blessingBonusCoeff: 100 - blessingBonus,&lt;br /&gt;
    magicAttackValueCoeff: 100 + magicAttackValueMeleeMagic,&lt;br /&gt;
    extraPiercingHitCoeff: 5 * extraPiercingHitPercentage,&lt;br /&gt;
    averageDamageCoeff: 100 + averageDamage,&lt;br /&gt;
    averageDamageResistanceCoeff: 100 - Math.min(99, averageDamageResistance),&lt;br /&gt;
    skillDamageCoeff: 100 + skillDamage,&lt;br /&gt;
    skillDamageResistanceCoeff: 100 - Math.min(99, skillDamageResistance),&lt;br /&gt;
    rankBonusCoeff: 100 + rankBonus,&lt;br /&gt;
    defensePercent: Math.floor(defensePercent),&lt;br /&gt;
    damageBonusCoeff: damageBonus,&lt;br /&gt;
    empireMalusCoeff: 10 - empireMalus,&lt;br /&gt;
    sungMaStrBonusCoeff: 10000 + sungMaStrBonus,&lt;br /&gt;
    sungmaStrMalusCoeff: sungmaStrMalus,&lt;br /&gt;
    whiteDragonElixirCoeff: 100 + whiteDragonElixir,&lt;br /&gt;
    steelDragonElixirCoeff: 100 - steelDragonElixir,&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  criticalHitPercentage = Math.min(criticalHitPercentage, 100);&lt;br /&gt;
  piercingHitPercentage = Math.min(piercingHitPercentage, 100);&lt;br /&gt;
&lt;br /&gt;
  var damagesTypeCombinaison = [&lt;br /&gt;
    {&lt;br /&gt;
      criticalHit: false,&lt;br /&gt;
      piercingHit: false,&lt;br /&gt;
      weight:&lt;br /&gt;
        (100 - criticalHitPercentage) *&lt;br /&gt;
        (100 - piercingHitPercentage) *&lt;br /&gt;
        (100 - missPercentage),&lt;br /&gt;
      name: &amp;quot;normalHit&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      criticalHit: true,&lt;br /&gt;
      piercingHit: false,&lt;br /&gt;
      weight:&lt;br /&gt;
        criticalHitPercentage *&lt;br /&gt;
        (100 - piercingHitPercentage) *&lt;br /&gt;
        (100 - missPercentage),&lt;br /&gt;
      name: &amp;quot;criticalHit&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      criticalHit: false,&lt;br /&gt;
      piercingHit: true,&lt;br /&gt;
      weight:&lt;br /&gt;
        (100 - criticalHitPercentage) *&lt;br /&gt;
        piercingHitPercentage *&lt;br /&gt;
        (100 - missPercentage),&lt;br /&gt;
      name: &amp;quot;piercingHit&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      criticalHit: true,&lt;br /&gt;
      piercingHit: true,&lt;br /&gt;
      weight:&lt;br /&gt;
        criticalHitPercentage * piercingHitPercentage * (100 - missPercentage),&lt;br /&gt;
      name: &amp;quot;criticalPiercingHit&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
  ];&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    attacker: attacker,&lt;br /&gt;
    victim: victim,&lt;br /&gt;
    attackFactor: calcAttackFactor(attacker, victim),&lt;br /&gt;
    mainAttackValue: calcMainAttackValue(attacker),&lt;br /&gt;
    attackValues: calcAttackValues(attacker),&lt;br /&gt;
    bonusValues: bonusValues,&lt;br /&gt;
    damagesTypeCombinaison: damagesTypeCombinaison,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function updateBattleValues(battleValues, skillFormula, skillInfo) {&lt;br /&gt;
  var weaponBonus = 0;&lt;br /&gt;
  var skillWard = 0;&lt;br /&gt;
  var skillBonus = 0;&lt;br /&gt;
  var skillBonusByBonus = 0;&lt;br /&gt;
  var { attacker: attacker, bonusValues: bonusValues } = battleValues;&lt;br /&gt;
  var {&lt;br /&gt;
    range: [minVariation, maxVariation],&lt;br /&gt;
  } = skillInfo;&lt;br /&gt;
  var variationLength = maxVariation - minVariation + 1;&lt;br /&gt;
&lt;br /&gt;
  if (skillInfo.hasOwnProperty(&amp;quot;weaponBonus&amp;quot;)) {&lt;br /&gt;
    var [weaponType, weaponBonusValue] = skillInfo.weaponBonus;&lt;br /&gt;
&lt;br /&gt;
    if (weaponType === attacker.weapon.type) {&lt;br /&gt;
      weaponBonus = weaponBonusValue;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillInfo.skillBonus) {&lt;br /&gt;
    skillBonus = skillInfo.skillBonus;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillInfo.skillWard) {&lt;br /&gt;
    skillWard = skillInfo.skillWard;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillInfo.skillBonusByBonus) {&lt;br /&gt;
    skillBonusByBonus = skillInfo.skillBonusByBonus;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (skillInfo.removeWeaponReduction) {&lt;br /&gt;
    bonusValues.weaponDefenseCoeff = 100;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  bonusValues.weaponBonusCoeff = 100 + weaponBonus;&lt;br /&gt;
  bonusValues.skillWardCoeff = 1 - skillWard / 100;&lt;br /&gt;
  bonusValues.skillBonusCoeff = 1 + skillBonus / 100;&lt;br /&gt;
  bonusValues.skillBonusByBonusCoeff = 100 + skillBonusByBonus;&lt;br /&gt;
&lt;br /&gt;
  battleValues.skillFormula = skillFormula;&lt;br /&gt;
  battleValues.skillRange = skillInfo.range;&lt;br /&gt;
  battleValues.attackValues.totalCardinal *= variationLength;&lt;br /&gt;
  battleValues.attackValues.possibleDamagesCount *= variationLength;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcWeights(minValue, maxValue, minInterval) {&lt;br /&gt;
  var firstWeightLimit = minValue + minInterval - 1;&lt;br /&gt;
  var lastWeightsLimit = maxValue - minInterval + 1;&lt;br /&gt;
  var weights = [];&lt;br /&gt;
&lt;br /&gt;
  for (var value = minValue; value &amp;lt; firstWeightLimit; value++) {&lt;br /&gt;
    weights.push(value - minValue + 1);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (var value = firstWeightLimit; value &amp;lt;= lastWeightsLimit; value++) {&lt;br /&gt;
    weights.push(minInterval);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (var value = lastWeightsLimit + 1; value &amp;lt;= maxValue; value++) {&lt;br /&gt;
    weights.push(maxValue - value + 1);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return weights;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcBlessingBonus(skillPowerTable, victim) {&lt;br /&gt;
  if (victim.isBlessed !== &amp;quot;on&amp;quot;) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var int = victim.intBlessing;&lt;br /&gt;
  var dex = victim.dexBlessing;&lt;br /&gt;
  var skillPower = getSkillPower(victim[&amp;quot;skillBlessing&amp;quot;], skillPowerTable);&lt;br /&gt;
&lt;br /&gt;
  if (!skillPower) {&lt;br /&gt;
    return 0;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var blessingBonus = floorMultiplication(&lt;br /&gt;
    ((int * 0.3 + 5) * (2 * skillPower + 0.5) + 0.3 * dex) / (skillPower + 2.3),&lt;br /&gt;
    1&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  if (victim.class === &amp;quot;dragon&amp;quot; &amp;amp;&amp;amp; isChecked(ictim.blessingOnself)) {&lt;br /&gt;
    blessingBonus = floorMultiplication(blessingBonus, 1.1);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return blessingBonus;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getSkillFormula(battle, skillId, battleValues, removeSkillVariation) {&lt;br /&gt;
  var { attacker, victim, attackFactor } = battleValues;&lt;br /&gt;
  var skillPowerTable = battle.constants.skillPowerTable;&lt;br /&gt;
&lt;br /&gt;
  var skillFormula;&lt;br /&gt;
  var skillInfo = { range: [0, 0] };&lt;br /&gt;
&lt;br /&gt;
  var { class: attackerClass, level: lv, vit, str, int, dex } = attacker;&lt;br /&gt;
&lt;br /&gt;
  if (skillId &amp;lt;= 9) {&lt;br /&gt;
    var skillPower = getSkillPower(&lt;br /&gt;
      attacker[&amp;quot;attackSkill&amp;quot; + skillId],&lt;br /&gt;
      skillPowerTable&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    var improvedBySkillBonus = false;&lt;br /&gt;
    var improvedByBonus = false;&lt;br /&gt;
&lt;br /&gt;
    if (attackerClass === &amp;quot;body&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Triple lacération&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.1 * atk + (0.5 * atk + 1.5 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Moulinet à l'épée&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              3 * atk + (0.8 * atk + 5 * str + 3 * dex + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Accélération&lt;br /&gt;
        case 5:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * atk + (atk + dex * 3 + str * 7 + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Volonté de vivre&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              (3 * atk + (atk + 1.5 * str) * skillPower) * 1.07,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          break;&lt;br /&gt;
        // Tremblement de terre&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              3 * atk +&lt;br /&gt;
                (0.9 * atk + variation + 5 * str + 3 * dex + lv) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;mental&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Attaque de l'esprit&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2.3 * atk + (4 * atk + 4 * str + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Attaque de la paume&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2.3 * atk + (3 * atk + 4 * str + 3 * vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Charge&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * atk + (2 * atk + 2 * dex + 2 * vit + 4 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          break;&lt;br /&gt;
        // Coup d'épée&lt;br /&gt;
        case 5:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * atk + (atk + 3 * dex + 5 * str + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Orbe de l'épée&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              (2 * atk + (2 * atk + 2 * dex + 2 * vit + 4 * str) * skillPower) *&lt;br /&gt;
                1.1,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          break;&lt;br /&gt;
        // Tremblement de terre&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              3 * atk +&lt;br /&gt;
                (0.9 * atk + variation + 5 * str + 3 * dex + lv) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;blade_fight&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Embuscade&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk + (1.2 * atk + variation + 4 * dex + 4 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [1, 50];&lt;br /&gt;
          skillInfo.range = [500, 700];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Attaque rapide&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk + (1.6 * atk + variation + 7 * dex + 7 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [1, 35];&lt;br /&gt;
          skillInfo.range = [200, 300];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Dague filante&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * atk + (0.5 * atk + 9 * dex + 7 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Brume empoisonnée&lt;br /&gt;
        case 5:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * lv + (atk + 3 * str + 18 * dex) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Poison insidieux&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              (2 * lv + (atk + 3 * str + 18 * dex) * skillPower) * 1.1,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          break;&lt;br /&gt;
        // Étoiles brillantes&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk + (1.7 * atk + variation + 6 * dex + 5 * lv) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;archery&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Tir à répétition&lt;br /&gt;
        // case 1:&lt;br /&gt;
        //   skillFormula = function (atk) {&lt;br /&gt;
        //     return floorMultiplication(&lt;br /&gt;
        //       atk + 0.2 * atk * Math.floor(2 + 6 * skillPower) + (0.8 * atk + 8 * dex * attackFactor + 2 * int) * skillPower,&lt;br /&gt;
        //       1&lt;br /&gt;
        //     );&lt;br /&gt;
        //   };&lt;br /&gt;
        //   improvedByBonus = true;&lt;br /&gt;
        //   break;&lt;br /&gt;
        // Pluie de flèches&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk + (1.7 * atk + 5 * dex + str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Flèche de feu&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.5 * atk + (2.6 * atk + 0.9 * int + variation) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [100, 300];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Foulée de plume&lt;br /&gt;
        case 4:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              (3 * dex + 200 + 2 * str + 2 * int) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.removeWeaponReduction = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Flèche empoisonnée&lt;br /&gt;
        case 5:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk +&lt;br /&gt;
                (1.4 * atk + variation + 7 * dex + 4 * str + 4 * int) *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [100, 200];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Coup étincelant&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              (atk +&lt;br /&gt;
                (1.2 * atk + variation + 6 * dex + 3 * str + 3 * int) *&lt;br /&gt;
                  skillPower) *&lt;br /&gt;
                1.2,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [100, 200];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Tir tempête&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.9 * atk + (2.6 * atk + variation) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;weaponary&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Toucher brûlant&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk +&lt;br /&gt;
                2 * lv +&lt;br /&gt;
                2 * int +&lt;br /&gt;
                (2 * atk + 4 * str + 14 * int) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Tourbillon du dragon&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.1 * atk +&lt;br /&gt;
                2 * lv +&lt;br /&gt;
                2 * int +&lt;br /&gt;
                (1.5 * atk + str + 12 * int) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Contre-sort&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              40 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                2 * int +&lt;br /&gt;
                (10 * int + 7 * mav + variation) * attackFactor * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [50, 100];&lt;br /&gt;
          break;&lt;br /&gt;
        // Coup démoniaque&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.9 * atk + (2.6 * atk + variation) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;black_magic&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Attaque des ténèbres&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              40 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                2 * int +&lt;br /&gt;
                (13 * int + 6 * mav + variation) * attackFactor * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [50, 100];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Attaque de flammes&lt;br /&gt;
        // case 2:&lt;br /&gt;
        //   skillFormula = function (mav, variation) {&lt;br /&gt;
        //     return floorMultiplication(&lt;br /&gt;
        //       5 * lv + 2 * int + (7 * int + 8 * mav + 4 * str + 2 * vit + variation) * skillPower,&lt;br /&gt;
        //       1&lt;br /&gt;
        //     );&lt;br /&gt;
        //   };&lt;br /&gt;
        //   skillInfo.range = [180, 100];&lt;br /&gt;
        //   improvedByBonus = true;&lt;br /&gt;
        //   break;&lt;br /&gt;
        // Esprit de flammes&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              30 +&lt;br /&gt;
                2 * lv +&lt;br /&gt;
                2 * int +&lt;br /&gt;
                (7 * int + 6 * mav + variation) * attackFactor * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [200, 500];&lt;br /&gt;
          break;&lt;br /&gt;
        // Frappe de l'esprit&lt;br /&gt;
        // case 5:&lt;br /&gt;
        //   skillFormula = function (mav, variation) {&lt;br /&gt;
        //     return floorMultiplication(&lt;br /&gt;
        //       40 + 2 * lv + 2 * int + (2 * vit + 2 * dex + 13 * int + 6 * mav + variation) * attackFactor * skillPower,&lt;br /&gt;
        //       1&lt;br /&gt;
        //     );&lt;br /&gt;
        //   };&lt;br /&gt;
        //   skillInfo.range = [180, 200];&lt;br /&gt;
        //   break;&lt;br /&gt;
        // Orbe des ténèbres&lt;br /&gt;
        case 6:&lt;br /&gt;
          skillFormula = function (mav) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              120 +&lt;br /&gt;
                6 * lv +&lt;br /&gt;
                (5 * vit + 5 * dex + 29 * int + 9 * mav) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Vague mortelle&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              120 +&lt;br /&gt;
                6 * lv +&lt;br /&gt;
                (5 * vit + 5 * dex + 30 * int + variation + 9 * mav) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;dragon&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Talisman volant&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (mav) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              70 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                (18 * int + 7 * str + 5 * mav + 50) * attackFactor * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [4, 10];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Dragon chassant&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (mav) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              60 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                (16 * int + 6 * dex + 6 * mav + 120) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [4, 10];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Rugissement du dragon&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (mav) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              70 +&lt;br /&gt;
                3 * lv +&lt;br /&gt;
                (20 * int + 3 * str + 10 * mav + 100) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [4, 10];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Météore&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              120 +&lt;br /&gt;
                6 * lv +&lt;br /&gt;
                (5 * vit + 5 * dex + 30 * int + variation + 9 * mav) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;heal&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Jet de foudre&lt;br /&gt;
        case 1:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              60 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                (8 * int + 2 * dex + 8 * mav + variation) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [6, 10];&lt;br /&gt;
          skillInfo.range = [5 * int, 15 * int];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Invocation de foudre&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              40 +&lt;br /&gt;
                4 * lv +&lt;br /&gt;
                (13 * int + 2 * str + 10 * mav + variation) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [6, 10];&lt;br /&gt;
          skillInfo.range = [5 * int, 16 * int];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Griffe de foudre&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (mav, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              50 +&lt;br /&gt;
                5 * lv +&lt;br /&gt;
                (8 * int + 2 * str + 8 * mav + variation) *&lt;br /&gt;
                  attackFactor *&lt;br /&gt;
                  skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 800];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    } else if (attackerClass === &amp;quot;lycan&amp;quot;) {&lt;br /&gt;
      switch (skillId) {&lt;br /&gt;
        // Déchiqueter&lt;br /&gt;
        // case 1:&lt;br /&gt;
        //   skillFormula = function (atk) {&lt;br /&gt;
        //     return floorMultiplication(&lt;br /&gt;
        //       1.1 * atk + (0.3 * atk + 1.5 * str) * skillPower,&lt;br /&gt;
        //       1&lt;br /&gt;
        //     );&lt;br /&gt;
        //   };&lt;br /&gt;
        //   skillInfo.weaponBonus = [5, 54];&lt;br /&gt;
        //   improvedByBonus = true;&lt;br /&gt;
        //   break;&lt;br /&gt;
        // Souffle de loup&lt;br /&gt;
        case 2:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              2 * atk + (atk + 3 * dex + 5 * str + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [5, 35];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          improvedBySkillBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Bond de loup&lt;br /&gt;
        case 3:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              atk + (1.6 * atk + 200 + 7 * dex + 7 * str) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.weaponBonus = [5, 35];&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Griffe de loup&lt;br /&gt;
        case 4:&lt;br /&gt;
          skillFormula = function (atk) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              3 * atk + (0.8 * atk + 6 * str + 2 * dex + vit) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          improvedByBonus = true;&lt;br /&gt;
          break;&lt;br /&gt;
        // Tempête cinglante&lt;br /&gt;
        case 9:&lt;br /&gt;
          skillFormula = function (atk, variation) {&lt;br /&gt;
            return floorMultiplication(&lt;br /&gt;
              1.8 * atk +&lt;br /&gt;
                (atk + 6 * dex + variation + 3 * str + lv) * skillPower,&lt;br /&gt;
              1&lt;br /&gt;
            );&lt;br /&gt;
          };&lt;br /&gt;
          skillInfo.range = [1, 1000];&lt;br /&gt;
          break;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
    if (improvedBySkillBonus) {&lt;br /&gt;
      skillInfo.skillBonus =&lt;br /&gt;
        16 * getSkillPower(attacker.skillBonus, skillPowerTable);&lt;br /&gt;
&lt;br /&gt;
      var skillWardChoice = victim.skillWardChoice;&lt;br /&gt;
&lt;br /&gt;
      if (skillWardChoice &amp;amp;&amp;amp; skillWardChoice === attackerClass) {&lt;br /&gt;
        skillInfo.skillWard =&lt;br /&gt;
          24 * getSkillPower(victim.skillWard, skillPowerTable);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (improvedByBonus) {&lt;br /&gt;
      skillInfo.skillBonusByBonus = attacker[&amp;quot;skillBonus&amp;quot; + skillId];&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (removeSkillVariation) {&lt;br /&gt;
      var averageVariation = (skillInfo.range[0] + skillInfo.range[0]) / 2;&lt;br /&gt;
      skillInfo.range = [averageVariation, averageVariation];&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    var skillPower = getSkillPower(&lt;br /&gt;
      attacker[&amp;quot;horseSkill&amp;quot; + skillId],&lt;br /&gt;
      skillPowerTable&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    switch (skillId) {&lt;br /&gt;
      // Combat équestre&lt;br /&gt;
      case 137:&lt;br /&gt;
        skillFormula = function (atk) {&lt;br /&gt;
          return floorMultiplication(atk + 2 * atk * skillPower, 1);&lt;br /&gt;
        };&lt;br /&gt;
        break;&lt;br /&gt;
      // Charge à cheval&lt;br /&gt;
      case 138:&lt;br /&gt;
        skillFormula = function (atk) {&lt;br /&gt;
          return floorMultiplication(&lt;br /&gt;
            2.4 * (200 + 1.5 * lv) + 600 * skillPower,&lt;br /&gt;
            1&lt;br /&gt;
          );&lt;br /&gt;
        };&lt;br /&gt;
        break;&lt;br /&gt;
      // Vague de Pouvoir&lt;br /&gt;
      case 139:&lt;br /&gt;
        skillFormula = function (atk) {&lt;br /&gt;
          return floorMultiplication(&lt;br /&gt;
            2 * (200 + 1.5 * lv) + 600 * skillPower,&lt;br /&gt;
            1&lt;br /&gt;
          );&lt;br /&gt;
        };&lt;br /&gt;
        break;&lt;br /&gt;
      // Grêle de flèches&lt;br /&gt;
      case 140:&lt;br /&gt;
        skillFormula = function (atk) {&lt;br /&gt;
          return floorMultiplication(atk + 2 * atk * skillPower, 1);&lt;br /&gt;
        };&lt;br /&gt;
        break;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  updateBattleValues(battleValues, skillFormula, skillInfo);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcMagicAttackValueAugmentation(&lt;br /&gt;
  magicAttackValueWeapon,&lt;br /&gt;
  magicAttackValueBonus&lt;br /&gt;
) {&lt;br /&gt;
  if (magicAttackValueBonus) {&lt;br /&gt;
    return Math.max(&lt;br /&gt;
      1,&lt;br /&gt;
      0.0025056 *&lt;br /&gt;
        magicAttackValueBonus ** 0.602338 *&lt;br /&gt;
        magicAttackValueWeapon ** 1.20476&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
  return 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getMagicAttackValueAugmentation(&lt;br /&gt;
  minMagicAttackValue,&lt;br /&gt;
  maxMagicAttackValue,&lt;br /&gt;
  magicAttackValueBonus&lt;br /&gt;
) {&lt;br /&gt;
  var magicAttackValueAugmentation = [];&lt;br /&gt;
&lt;br /&gt;
  for (&lt;br /&gt;
    var magicAttackValue = minMagicAttackValue;&lt;br /&gt;
    magicAttackValue &amp;lt;= maxMagicAttackValue;&lt;br /&gt;
    magicAttackValue++&lt;br /&gt;
  ) {&lt;br /&gt;
    magicAttackValueAugmentation.push(&lt;br /&gt;
      calcMagicAttackValueAugmentation(magicAttackValue, magicAttackValueBonus)&lt;br /&gt;
    );&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return magicAttackValueAugmentation;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcPhysicalDamages(battleValues) {&lt;br /&gt;
  var {&lt;br /&gt;
    attackFactor,&lt;br /&gt;
    mainAttackValue,&lt;br /&gt;
    attackValues: { minAttackValue, maxAttackValue, attackValueOther, weights },&lt;br /&gt;
    bonusValues,&lt;br /&gt;
    damagesTypeCombinaison,&lt;br /&gt;
  } = battleValues;&lt;br /&gt;
&lt;br /&gt;
  var damagesWeightedByType = {};&lt;br /&gt;
&lt;br /&gt;
  if (bonusValues.missPercentage) {&lt;br /&gt;
    damagesWeightedByType.miss = bonusValues.missPercentage / 100;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  for (var damagesType of damagesTypeCombinaison) {&lt;br /&gt;
    if (!damagesType.weight) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var damagesWeighted = {};&lt;br /&gt;
    damagesWeightedByType[damagesType.name] = damagesWeighted;&lt;br /&gt;
&lt;br /&gt;
    for (&lt;br /&gt;
      var attackValue = minAttackValue;&lt;br /&gt;
      attackValue &amp;lt;= maxAttackValue;&lt;br /&gt;
      attackValue++&lt;br /&gt;
    ) {&lt;br /&gt;
      var weight = weights[attackValue - minAttackValue] * damagesType.weight;&lt;br /&gt;
&lt;br /&gt;
      var secondaryAttackValue = 2 * attackValue + attackValueOther;&lt;br /&gt;
      var rawDamages =&lt;br /&gt;
        mainAttackValue +&lt;br /&gt;
        floorMultiplication(attackFactor, secondaryAttackValue);&lt;br /&gt;
&lt;br /&gt;
      var damagesWithPrimaryBonuses = calcDamageWithPrimaryBonuses(&lt;br /&gt;
        rawDamages,&lt;br /&gt;
        bonusValues&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      var minPiercingDamages =&lt;br /&gt;
        damagesWithPrimaryBonuses -&lt;br /&gt;
        bonusValues.defenseBoost +&lt;br /&gt;
        bonusValues.defenseMarriage;&lt;br /&gt;
&lt;br /&gt;
      if (minPiercingDamages &amp;lt;= 2) {&lt;br /&gt;
        for (var damages = 1; damages &amp;lt;= 5; damages++) {&lt;br /&gt;
          var finalDamages = calcDamageWithSecondaryBonuses(&lt;br /&gt;
            damages,&lt;br /&gt;
            bonusValues,&lt;br /&gt;
            damagesType,&lt;br /&gt;
            minPiercingDamages,&lt;br /&gt;
            damagesWithPrimaryBonuses&lt;br /&gt;
          );&lt;br /&gt;
&lt;br /&gt;
          addKeyValue(damagesWeighted, finalDamages, weight / 5);&lt;br /&gt;
        }&lt;br /&gt;
      } else {&lt;br /&gt;
        var finalDamages = calcDamageWithSecondaryBonuses(&lt;br /&gt;
          minPiercingDamages,&lt;br /&gt;
          bonusValues,&lt;br /&gt;
          damagesType,&lt;br /&gt;
          minPiercingDamages,&lt;br /&gt;
          damagesWithPrimaryBonuses&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        addKeyValue(damagesWeighted, finalDamages, weight);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return damagesWeightedByType;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcPhysicalSkillDamages(battleValues) {&lt;br /&gt;
  var {&lt;br /&gt;
    attackFactor,&lt;br /&gt;
    mainAttackValue,&lt;br /&gt;
    attackValues: { minAttackValue, maxAttackValue, attackValueOther, weights },&lt;br /&gt;
    bonusValues,&lt;br /&gt;
    damagesTypeCombinaison,&lt;br /&gt;
    skillFormula,&lt;br /&gt;
    skillRange: [minVariation, maxVariation],&lt;br /&gt;
  } = battleValues;&lt;br /&gt;
&lt;br /&gt;
  var damagesWeightedByType = {};&lt;br /&gt;
&lt;br /&gt;
  for (var damagesType of damagesTypeCombinaison) {&lt;br /&gt;
    if (!damagesType.weight) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var damagesWeighted = {};&lt;br /&gt;
    var savedDamages = {};&lt;br /&gt;
&lt;br /&gt;
    damagesWeightedByType[damagesType.name] = damagesWeighted;&lt;br /&gt;
&lt;br /&gt;
    for (&lt;br /&gt;
      var attackValue = minAttackValue;&lt;br /&gt;
      attackValue &amp;lt;= maxAttackValue;&lt;br /&gt;
      attackValue++&lt;br /&gt;
    ) {&lt;br /&gt;
      var weight = weights[attackValue - minAttackValue] * damagesType.weight;&lt;br /&gt;
&lt;br /&gt;
      var secondaryAttackValue = 2 * attackValue + attackValueOther;&lt;br /&gt;
      var rawDamages =&lt;br /&gt;
        mainAttackValue +&lt;br /&gt;
        floorMultiplication(attackFactor, secondaryAttackValue);&lt;br /&gt;
&lt;br /&gt;
      var damagesWithPrimaryBonuses = calcDamageWithPrimaryBonuses(&lt;br /&gt;
        rawDamages,&lt;br /&gt;
        bonusValues&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      for (&lt;br /&gt;
        var variation = minVariation;&lt;br /&gt;
        variation &amp;lt;= maxVariation;&lt;br /&gt;
        variation++&lt;br /&gt;
      ) {&lt;br /&gt;
        if (damagesWithPrimaryBonuses &amp;lt;= 2) {&lt;br /&gt;
          for (var damages = 1; damages &amp;lt;= 5; damages++) {&lt;br /&gt;
            damages *= bonusValues.useDamages;&lt;br /&gt;
&lt;br /&gt;
            var damagesWithFormula = skillFormula(damages, variation);&lt;br /&gt;
&lt;br /&gt;
            damagesWithFormula = Math.floor(&lt;br /&gt;
              (damagesWithFormula * bonusValues.weaponBonusCoeff) / 100&lt;br /&gt;
            );&lt;br /&gt;
&lt;br /&gt;
            var finalDamages = calcSkillDamageWithSecondaryBonuses(&lt;br /&gt;
              damagesWithFormula,&lt;br /&gt;
              bonusValues,&lt;br /&gt;
              damagesType,&lt;br /&gt;
              damagesWithPrimaryBonuses&lt;br /&gt;
            );&lt;br /&gt;
&lt;br /&gt;
            addKeyValue(damagesWeighted, finalDamages, weight / 5);&lt;br /&gt;
          }&lt;br /&gt;
        } else {&lt;br /&gt;
          damagesWithPrimaryBonuses *= bonusValues.useDamages;&lt;br /&gt;
&lt;br /&gt;
          var damagesWithFormula = skillFormula(&lt;br /&gt;
            damagesWithPrimaryBonuses,&lt;br /&gt;
            variation&lt;br /&gt;
          );&lt;br /&gt;
&lt;br /&gt;
          if (savedDamages.hasOwnProperty(damagesWithFormula)) {&lt;br /&gt;
            var finalDamages = savedDamages[damagesWithFormula];&lt;br /&gt;
            damagesWeighted[finalDamages] += weight;&lt;br /&gt;
            continue;&lt;br /&gt;
          }&lt;br /&gt;
&lt;br /&gt;
          var finalDamages = Math.floor(&lt;br /&gt;
            (damagesWithFormula * bonusValues.weaponBonusCoeff) / 100&lt;br /&gt;
          );&lt;br /&gt;
&lt;br /&gt;
          finalDamages = calcSkillDamageWithSecondaryBonuses(&lt;br /&gt;
            finalDamages,&lt;br /&gt;
            bonusValues,&lt;br /&gt;
            damagesType,&lt;br /&gt;
            damagesWithPrimaryBonuses&lt;br /&gt;
          );&lt;br /&gt;
&lt;br /&gt;
          savedDamages[damagesWithFormula] = finalDamages;&lt;br /&gt;
          addKeyValue(damagesWeighted, finalDamages, weight);&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return damagesWeightedByType;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcMagicSkillDamages(battleValues) {&lt;br /&gt;
  var {&lt;br /&gt;
    attackValues: {&lt;br /&gt;
      minMagicAttackValue,&lt;br /&gt;
      maxMagicAttackValue,&lt;br /&gt;
      magicAttackValueAugmentation,&lt;br /&gt;
      weights,&lt;br /&gt;
    },&lt;br /&gt;
    bonusValues,&lt;br /&gt;
    damagesTypeCombinaison,&lt;br /&gt;
    skillFormula,&lt;br /&gt;
    skillRange: [minVariation, maxVariation],&lt;br /&gt;
  } = battleValues;&lt;br /&gt;
&lt;br /&gt;
  var damagesWeightedByType = {};&lt;br /&gt;
&lt;br /&gt;
  for (var damagesType of damagesTypeCombinaison) {&lt;br /&gt;
    if (!damagesType.weight) {&lt;br /&gt;
      continue;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var damagesWeighted = {};&lt;br /&gt;
    var savedDamages = {};&lt;br /&gt;
&lt;br /&gt;
    damagesWeightedByType[damagesType.name] = damagesWeighted;&lt;br /&gt;
&lt;br /&gt;
    for (&lt;br /&gt;
      var magicAttackValue = minMagicAttackValue;&lt;br /&gt;
      magicAttackValue &amp;lt;= maxMagicAttackValue;&lt;br /&gt;
      magicAttackValue++&lt;br /&gt;
    ) {&lt;br /&gt;
      var index = magicAttackValue - minMagicAttackValue;&lt;br /&gt;
      var weight = weights[index] * damagesType.weight;&lt;br /&gt;
&lt;br /&gt;
      for (&lt;br /&gt;
        var variation = minVariation;&lt;br /&gt;
        variation &amp;lt;= maxVariation;&lt;br /&gt;
        variation++&lt;br /&gt;
      ) {&lt;br /&gt;
        var rawDamages = skillFormula(&lt;br /&gt;
          magicAttackValue + magicAttackValueAugmentation[index],&lt;br /&gt;
          variation&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        if (savedDamages.hasOwnProperty(rawDamages)) {&lt;br /&gt;
          var finalDamages = savedDamages[rawDamages];&lt;br /&gt;
          damagesWeighted[finalDamages] += weight;&lt;br /&gt;
          continue;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        var damagesWithPrimaryBonuses = Math.floor(&lt;br /&gt;
          (rawDamages * bonusValues.weaponBonusCoeff) / 100&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        damagesWithPrimaryBonuses = calcDamageWithPrimaryBonuses(&lt;br /&gt;
          damagesWithPrimaryBonuses,&lt;br /&gt;
          bonusValues&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        if (damagesWithPrimaryBonuses &amp;lt;= 2) {&lt;br /&gt;
          for (var damages = 1; damages &amp;lt;= 5; damages++) {&lt;br /&gt;
            var finalDamages = calcSkillDamageWithSecondaryBonuses(&lt;br /&gt;
              damages,&lt;br /&gt;
              bonusValues,&lt;br /&gt;
              damagesType,&lt;br /&gt;
              damagesWithPrimaryBonuses&lt;br /&gt;
            );&lt;br /&gt;
            addKeyValue(damagesWeighted, finalDamages, weight / 5);&lt;br /&gt;
          }&lt;br /&gt;
        } else {&lt;br /&gt;
          var finalDamages = calcSkillDamageWithSecondaryBonuses(&lt;br /&gt;
            damagesWithPrimaryBonuses,&lt;br /&gt;
            bonusValues,&lt;br /&gt;
            damagesType,&lt;br /&gt;
            damagesWithPrimaryBonuses&lt;br /&gt;
          );&lt;br /&gt;
&lt;br /&gt;
          savedDamages[rawDamages] = finalDamages;&lt;br /&gt;
          addKeyValue(damagesWeighted, finalDamages, weight);&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return damagesWeightedByType;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function calcDamages(&lt;br /&gt;
  attacker,&lt;br /&gt;
  victim,&lt;br /&gt;
  attackType,&lt;br /&gt;
  battle,&lt;br /&gt;
  removeSkillVariation&lt;br /&gt;
) {&lt;br /&gt;
  var damagesCalculator, skillId, skillType;&lt;br /&gt;
&lt;br /&gt;
  if (attackType === &amp;quot;physical&amp;quot;) {&lt;br /&gt;
    damagesCalculator = calcPhysicalDamages;&lt;br /&gt;
  } else if (attackType.startsWith(&amp;quot;attackSkill&amp;quot;)) {&lt;br /&gt;
    skillId = Number(attackType.split(&amp;quot;attackSkill&amp;quot;)[1]);&lt;br /&gt;
&lt;br /&gt;
    if (isMagicClass(attacker) || isDispell(attacker, skillId)) {&lt;br /&gt;
      skillType = &amp;quot;magic&amp;quot;;&lt;br /&gt;
      damagesCalculator = calcMagicSkillDamages;&lt;br /&gt;
    } else {&lt;br /&gt;
      skillType = &amp;quot;physical&amp;quot;;&lt;br /&gt;
      damagesCalculator = calcPhysicalSkillDamages;&lt;br /&gt;
    }&lt;br /&gt;
  } else if (attackType.startsWith(&amp;quot;horseSkill&amp;quot;)) {&lt;br /&gt;
    skillType = &amp;quot;physical&amp;quot;;&lt;br /&gt;
    skillId = Number(attackType.split(&amp;quot;horseSkill&amp;quot;)[1]);&lt;br /&gt;
    damagesCalculator = calcPhysicalSkillDamages;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var battleValues = createBattleValues(attacker, victim, battle, skillType);&lt;br /&gt;
&lt;br /&gt;
  if (skillId) {&lt;br /&gt;
    getSkillFormula(battle, skillId, battleValues, removeSkillVariation);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var {&lt;br /&gt;
    attackValues: { totalCardinal, possibleDamagesCount },&lt;br /&gt;
  } = battleValues;&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    damagesWeightedByType: damagesCalculator(battleValues),&lt;br /&gt;
    totalCardinal: totalCardinal,&lt;br /&gt;
    possibleDamagesCount: possibleDamagesCount,&lt;br /&gt;
    skillType: skillType,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function damagesWithoutVariation(&lt;br /&gt;
  attacker,&lt;br /&gt;
  victim,&lt;br /&gt;
  attackType,&lt;br /&gt;
  battle,&lt;br /&gt;
  characters&lt;br /&gt;
) {&lt;br /&gt;
  startDamagesTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
  var {&lt;br /&gt;
    damagesWeightedByType,&lt;br /&gt;
    totalCardinal,&lt;br /&gt;
    possibleDamagesCount,&lt;br /&gt;
    skillType,&lt;br /&gt;
  } = calcDamages(attacker, victim, attackType, battle);&lt;br /&gt;
&lt;br /&gt;
  endDamagesTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
  possibleDamagesCount = displayResults(&lt;br /&gt;
    possibleDamagesCount,&lt;br /&gt;
    totalCardinal,&lt;br /&gt;
    damagesWeightedByType,&lt;br /&gt;
    battle,&lt;br /&gt;
    attacker.name,&lt;br /&gt;
    victim.name&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  endDisplayTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
  displayFightInfo(&lt;br /&gt;
    possibleDamagesCount,&lt;br /&gt;
    endDamagesTime - startDamagesTime,&lt;br /&gt;
    endDisplayTime - endDamagesTime,&lt;br /&gt;
    battle&lt;br /&gt;
  );&lt;br /&gt;
  addPotentialErrorInformation(&lt;br /&gt;
    battle.errorInformation,&lt;br /&gt;
    attacker,&lt;br /&gt;
    victim,&lt;br /&gt;
    skillType,&lt;br /&gt;
    characters&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  hideElement(battle.bonusVariationResultContainer);&lt;br /&gt;
  showElement(battle.fightResultContainer);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function damagesWithVariation(&lt;br /&gt;
  attacker,&lt;br /&gt;
  victim,&lt;br /&gt;
  attackType,&lt;br /&gt;
  battle,&lt;br /&gt;
  entity,&lt;br /&gt;
  entityVariation&lt;br /&gt;
) {&lt;br /&gt;
  startTime = performance.now();&lt;br /&gt;
  var damagesByBonus = [];&lt;br /&gt;
  var augmentationByBonus = [];&lt;br /&gt;
  var {&lt;br /&gt;
    bonusVariationMinValue: minVariation,&lt;br /&gt;
    bonusVariationMaxValue: maxVariation,&lt;br /&gt;
  } = entity;&lt;br /&gt;
  var step = Math.ceil((maxVariation - minVariation + 1) / 500);&lt;br /&gt;
  var simulationCount = 0;&lt;br /&gt;
  var simulationTime;&lt;br /&gt;
&lt;br /&gt;
  for (&lt;br /&gt;
    var bonusValue = minVariation;&lt;br /&gt;
    bonusValue &amp;lt;= maxVariation;&lt;br /&gt;
    bonusValue += step&lt;br /&gt;
  ) {&lt;br /&gt;
    entity[entityVariation] = bonusValue;&lt;br /&gt;
&lt;br /&gt;
    var { damagesWeightedByType, totalCardinal } = calcDamages(&lt;br /&gt;
      copyObject(attacker),&lt;br /&gt;
      copyObject(victim),&lt;br /&gt;
      attackType,&lt;br /&gt;
      battle,&lt;br /&gt;
      true&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    var meanDamages = calcMeanDamages(damagesWeightedByType, totalCardinal);&lt;br /&gt;
&lt;br /&gt;
    if (bonusValue === minVariation) {&lt;br /&gt;
      var firstDamages = Math.max(meanDamages, 1e-3);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    damagesByBonus.push({ x: bonusValue, y: meanDamages });&lt;br /&gt;
    augmentationByBonus.push({&lt;br /&gt;
      x: bonusValue,&lt;br /&gt;
      y: meanDamages / firstDamages - 1,&lt;br /&gt;
    });&lt;br /&gt;
    simulationCount++;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  endTime = performance.now();&lt;br /&gt;
&lt;br /&gt;
  battle.damagesByBonus = damagesByBonus.concat(entityVariation);&lt;br /&gt;
&lt;br /&gt;
  addToBonusVariationChart(&lt;br /&gt;
    damagesByBonus,&lt;br /&gt;
    augmentationByBonus,&lt;br /&gt;
    entity.bonusVariationDisplay,&lt;br /&gt;
    battle.bonusVariationChart&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  simulationCount = battle.numberFormats.default.format(simulationCount);&lt;br /&gt;
  simulationTime = battle.numberFormats.second.format(&lt;br /&gt;
    (endTime - startTime) / 1000&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  battle.simulationCounter.textContent = simulationCount;&lt;br /&gt;
  battle.simulationTime.textContent = simulationTime;&lt;br /&gt;
&lt;br /&gt;
  hideElement(battle.fightResultContainer);&lt;br /&gt;
  showElement(battle.bonusVariationResultContainer);&lt;br /&gt;
&lt;br /&gt;
  if (&lt;br /&gt;
    isChecked(attacker.bonusVariationActivation) &amp;amp;&amp;amp;&lt;br /&gt;
    isChecked(victim.bonusVariationActivation)&lt;br /&gt;
  ) {&lt;br /&gt;
    showElement(battle.errorInformation[&amp;quot;attacker-victim-variation&amp;quot;]);&lt;br /&gt;
  } else {&lt;br /&gt;
    hideElement(battle.errorInformation[&amp;quot;attacker-victim-variation&amp;quot;]);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function changeMonsterValues(monster, instance, attacker) {&lt;br /&gt;
  switch (instance) {&lt;br /&gt;
    case &amp;quot;SungMahiTower&amp;quot;:&lt;br /&gt;
      var sungMahiFloor = 1;&lt;br /&gt;
      var sungMahiStep = 1;&lt;br /&gt;
      var rawDefense = 120;&lt;br /&gt;
&lt;br /&gt;
      if (isPC(attacker)) {&lt;br /&gt;
        sungMahiFloor = attacker.sungMahiFloor;&lt;br /&gt;
        sungMahiStep = attacker.sungMahiStep;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (monster.rank === 5) {&lt;br /&gt;
        monster.level = 121;&lt;br /&gt;
        monster.dex = 75;&lt;br /&gt;
        rawDefense += 1;&lt;br /&gt;
      } else if (monster.rank === 6) {&lt;br /&gt;
        monster.level = 123;&lt;br /&gt;
        monster.dex = 75;&lt;br /&gt;
        rawDefense += 1;&lt;br /&gt;
      } else {&lt;br /&gt;
        monster.level = 120;&lt;br /&gt;
        monster.dex = 68;&lt;br /&gt;
      }&lt;br /&gt;
      monster.vit = 100;&lt;br /&gt;
      monster.rawDefense = rawDefense + (sungMahiStep - 1) * 6;&lt;br /&gt;
      monster.fistDefense = 0;&lt;br /&gt;
      monster.swordDefense = 0;&lt;br /&gt;
      monster.twoHandedSwordDefense = 0;&lt;br /&gt;
      monster.daggerDefense = 0;&lt;br /&gt;
      monster.bellDefense = 0;&lt;br /&gt;
      monster.fanDefense = 0;&lt;br /&gt;
      monster.arrowDefense = 0;&lt;br /&gt;
      monster.clawDefense = 0;&lt;br /&gt;
      monster.magicResistance = 0;&lt;br /&gt;
      monster.fireResistance = -20;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createWeapon(weaponVnum) {&lt;br /&gt;
  var weapon = weaponData[weaponVnum];&lt;br /&gt;
  var weaponName = weapon[0];&lt;br /&gt;
&lt;br /&gt;
  return {&lt;br /&gt;
    name: weaponName,&lt;br /&gt;
    type: weapon[1],&lt;br /&gt;
    minAttackValue: weapon[2][2],&lt;br /&gt;
    maxAttackValue: weapon[2][3],&lt;br /&gt;
    minMagicAttackValue: weapon[2][0],&lt;br /&gt;
    maxMagicAttackValue: weapon[2][1],&lt;br /&gt;
    upgrades: weapon[3],&lt;br /&gt;
    isSerpent: isValueInArray(&amp;quot;serpent&amp;quot;, weaponName.toLowerCase()),&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createMonster(monsterVnum, attacker) {&lt;br /&gt;
  var monsterAttributes = monsterData[monsterVnum];&lt;br /&gt;
&lt;br /&gt;
  var monster = {&lt;br /&gt;
    name: monsterAttributes[36],&lt;br /&gt;
    rank: monsterAttributes[0],&lt;br /&gt;
    race: monsterAttributes[1],&lt;br /&gt;
    attack: monsterAttributes[2],&lt;br /&gt;
    level: monsterAttributes[3],&lt;br /&gt;
    type: monsterAttributes[4],&lt;br /&gt;
    str: monsterAttributes[5],&lt;br /&gt;
    dex: monsterAttributes[6],&lt;br /&gt;
    vit: monsterAttributes[7],&lt;br /&gt;
    int: monsterAttributes[8],&lt;br /&gt;
    minAttackValue: monsterAttributes[9],&lt;br /&gt;
    maxAttackValue: monsterAttributes[10],&lt;br /&gt;
    rawDefense: monsterAttributes[11],&lt;br /&gt;
    criticalHit: monsterAttributes[12],&lt;br /&gt;
    piercingHit: monsterAttributes[13],&lt;br /&gt;
    fistDefense: monsterAttributes[14],&lt;br /&gt;
    swordDefense: monsterAttributes[15],&lt;br /&gt;
    twoHandedSwordDefense: monsterAttributes[16],&lt;br /&gt;
    daggerDefense: monsterAttributes[17],&lt;br /&gt;
    bellDefense: monsterAttributes[18],&lt;br /&gt;
    fanDefense: monsterAttributes[19],&lt;br /&gt;
    arrowDefense: monsterAttributes[20],&lt;br /&gt;
    clawDefense: monsterAttributes[21],&lt;br /&gt;
    fireResistance: monsterAttributes[22],&lt;br /&gt;
    lightningResistance: monsterAttributes[23],&lt;br /&gt;
    magicResistance: monsterAttributes[24],&lt;br /&gt;
    windResistance: monsterAttributes[25],&lt;br /&gt;
    lightningBonus: monsterAttributes[26],&lt;br /&gt;
    fireBonus: monsterAttributes[27],&lt;br /&gt;
    iceBonus: monsterAttributes[28],&lt;br /&gt;
    windBonus: monsterAttributes[29],&lt;br /&gt;
    earthBonus: monsterAttributes[30],&lt;br /&gt;
    darknessBonus: monsterAttributes[31],&lt;br /&gt;
    darknessResistance: monsterAttributes[32],&lt;br /&gt;
    iceResistance: monsterAttributes[33],&lt;br /&gt;
    earthResistance: monsterAttributes[34],&lt;br /&gt;
    damageMultiplier: monsterAttributes[35],&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  // monster.instance = 0;&lt;br /&gt;
&lt;br /&gt;
  // if (attacker &amp;amp;&amp;amp; monster.instance === 0) {&lt;br /&gt;
  //   changeMonsterValues(monster, &amp;quot;SungMahiTower&amp;quot;, attacker);&lt;br /&gt;
  // }&lt;br /&gt;
&lt;br /&gt;
  monster.defense = monster.rawDefense + monster.level + monster.vit;&lt;br /&gt;
&lt;br /&gt;
  return monster;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function addPotentialErrorInformation(&lt;br /&gt;
  errorInformation,&lt;br /&gt;
  attacker,&lt;br /&gt;
  victim,&lt;br /&gt;
  skillType,&lt;br /&gt;
  characters&lt;br /&gt;
) {&lt;br /&gt;
  for (var error of Object.values(errorInformation)) {&lt;br /&gt;
    hideElement(error);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (isPC(attacker)) {&lt;br /&gt;
    if (isRiding(attacker)) {&lt;br /&gt;
      if (attacker.horsePoint === 0) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;horse-level&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
      showElement(errorInformation[&amp;quot;horse-stat&amp;quot;]);&lt;br /&gt;
    } else if (isPolymorph(attacker)) {&lt;br /&gt;
      if (attacker.polymorphPoint === 0) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;polymorph-level&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      if (&lt;br /&gt;
        (attacker.polymorphPoint &amp;lt;= 39 &amp;amp;&amp;amp; attacker.attackValuePercent &amp;lt;= 199) ||&lt;br /&gt;
        (attacker.polymorphPoint === 40 &amp;amp;&amp;amp; attacker.attackValuePercent &amp;lt;= 299)&lt;br /&gt;
      ) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;polymorph-bonus&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
    if (skillType === &amp;quot;magic&amp;quot;) {&lt;br /&gt;
      if (attacker.magicAttackValue) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;magic-attack-value-bonus&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
      if (victim.magicResistance) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;magic-resistance&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  } else {&lt;br /&gt;
    showElement(errorInformation[&amp;quot;monster-attacker&amp;quot;]);&lt;br /&gt;
    if (isMagicAttacker(attacker) &amp;amp;&amp;amp; victim.magicResistance) {&lt;br /&gt;
      showElement(errorInformation[&amp;quot;magic-resistance&amp;quot;]);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (isPC(victim)) {&lt;br /&gt;
    if (isRiding(victim)) {&lt;br /&gt;
      showElement(errorInformation[&amp;quot;horse-stat&amp;quot;]);&lt;br /&gt;
    } else if (isPolymorph(victim)) {&lt;br /&gt;
      if (attacker.polymorphPoint === 0) {&lt;br /&gt;
        showElement(errorInformation[&amp;quot;polymorph-level&amp;quot;]);&lt;br /&gt;
      }&lt;br /&gt;
      showElement(errorInformation[&amp;quot;polymorph-defense&amp;quot;]);&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  if (characters.unsavedChanges) {&lt;br /&gt;
    showElement(errorInformation[&amp;quot;save&amp;quot;]);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function reduceChartPointsListener(battle) {&lt;br /&gt;
  var {&lt;br /&gt;
    reduceChartPointsContainer,&lt;br /&gt;
    reduceChartPoints,&lt;br /&gt;
    numberFormats: { second: numberFormat },&lt;br /&gt;
    displayTime,&lt;br /&gt;
  } = battle;&lt;br /&gt;
&lt;br /&gt;
  reduceChartPoints.addEventListener(&amp;quot;change&amp;quot;, function () {&lt;br /&gt;
    var startDisplayTime = performance.now();&lt;br /&gt;
    var scatterDataByType = battle.scatterDataByType;&lt;br /&gt;
    var {&lt;br /&gt;
      chart,&lt;br /&gt;
      maxPoints,&lt;br /&gt;
      chart: {&lt;br /&gt;
        data: { datasets },&lt;br /&gt;
      },&lt;br /&gt;
    } = battle.damagesChart;&lt;br /&gt;
    var addAnimations = false;&lt;br /&gt;
&lt;br /&gt;
    for (var index = 0; index &amp;lt; datasets.length; index++) {&lt;br /&gt;
      var dataset = datasets[index];&lt;br /&gt;
      var scatterData = scatterDataByType[dataset.name];&lt;br /&gt;
&lt;br /&gt;
      if (dataset.canBeReduced &amp;amp;&amp;amp; reduceChartPoints.checked) {&lt;br /&gt;
        dataset.data = aggregateDamages(scatterData, maxPoints);&lt;br /&gt;
        addAnimations = true;&lt;br /&gt;
      } else {&lt;br /&gt;
        dataset.data = scatterData;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    handleChartAnimations(chart, addAnimations);&lt;br /&gt;
    chart.update();&lt;br /&gt;
&lt;br /&gt;
    displayTime.textContent = numberFormat.format(&lt;br /&gt;
      (performance.now() - startDisplayTime) / 1000&lt;br /&gt;
    );&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  reduceChartPointsContainer.addEventListener(&amp;quot;pointerup&amp;quot;, function (event) {&lt;br /&gt;
    if (event.pointerType === &amp;quot;mouse&amp;quot;) {&lt;br /&gt;
      reduceChartPoints.click();&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function downloadRawDataListener(battle) {&lt;br /&gt;
  var { downLoadRawData, downLoadRawDataVariation } = battle;&lt;br /&gt;
  var fileType = &amp;quot;text/csv;charset=utf-8;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  downLoadRawData.addEventListener(&amp;quot;click&amp;quot;, function () {&lt;br /&gt;
    var damagesWeightedByType = battle.damagesWeightedByType;&lt;br /&gt;
    var filename = &amp;quot;raw_damages.csv&amp;quot;;&lt;br /&gt;
    var csvContent = &amp;quot;damage,probabilities,damageType\n&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    for (var damagesType in damagesWeightedByType) {&lt;br /&gt;
      var damagesWeighted = damagesWeightedByType[damagesType];&lt;br /&gt;
&lt;br /&gt;
      for (var damages in damagesWeighted) {&lt;br /&gt;
        csvContent +=&lt;br /&gt;
          damages + &amp;quot;,&amp;quot; + damagesWeighted[damages] + &amp;quot;,&amp;quot; + damagesType + &amp;quot;\n&amp;quot;;&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    downloadData(csvContent, fileType, filename);&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  downLoadRawDataVariation.addEventListener(&amp;quot;click&amp;quot;, function () {&lt;br /&gt;
    var damagesByBonus = battle.damagesByBonus;&lt;br /&gt;
    var damagesByBonusLength = damagesByBonus.length;&lt;br /&gt;
    var filename = &amp;quot;damages_variation.csv&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    if (!damagesByBonusLength) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var csvContent =&lt;br /&gt;
      damagesByBonus[damagesByBonusLength - 1] + &amp;quot;,averageDamage\n&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    for (var index = 0; index &amp;lt; damagesByBonusLength - 1; index++) {&lt;br /&gt;
      var row = damagesByBonus[index];&lt;br /&gt;
&lt;br /&gt;
      csvContent += row.x + &amp;quot;,&amp;quot; + row.y + &amp;quot;\n&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    downloadData(csvContent, fileType, filename);&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function displayResults(&lt;br /&gt;
  possibleDamagesCount,&lt;br /&gt;
  totalCardinal,&lt;br /&gt;
  damagesWeightedByType,&lt;br /&gt;
  battle,&lt;br /&gt;
  attackerName,&lt;br /&gt;
  victimName&lt;br /&gt;
) {&lt;br /&gt;
  var [&lt;br /&gt;
    meanDamages,&lt;br /&gt;
    minDamages,&lt;br /&gt;
    maxDamages,&lt;br /&gt;
    scatterDataByType,&lt;br /&gt;
    possibleDamagesCount,&lt;br /&gt;
    uniqueDamagesCount,&lt;br /&gt;
  ] = prepareDamagesData(&lt;br /&gt;
    damagesWeightedByType,&lt;br /&gt;
    possibleDamagesCount,&lt;br /&gt;
    totalCardinal&lt;br /&gt;
  );&lt;br /&gt;
&lt;br /&gt;
  addToDamagesChart(&lt;br /&gt;
    scatterDataByType,&lt;br /&gt;
    battle.damagesChart,&lt;br /&gt;
    battle.reduceChartPoints.checked&lt;br /&gt;
  );&lt;br /&gt;
  updateDamagesChartDescription(&lt;br /&gt;
    battle.uniqueDamagesCounters,&lt;br /&gt;
    uniqueDamagesCount,&lt;br /&gt;
    battle.numberFormats.default&lt;br /&gt;
  );&lt;br /&gt;
  displayFightResults(&lt;br /&gt;
    battle,&lt;br /&gt;
    attackerName,&lt;br /&gt;
    victimName,&lt;br /&gt;
    meanDamages,&lt;br /&gt;
    minDamages,&lt;br /&gt;
    maxDamages&lt;br /&gt;
  );&lt;br /&gt;
  battle.damagesWeightedByType = damagesWeightedByType;&lt;br /&gt;
  battle.scatterDataByType = scatterDataByType;&lt;br /&gt;
&lt;br /&gt;
  return possibleDamagesCount;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function displayFightResults(&lt;br /&gt;
  battle,&lt;br /&gt;
  attackerName,&lt;br /&gt;
  victimName,&lt;br /&gt;
  meanDamages,&lt;br /&gt;
  minDamages,&lt;br /&gt;
  maxDamages&lt;br /&gt;
) {&lt;br /&gt;
  var {&lt;br /&gt;
    tableResultFight,&lt;br /&gt;
    tableResultHistory,&lt;br /&gt;
    attackTypeSelection,&lt;br /&gt;
    savedFights,&lt;br /&gt;
    numberFormats: { default: numberFormat },&lt;br /&gt;
    deleteFightTemplate,&lt;br /&gt;
  } = battle;&lt;br /&gt;
&lt;br /&gt;
  hideElement(tableResultHistory.rows[1]);&lt;br /&gt;
&lt;br /&gt;
  var valuesToDisplay = [&lt;br /&gt;
    attackerName,&lt;br /&gt;
    victimName,&lt;br /&gt;
    attackTypeSelection.options[attackTypeSelection.selectedIndex].textContent,&lt;br /&gt;
    meanDamages,&lt;br /&gt;
    minDamages,&lt;br /&gt;
    maxDamages,&lt;br /&gt;
  ];&lt;br /&gt;
&lt;br /&gt;
  savedFights.push(valuesToDisplay);&lt;br /&gt;
  updateSavedFights(savedFights);&lt;br /&gt;
&lt;br /&gt;
  editTableResultRow(tableResultFight.rows[1], valuesToDisplay, numberFormat);&lt;br /&gt;
  addRowToTableResultHistory(&lt;br /&gt;
    tableResultHistory,&lt;br /&gt;
    valuesToDisplay,&lt;br /&gt;
    deleteFightTemplate,&lt;br /&gt;
    numberFormat&lt;br /&gt;
  );&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function displayFightInfo(&lt;br /&gt;
  possibleDamagesCount,&lt;br /&gt;
  damagesTime,&lt;br /&gt;
  displayTime,&lt;br /&gt;
  battle&lt;br /&gt;
) {&lt;br /&gt;
  var container = battle.possibleDamagesCounter.parentElement;&lt;br /&gt;
&lt;br /&gt;
  if (possibleDamagesCount &amp;lt;= 1) {&lt;br /&gt;
    hideElement(container);&lt;br /&gt;
    return;&lt;br /&gt;
  } else {&lt;br /&gt;
    showElement(container);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  possibleDamagesCount =&lt;br /&gt;
    battle.numberFormats.default.format(possibleDamagesCount);&lt;br /&gt;
  damagesTime = battle.numberFormats.second.format(damagesTime / 1000);&lt;br /&gt;
  displayTime = battle.numberFormats.second.format(displayTime / 1000);&lt;br /&gt;
&lt;br /&gt;
  battle.possibleDamagesCounter.textContent = possibleDamagesCount;&lt;br /&gt;
  battle.damagesTime.textContent = damagesTime;&lt;br /&gt;
  battle.displayTime.textContent = displayTime;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function isPseudoSaved(characters, pseudo) {&lt;br /&gt;
  return characters.savedCharacters.hasOwnProperty(pseudo);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createBattle(characters, battle) {&lt;br /&gt;
  battle.battleForm.addEventListener(&amp;quot;submit&amp;quot;, function (event) {&lt;br /&gt;
    event.preventDefault();&lt;br /&gt;
&lt;br /&gt;
    // auto save&lt;br /&gt;
    if (characters.unsavedChanges) {&lt;br /&gt;
      characters.saveButton.click();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var battleInfo = new FormData(event.target);&lt;br /&gt;
    var attackerName = battleInfo.get(&amp;quot;attacker&amp;quot;);&lt;br /&gt;
    var attackType = battleInfo.get(&amp;quot;attackTypeSelection&amp;quot;);&lt;br /&gt;
    var victimName = battleInfo.get(&amp;quot;victim&amp;quot;);&lt;br /&gt;
    var attackerVariation;&lt;br /&gt;
    var victimVariation;&lt;br /&gt;
&lt;br /&gt;
    if (!attackerName &amp;amp;&amp;amp; !attackType &amp;amp;&amp;amp; !victimName) {&lt;br /&gt;
      return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isPseudoSaved(characters, attackerName)) {&lt;br /&gt;
      var attacker = copyObject(characters.savedCharacters[attackerName]);&lt;br /&gt;
      attackerVariation = attacker.bonusVariation;&lt;br /&gt;
    } else {&lt;br /&gt;
      var attacker = createMonster(attackerName);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (isPseudoSaved(characters, victimName)) {&lt;br /&gt;
      var victim = copyObject(characters.savedCharacters[victimName]);&lt;br /&gt;
      victimVariation = victim.bonusVariation;&lt;br /&gt;
    } else {&lt;br /&gt;
      var victim = createMonster(victimName, attacker);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (&lt;br /&gt;
      isChecked(attacker.bonusVariationActivation) &amp;amp;&amp;amp;&lt;br /&gt;
      attacker.hasOwnProperty(attackerVariation) &amp;amp;&amp;amp;&lt;br /&gt;
      attacker.bonusVariationMinValue &amp;lt; attacker.bonusVariationMaxValue&lt;br /&gt;
    ) {&lt;br /&gt;
      damagesWithVariation(&lt;br /&gt;
        attacker,&lt;br /&gt;
        victim,&lt;br /&gt;
        attackType,&lt;br /&gt;
        battle,&lt;br /&gt;
        attacker,&lt;br /&gt;
        attackerVariation&lt;br /&gt;
      );&lt;br /&gt;
    } else if (&lt;br /&gt;
      isChecked(victim.bonusVariationActivation) &amp;amp;&amp;amp;&lt;br /&gt;
      victim.hasOwnProperty(victimVariation) &amp;amp;&amp;amp;&lt;br /&gt;
      victim.bonusVariationMinValue &amp;lt; victim.bonusVariationMaxValue&lt;br /&gt;
    ) {&lt;br /&gt;
      damagesWithVariation(&lt;br /&gt;
        attacker,&lt;br /&gt;
        victim,&lt;br /&gt;
        attackType,&lt;br /&gt;
        battle,&lt;br /&gt;
        victim,&lt;br /&gt;
        victimVariation&lt;br /&gt;
      );&lt;br /&gt;
    } else {&lt;br /&gt;
      damagesWithoutVariation(attacker, victim, attackType, battle, characters);&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createMapping() {&lt;br /&gt;
  mapping = {&lt;br /&gt;
    typeFlag: [&lt;br /&gt;
      &amp;quot;animalBonus&amp;quot;, // 0&lt;br /&gt;
      &amp;quot;humanBonus&amp;quot;, // 1&lt;br /&gt;
      &amp;quot;orcBonus&amp;quot;, // 2&lt;br /&gt;
      &amp;quot;mysticBonus&amp;quot;, // 3&lt;br /&gt;
      &amp;quot;undeadBonus&amp;quot;, // 4&lt;br /&gt;
      &amp;quot;insectBonus&amp;quot;, // 5&lt;br /&gt;
      &amp;quot;desertBonus&amp;quot;, // 6&lt;br /&gt;
      &amp;quot;devilBonus&amp;quot;, // 7&lt;br /&gt;
    ],&lt;br /&gt;
    raceBonus: {&lt;br /&gt;
      warrior: &amp;quot;warriorBonus&amp;quot;,&lt;br /&gt;
      sura: &amp;quot;suraBonus&amp;quot;,&lt;br /&gt;
      ninja: &amp;quot;ninjaBonus&amp;quot;,&lt;br /&gt;
      shaman: &amp;quot;shamanBonus&amp;quot;,&lt;br /&gt;
      lycan: &amp;quot;lycanBonus&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    raceResistance: {&lt;br /&gt;
      warrior: &amp;quot;warriorResistance&amp;quot;,&lt;br /&gt;
      sura: &amp;quot;suraResistance&amp;quot;,&lt;br /&gt;
      ninja: &amp;quot;ninjaResistance&amp;quot;,&lt;br /&gt;
      shaman: &amp;quot;shamanResistance&amp;quot;,&lt;br /&gt;
      lycan: &amp;quot;lycanResistance&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    defenseWeapon: [&lt;br /&gt;
      &amp;quot;swordDefense&amp;quot;, // 0&lt;br /&gt;
      &amp;quot;daggerDefense&amp;quot;, // 1&lt;br /&gt;
      &amp;quot;arrowDefense&amp;quot;, // 2&lt;br /&gt;
      &amp;quot;twoHandedSwordDefense&amp;quot;, // 3&lt;br /&gt;
      &amp;quot;bellDefense&amp;quot;, // 4&lt;br /&gt;
      &amp;quot;clawDefense&amp;quot;, // 5&lt;br /&gt;
      &amp;quot;fanDefense&amp;quot;, // 6&lt;br /&gt;
      &amp;quot;swordDefense&amp;quot;, // 7&lt;br /&gt;
      &amp;quot;fistDefense&amp;quot;, // 8&lt;br /&gt;
    ],&lt;br /&gt;
    breakWeapon: [&lt;br /&gt;
      &amp;quot;breakSwordDefense&amp;quot;, // 0&lt;br /&gt;
      &amp;quot;breakDaggerDefense&amp;quot;, // 1&lt;br /&gt;
      &amp;quot;breakArrowDefense&amp;quot;, // 2&lt;br /&gt;
      &amp;quot;breakTwoHandedSwordDefense&amp;quot;, // 3&lt;br /&gt;
      &amp;quot;breakBellDefense&amp;quot;, // 4&lt;br /&gt;
      &amp;quot;breakClawDefense&amp;quot;, // 5&lt;br /&gt;
      &amp;quot;breakFanDefense&amp;quot;, // 6&lt;br /&gt;
      &amp;quot;breakSwordDefense&amp;quot;, // 7&lt;br /&gt;
    ],&lt;br /&gt;
    elementBonus: [&lt;br /&gt;
      &amp;quot;fireBonus&amp;quot;, // 0&lt;br /&gt;
      &amp;quot;iceBonus&amp;quot;, // 1&lt;br /&gt;
      &amp;quot;windBonus&amp;quot;, // 2&lt;br /&gt;
      &amp;quot;lightningBonus&amp;quot;, // 3&lt;br /&gt;
      &amp;quot;earthBonus&amp;quot;, // 4&lt;br /&gt;
      &amp;quot;darknessBonus&amp;quot;, // 5&lt;br /&gt;
    ],&lt;br /&gt;
    elementResistance: [&lt;br /&gt;
      &amp;quot;fireResistance&amp;quot;, // 0&lt;br /&gt;
      &amp;quot;iceResistance&amp;quot;, // 1&lt;br /&gt;
      &amp;quot;windResistance&amp;quot;, // 2&lt;br /&gt;
      &amp;quot;lightningResistance&amp;quot;, // 3&lt;br /&gt;
      &amp;quot;earthResistance&amp;quot;, // 4&lt;br /&gt;
      &amp;quot;darknessResistance&amp;quot;, // 5&lt;br /&gt;
    ],&lt;br /&gt;
  };&lt;br /&gt;
  return mapping;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createConstants() {&lt;br /&gt;
  var constants = {&lt;br /&gt;
    polymorphPowerTable: [&lt;br /&gt;
      10, 11, 11, 12, 13, 13, 14, 15, 16, 17, 18, 19, 20, 22, 23, 24, 26, 27,&lt;br /&gt;
      29, 31, 33, 35, 37, 39, 41, 44, 46, 49, 52, 55, 59, 62, 66, 70, 74, 79,&lt;br /&gt;
      84, 89, 94, 100, 0,&lt;br /&gt;
    ],&lt;br /&gt;
    skillPowerTable: [&lt;br /&gt;
      0, 0.05, 0.06, 0.08, 0.1, 0.12, 0.14, 0.16, 0.18, 0.2, 0.22, 0.24, 0.26,&lt;br /&gt;
      0.28, 0.3, 0.32, 0.34, 0.36, 0.38, 0.4, 0.5, 0.52, 0.54, 0.56, 0.58, 0.6,&lt;br /&gt;
      0.63, 0.66, 0.69, 0.72, 0.82, 0.85, 0.88, 0.91, 0.94, 0.98, 1.02, 1.06,&lt;br /&gt;
      1.1, 1.15, 1.25,&lt;br /&gt;
    ],&lt;br /&gt;
    marriageTable: {&lt;br /&gt;
      harmonyEarrings: [4, 5, 6, 8],&lt;br /&gt;
      loveEarrings: [4, 5, 6, 8],&lt;br /&gt;
      harmonyBracelet: [4, 5, 6, 8],&lt;br /&gt;
      loveNecklace: [20, 25, 30, 40],&lt;br /&gt;
      harmonyNecklace: [12, 16, 20, 30],&lt;br /&gt;
    },&lt;br /&gt;
    allowedWeaponsPerRace: {&lt;br /&gt;
      warrior: [0, 3, 8],&lt;br /&gt;
      ninja: [0, 1, 2, 8],&lt;br /&gt;
      sura: [0, 7, 8],&lt;br /&gt;
      shaman: [4, 6, 8],&lt;br /&gt;
      lycan: [5, 8],&lt;br /&gt;
    },&lt;br /&gt;
    translation: {&lt;br /&gt;
      fr: {&lt;br /&gt;
        damages: &amp;quot;Dégâts&amp;quot;,&lt;br /&gt;
        percentage: &amp;quot;Pourcentage&amp;quot;,&lt;br /&gt;
        miss: &amp;quot;Miss&amp;quot;,&lt;br /&gt;
        normalHit: &amp;quot;Coup classique&amp;quot;,&lt;br /&gt;
        criticalHit: &amp;quot;Coup critique&amp;quot;,&lt;br /&gt;
        piercingHit: &amp;quot;Coup perçant&amp;quot;,&lt;br /&gt;
        criticalPiercingHit: &amp;quot;Coup critique perçant&amp;quot;,&lt;br /&gt;
        damagesRepartition: &amp;quot;Distribution des dégâts&amp;quot;,&lt;br /&gt;
        averageDamages: &amp;quot;Dégâts moyens&amp;quot;,&lt;br /&gt;
        damagesAugmentation: &amp;quot;Augmentation des dégâts&amp;quot;,&lt;br /&gt;
        bonusVariationTitle: [&lt;br /&gt;
          &amp;quot;Évolution des dégâts moyens&amp;quot;,&lt;br /&gt;
          &amp;quot;par rapport à la valeur d'un bonus&amp;quot;,&lt;br /&gt;
        ],&lt;br /&gt;
      },&lt;br /&gt;
      en: {&lt;br /&gt;
        damages: &amp;quot;Damage&amp;quot;,&lt;br /&gt;
        percentage: &amp;quot;Percentage&amp;quot;,&lt;br /&gt;
        miss: &amp;quot;Miss&amp;quot;,&lt;br /&gt;
        normalHit: &amp;quot;Normal Hit&amp;quot;,&lt;br /&gt;
        criticalHit: &amp;quot;Critical Hit&amp;quot;,&lt;br /&gt;
        piercingHit: &amp;quot;Piercing Hit&amp;quot;,&lt;br /&gt;
        criticalPiercingHit: &amp;quot;Critical Piercing Hit&amp;quot;,&lt;br /&gt;
        damagesRepartition: &amp;quot;Damage Repartition&amp;quot;,&lt;br /&gt;
        averageDamages: &amp;quot;Average Damage&amp;quot;,&lt;br /&gt;
        damagesAugmentation: &amp;quot;Damage Augmentation&amp;quot;,&lt;br /&gt;
        bonusVariationTitle: [&lt;br /&gt;
          &amp;quot;Evolution of Average Damage&amp;quot;,&lt;br /&gt;
          &amp;quot;Relative to a Bonus Value&amp;quot;,&lt;br /&gt;
        ],&lt;br /&gt;
      },&lt;br /&gt;
      tr: {&lt;br /&gt;
        damages: &amp;quot;Hasar&amp;quot;,&lt;br /&gt;
        percentage: &amp;quot;Yüzde&amp;quot;,&lt;br /&gt;
        miss: &amp;quot;Miss Vuruş&amp;quot;,&lt;br /&gt;
        normalHit: &amp;quot;Düz Vuruş&amp;quot;,&lt;br /&gt;
        criticalHit: &amp;quot;Kritik Vuruş&amp;quot;,&lt;br /&gt;
        piercingHit: &amp;quot;Delici Vuruş&amp;quot;,&lt;br /&gt;
        criticalPiercingHit: &amp;quot;Kritikli Delici Vuruş&amp;quot;,&lt;br /&gt;
        damagesRepartition: &amp;quot;Hasar Dağılımı&amp;quot;,&lt;br /&gt;
        averageDamages: &amp;quot;Ortalama Hasar&amp;quot;,&lt;br /&gt;
        damagesAugmentation: &amp;quot;Ortalama Hasar Artışı&amp;quot;,&lt;br /&gt;
        bonusVariationTitle: [&lt;br /&gt;
          &amp;quot;Bir bonusun değerine kıyasla&amp;quot;,&lt;br /&gt;
          &amp;quot;Ortalama Hasar Çizelgesi&amp;quot;,&lt;br /&gt;
        ],&lt;br /&gt;
      },&lt;br /&gt;
      ro: {&lt;br /&gt;
        damages: &amp;quot;Daune&amp;quot;,&lt;br /&gt;
        percentage: &amp;quot;Procent&amp;quot;,&lt;br /&gt;
        miss: &amp;quot;Miss&amp;quot;,&lt;br /&gt;
        normalHit: &amp;quot;Lovitura normala&amp;quot;,&lt;br /&gt;
        criticalHit: &amp;quot;Lovitura critica&amp;quot;,&lt;br /&gt;
        piercingHit: &amp;quot;Lovitura patrunzatoare&amp;quot;,&lt;br /&gt;
        criticalPiercingHit: &amp;quot;Lovitura critica si patrunzatoare&amp;quot;,&lt;br /&gt;
        damagesRepartition: &amp;quot;Distribuția daunelor&amp;quot;,&lt;br /&gt;
        averageDamages: &amp;quot;Media damageului&amp;quot;,&lt;br /&gt;
        damagesAugmentation: &amp;quot;Damage imbunatatit&amp;quot;,&lt;br /&gt;
        bonusVariationTitle: [&lt;br /&gt;
          &amp;quot;Evolutia mediei damageului&amp;quot;,&lt;br /&gt;
          &amp;quot;relativ la o valoare bonus&amp;quot;,&lt;br /&gt;
        ],&lt;br /&gt;
      },&lt;br /&gt;
      de: {&lt;br /&gt;
        damages: &amp;quot;Schäden&amp;quot;,&lt;br /&gt;
        percentage: &amp;quot;Prozentsatz&amp;quot;,&lt;br /&gt;
        miss: &amp;quot;Verfehlen&amp;quot;,&lt;br /&gt;
        normalHit: &amp;quot;Normaler Treffer&amp;quot;,&lt;br /&gt;
        criticalHit: &amp;quot;Kritischer Treffer&amp;quot;,&lt;br /&gt;
        piercingHit: &amp;quot;Durchdringender Treffer&amp;quot;,&lt;br /&gt;
        criticalPiercingHit: &amp;quot;Kritischer durchdringender Treffer&amp;quot;,&lt;br /&gt;
        damagesRepartition: &amp;quot;Schadensverteilung&amp;quot;,&lt;br /&gt;
        averageDamages: &amp;quot;Durchschnittlicher Schaden&amp;quot;,&lt;br /&gt;
        damagesAugmentation: &amp;quot;Schadenserhöhung&amp;quot;,&lt;br /&gt;
        bonusVariationTitle: [&lt;br /&gt;
          &amp;quot;Entwicklung des durchschnittlichen Schadens&amp;quot;,&lt;br /&gt;
          &amp;quot;im Verhältnis zu einem Bonus&amp;quot;,&lt;br /&gt;
        ],&lt;br /&gt;
      },&lt;br /&gt;
      pt: {&lt;br /&gt;
        damages: &amp;quot;Dano&amp;quot;,&lt;br /&gt;
        percentage: &amp;quot;Percentagem&amp;quot;,&lt;br /&gt;
        miss: &amp;quot;Miss&amp;quot;,&lt;br /&gt;
        normalHit: &amp;quot;Dano normal&amp;quot;,&lt;br /&gt;
        criticalHit: &amp;quot;Dano crítico&amp;quot;,&lt;br /&gt;
        piercingHit: &amp;quot;Dano perfurante&amp;quot;,&lt;br /&gt;
        criticalPiercingHit: &amp;quot;Dano crítico perfurante&amp;quot;,&lt;br /&gt;
        damagesRepartition: &amp;quot;Repartição de dano&amp;quot;,&lt;br /&gt;
        averageDamages: &amp;quot;Dano médio&amp;quot;,&lt;br /&gt;
        damagesAugmentation: &amp;quot;Aumento de dano&amp;quot;,&lt;br /&gt;
        bonusVariationTitle: [&amp;quot;Evolução do dano médio&amp;quot;, &amp;quot;relativo a um bónus&amp;quot;],&lt;br /&gt;
      },&lt;br /&gt;
      // es: {&lt;br /&gt;
      //   damages: &amp;quot;Daño&amp;quot;,&lt;br /&gt;
      //   percentage: &amp;quot;Porcentaje&amp;quot;,&lt;br /&gt;
      //   miss: &amp;quot;Miss&amp;quot;,&lt;br /&gt;
      //   normalHit: &amp;quot;Daño normal&amp;quot;,&lt;br /&gt;
      //   criticalHit: &amp;quot;Daño crítico&amp;quot;,&lt;br /&gt;
      //   piercingHit: &amp;quot;Daño perforante&amp;quot;,&lt;br /&gt;
      //   criticalPiercingHit: &amp;quot;Daño crítico perforante&amp;quot;,&lt;br /&gt;
      //   damagesRepartition: &amp;quot;Repartición de daños&amp;quot;,&lt;br /&gt;
      //   averageDamages: &amp;quot;Daño medio&amp;quot;,&lt;br /&gt;
      //   damagesAugmentation: &amp;quot;Aumento de daño&amp;quot;,&lt;br /&gt;
      //   bonusVariationTitle: [&amp;quot;Evolución del daño medio&amp;quot;, &amp;quot;Relativo a una bonificación&amp;quot;]&lt;br /&gt;
      // },&lt;br /&gt;
    },&lt;br /&gt;
  };&lt;br /&gt;
  return constants;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initResultTableHistory(battle) {&lt;br /&gt;
  var {&lt;br /&gt;
    tableResultHistory,&lt;br /&gt;
    savedFights,&lt;br /&gt;
    deleteFightTemplate,&lt;br /&gt;
    numberFormats: { default: numberFormat },&lt;br /&gt;
  } = battle;&lt;br /&gt;
  var startIndex = 3;&lt;br /&gt;
&lt;br /&gt;
  if (savedFights.length) {&lt;br /&gt;
    hideElement(tableResultHistory.rows[1]);&lt;br /&gt;
&lt;br /&gt;
    for (var savedFight of savedFights) {&lt;br /&gt;
      addRowToTableResultHistory(&lt;br /&gt;
        tableResultHistory,&lt;br /&gt;
        savedFight,&lt;br /&gt;
        deleteFightTemplate,&lt;br /&gt;
        numberFormat&lt;br /&gt;
      );&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  tableResultHistory.addEventListener(&amp;quot;click&amp;quot;, function (event) {&lt;br /&gt;
    var deleteButton = event.target.closest(&amp;quot;.svg-icon-delete&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
    if (deleteButton) {&lt;br /&gt;
      var row = deleteButton.closest(&amp;quot;tr&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
      if (row) {&lt;br /&gt;
        savedFights.splice(row.rowIndex - startIndex, 1);&lt;br /&gt;
        updateSavedFights(savedFights);&lt;br /&gt;
&lt;br /&gt;
        row.remove();&lt;br /&gt;
&lt;br /&gt;
        if (tableResultHistory.rows.length === startIndex) {&lt;br /&gt;
          showElement(tableResultHistory.rows[1]);&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initDamagesChart(battle) {&lt;br /&gt;
  var { translation, reduceChartPointsContainer, reduceChartPoints } = battle;&lt;br /&gt;
  var percentFormat = battle.numberFormats.percent;&lt;br /&gt;
  var customPlugins = {&lt;br /&gt;
    id: &amp;quot;customPlugins&amp;quot;,&lt;br /&gt;
    afterDraw(chart) {&lt;br /&gt;
      var missPercentage = chart.data.missPercentage;&lt;br /&gt;
&lt;br /&gt;
      if (!missPercentage) {&lt;br /&gt;
        return;&lt;br /&gt;
      }&lt;br /&gt;
&lt;br /&gt;
      var {&lt;br /&gt;
        ctx,&lt;br /&gt;
        chartArea: { top, right },&lt;br /&gt;
      } = chart;&lt;br /&gt;
      ctx.save();&lt;br /&gt;
      var text =&lt;br /&gt;
        translation.miss + &amp;quot; : &amp;quot; + percentFormat.format(missPercentage);&lt;br /&gt;
      var padding = 4;&lt;br /&gt;
      var fontSize = 14;&lt;br /&gt;
&lt;br /&gt;
      ctx.font = fontSize + &amp;quot;px Helvetica Neue&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
      var textWidth = ctx.measureText(text).width;&lt;br /&gt;
      var xPosition = right - textWidth - 5;&lt;br /&gt;
      var yPosition = top + 5;&lt;br /&gt;
&lt;br /&gt;
      ctx.fillStyle = &amp;quot;rgba(255, 0, 0, 0.2)&amp;quot;;&lt;br /&gt;
      ctx.fillRect(&lt;br /&gt;
        xPosition - padding,&lt;br /&gt;
        yPosition - padding,&lt;br /&gt;
        textWidth + 2 * padding,&lt;br /&gt;
        fontSize + 2 * padding&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      ctx.strokeStyle = &amp;quot;red&amp;quot;;&lt;br /&gt;
      ctx.strokeRect(&lt;br /&gt;
        xPosition - padding,&lt;br /&gt;
        yPosition - padding,&lt;br /&gt;
        textWidth + 2 * padding,&lt;br /&gt;
        fontSize + 2 * padding&lt;br /&gt;
      );&lt;br /&gt;
&lt;br /&gt;
      ctx.fillStyle = &amp;quot;#666&amp;quot;;&lt;br /&gt;
      ctx.textBaseline = &amp;quot;top&amp;quot;;&lt;br /&gt;
      ctx.fillText(text, xPosition, yPosition + 1);&lt;br /&gt;
&lt;br /&gt;
      ctx.restore();&lt;br /&gt;
    },&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  Chart.register(customPlugins);&lt;br /&gt;
&lt;br /&gt;
  var ctx = battle.plotDamages.getContext(&amp;quot;2d&amp;quot;);&lt;br /&gt;
  var maxLabelsInTooltip = 10;&lt;br /&gt;
  var nullLabelText = &amp;quot; ...&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  var chart = new Chart(ctx, {&lt;br /&gt;
    type: &amp;quot;scatter&amp;quot;,&lt;br /&gt;
    data: {&lt;br /&gt;
      missPercentage: 0,&lt;br /&gt;
      datasets: [],&lt;br /&gt;
    },&lt;br /&gt;
    options: {&lt;br /&gt;
      responsive: true,&lt;br /&gt;
      maintainAspectRatio: false,&lt;br /&gt;
      plugins: {&lt;br /&gt;
        legend: {&lt;br /&gt;
          display: true,&lt;br /&gt;
          onHover: function (e) {&lt;br /&gt;
            e.native.target.style.cursor = &amp;quot;pointer&amp;quot;;&lt;br /&gt;
          },&lt;br /&gt;
          onLeave: function (e) {&lt;br /&gt;
            e.native.target.style.cursor = &amp;quot;default&amp;quot;;&lt;br /&gt;
          },&lt;br /&gt;
          onClick: function (e, legendItem, legend) {&lt;br /&gt;
            var currentIndex = legendItem.datasetIndex;&lt;br /&gt;
            var ci = legend.chart;&lt;br /&gt;
            var isCurrentDatasetVisible = ci.isDatasetVisible(currentIndex);&lt;br /&gt;
            var datasets = ci.data.datasets;&lt;br /&gt;
            var hideReducePoints = true;&lt;br /&gt;
            var isReducePointsChecked = reduceChartPoints.checked;&lt;br /&gt;
&lt;br /&gt;
            datasets[currentIndex].hidden = isCurrentDatasetVisible;&lt;br /&gt;
            legendItem.hidden = isCurrentDatasetVisible;&lt;br /&gt;
&lt;br /&gt;
            for (var index in datasets) {&lt;br /&gt;
              if (ci.isDatasetVisible(index) &amp;amp;&amp;amp; datasets[index].canBeReduced) {&lt;br /&gt;
                showElement(reduceChartPointsContainer);&lt;br /&gt;
                hideReducePoints = false;&lt;br /&gt;
                break;&lt;br /&gt;
              }&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            if (hideReducePoints) {&lt;br /&gt;
              hideElement(reduceChartPointsContainer);&lt;br /&gt;
              handleChartAnimations(ci, true);&lt;br /&gt;
            } else {&lt;br /&gt;
              handleChartAnimations(ci, isReducePointsChecked);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            ci.update();&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        title: {&lt;br /&gt;
          display: true,&lt;br /&gt;
          text: translation.damagesRepartition,&lt;br /&gt;
          font: {&lt;br /&gt;
            size: 20,&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        tooltip: {&lt;br /&gt;
          callbacks: {&lt;br /&gt;
            label: function (context) {&lt;br /&gt;
              if (context.label === null) {&lt;br /&gt;
                return nullLabelText;&lt;br /&gt;
              }&lt;br /&gt;
&lt;br /&gt;
              var xValue = battle.numberFormats.default.format(&lt;br /&gt;
                context.parsed.x&lt;br /&gt;
              );&lt;br /&gt;
              var yValue = battle.numberFormats.percent.format(&lt;br /&gt;
                context.parsed.y&lt;br /&gt;
              );&lt;br /&gt;
&lt;br /&gt;
              label =&lt;br /&gt;
                &amp;quot; &amp;quot; +&lt;br /&gt;
                context.dataset.label +&lt;br /&gt;
                &amp;quot; : (&amp;quot; +&lt;br /&gt;
                xValue +&lt;br /&gt;
                &amp;quot;, &amp;quot; +&lt;br /&gt;
                yValue +&lt;br /&gt;
                &amp;quot;)&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
              return label;&lt;br /&gt;
            },&lt;br /&gt;
            beforeBody: function (tooltipItems) {&lt;br /&gt;
              if (tooltipItems.length &amp;gt; maxLabelsInTooltip + 1) {&lt;br /&gt;
                tooltipItems.splice(maxLabelsInTooltip + 1);&lt;br /&gt;
                tooltipItems[maxLabelsInTooltip].label = null;&lt;br /&gt;
              }&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          caretPadding: 10,&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
      scales: {&lt;br /&gt;
        x: {&lt;br /&gt;
          type: &amp;quot;linear&amp;quot;,&lt;br /&gt;
          position: &amp;quot;bottom&amp;quot;,&lt;br /&gt;
          title: {&lt;br /&gt;
            display: true,&lt;br /&gt;
            text: translation.damages,&lt;br /&gt;
            font: {&lt;br /&gt;
              size: 16,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        y: {&lt;br /&gt;
          title: {&lt;br /&gt;
            display: true,&lt;br /&gt;
            text: translation.percentage,&lt;br /&gt;
            font: {&lt;br /&gt;
              size: 16,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          ticks: {&lt;br /&gt;
            format: {&lt;br /&gt;
              style: &amp;quot;percent&amp;quot;,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
      elements: {&lt;br /&gt;
        point: {&lt;br /&gt;
          borderWidth: 1,&lt;br /&gt;
          radius: 3,&lt;br /&gt;
          hitRadius: 3,&lt;br /&gt;
          hoverRadius: 6,&lt;br /&gt;
          hoverBorderWidth: 2,&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
    },&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  var datasetsStyle = [&lt;br /&gt;
    {&lt;br /&gt;
      name: &amp;quot;normalHit&amp;quot;,&lt;br /&gt;
      canBeReduced: false,&lt;br /&gt;
      label: translation.normalHit,&lt;br /&gt;
      backgroundColor: &amp;quot;rgba(75, 192, 192, 0.2)&amp;quot;,&lt;br /&gt;
      borderColor: &amp;quot;rgba(75, 192, 192, 1)&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      name: &amp;quot;piercingHit&amp;quot;,&lt;br /&gt;
      canBeReduced: false,&lt;br /&gt;
      label: translation.piercingHit,&lt;br /&gt;
      backgroundColor: &amp;quot;rgba(192, 192, 75, 0.2)&amp;quot;,&lt;br /&gt;
      borderColor: &amp;quot;rgba(192, 192, 75, 1)&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      name: &amp;quot;criticalHit&amp;quot;,&lt;br /&gt;
      canBeReduced: false,&lt;br /&gt;
      label: translation.criticalHit,&lt;br /&gt;
      backgroundColor: &amp;quot;rgba(192, 75, 192, 0.2)&amp;quot;,&lt;br /&gt;
      borderColor: &amp;quot;rgba(192, 75, 192, 1)&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
    {&lt;br /&gt;
      name: &amp;quot;criticalPiercingHit&amp;quot;,&lt;br /&gt;
      canBeReduced: false,&lt;br /&gt;
      label: translation.criticalPiercingHit,&lt;br /&gt;
      backgroundColor: &amp;quot;rgba(75, 75, 192, 0.2)&amp;quot;,&lt;br /&gt;
      borderColor: &amp;quot;rgba(75, 75, 192, 1)&amp;quot;,&lt;br /&gt;
    },&lt;br /&gt;
  ];&lt;br /&gt;
  battle.damagesChart = {&lt;br /&gt;
    chart: chart,&lt;br /&gt;
    datasetsStyle: datasetsStyle,&lt;br /&gt;
    maxPoints: 500,&lt;br /&gt;
    reduceChartPointsContainer: reduceChartPointsContainer,&lt;br /&gt;
  };&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function initBonusVariationChart(battle) {&lt;br /&gt;
  var translation = battle.translation;&lt;br /&gt;
&lt;br /&gt;
  var ctx = battle.plotBonusVariation.getContext(&amp;quot;2d&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  var chart = new Chart(ctx, {&lt;br /&gt;
    type: &amp;quot;line&amp;quot;,&lt;br /&gt;
    data: {&lt;br /&gt;
      datasets: [&lt;br /&gt;
        {&lt;br /&gt;
          label: translation.averageDamages,&lt;br /&gt;
          backgroundColor: &amp;quot;rgba(75, 192, 192, 0.2)&amp;quot;,&lt;br /&gt;
          borderColor: &amp;quot;rgba(75, 192, 192, 1)&amp;quot;,&lt;br /&gt;
          fill: true,&lt;br /&gt;
        },&lt;br /&gt;
        {&lt;br /&gt;
          label: translation.damagesAugmentation,&lt;br /&gt;
          backgroundColor: &amp;quot;rgba(192, 192, 75, 0.2)&amp;quot;,&lt;br /&gt;
          borderColor: &amp;quot;rgba(192, 192, 75, 1)&amp;quot;,&lt;br /&gt;
          hidden: true,&lt;br /&gt;
          yTicksFormat: { style: &amp;quot;percent&amp;quot; },&lt;br /&gt;
          fill: true,&lt;br /&gt;
        },&lt;br /&gt;
      ],&lt;br /&gt;
    },&lt;br /&gt;
    options: {&lt;br /&gt;
      responsive: true,&lt;br /&gt;
      maintainAspectRatio: false,&lt;br /&gt;
      plugins: {&lt;br /&gt;
        legend: {&lt;br /&gt;
          display: true,&lt;br /&gt;
          onHover: function (e) {&lt;br /&gt;
            e.native.target.style.cursor = &amp;quot;pointer&amp;quot;;&lt;br /&gt;
          },&lt;br /&gt;
          onLeave: function (e) {&lt;br /&gt;
            e.native.target.style.cursor = &amp;quot;default&amp;quot;;&lt;br /&gt;
          },&lt;br /&gt;
          onClick: function (e, legendItem, legend) {&lt;br /&gt;
            var currentIndex = legendItem.datasetIndex;&lt;br /&gt;
            var ci = legend.chart;&lt;br /&gt;
            var datasets = ci.data.datasets;&lt;br /&gt;
            var isCurrentDatasetVisible = ci.isDatasetVisible(currentIndex);&lt;br /&gt;
            var yAxis = ci.options.scales.y;&lt;br /&gt;
&lt;br /&gt;
            var otherIndex = currentIndex === 0 ? 1 : 0;&lt;br /&gt;
            var visibleDataset = isCurrentDatasetVisible&lt;br /&gt;
              ? datasets[otherIndex]&lt;br /&gt;
              : datasets[currentIndex];&lt;br /&gt;
&lt;br /&gt;
            datasets[currentIndex].hidden = isCurrentDatasetVisible;&lt;br /&gt;
            datasets[otherIndex].hidden = !isCurrentDatasetVisible;&lt;br /&gt;
&lt;br /&gt;
            yAxis.title.text = visibleDataset.label;&lt;br /&gt;
            yAxis.ticks.format = visibleDataset.yTicksFormat;&lt;br /&gt;
&lt;br /&gt;
            ci.update();&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        title: {&lt;br /&gt;
          display: true,&lt;br /&gt;
          text: translation.bonusVariationTitle,&lt;br /&gt;
          font: {&lt;br /&gt;
            size: 18,&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        tooltip: {&lt;br /&gt;
          caretPadding: 10,&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
      scales: {&lt;br /&gt;
        x: {&lt;br /&gt;
          type: &amp;quot;linear&amp;quot;,&lt;br /&gt;
          position: &amp;quot;bottom&amp;quot;,&lt;br /&gt;
          title: {&lt;br /&gt;
            display: true,&lt;br /&gt;
            text: &amp;quot;Bonus&amp;quot;,&lt;br /&gt;
            font: {&lt;br /&gt;
              size: 16,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
          ticks: {&lt;br /&gt;
            callback: function (value) {&lt;br /&gt;
              if (Number.isInteger(value)) {&lt;br /&gt;
                return Number(value);&lt;br /&gt;
              }&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
        y: {&lt;br /&gt;
          title: {&lt;br /&gt;
            display: true,&lt;br /&gt;
            text: translation.averageDamages,&lt;br /&gt;
            font: {&lt;br /&gt;
              size: 16,&lt;br /&gt;
            },&lt;br /&gt;
          },&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
      elements: {&lt;br /&gt;
        point: {&lt;br /&gt;
          borderWidth: 1,&lt;br /&gt;
          radius: 3,&lt;br /&gt;
          hitRadius: 3,&lt;br /&gt;
          hoverRadius: 6,&lt;br /&gt;
          hoverBorderWidth: 2,&lt;br /&gt;
        },&lt;br /&gt;
      },&lt;br /&gt;
    },&lt;br /&gt;
  });&lt;br /&gt;
&lt;br /&gt;
  battle.bonusVariationChart = chart;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function attackSelectonListener(&lt;br /&gt;
  characters,&lt;br /&gt;
  attackerSelection,&lt;br /&gt;
  attackTypeSelection&lt;br /&gt;
) {&lt;br /&gt;
  attackerSelection.addEventListener(&amp;quot;change&amp;quot;, function (event) {&lt;br /&gt;
    var attackerName = event.target.value;&lt;br /&gt;
&lt;br /&gt;
    if (isPseudoSaved(characters, attackerName)) {&lt;br /&gt;
      var attacker = characters.savedCharacters[attackerName];&lt;br /&gt;
      filterAttackTypeSelection(attacker, attackTypeSelection);&lt;br /&gt;
    } else {&lt;br /&gt;
      filterAttackTypeSelectionMonster(attackTypeSelection);&lt;br /&gt;
    }&lt;br /&gt;
  });&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function getTranslation(translation) {&lt;br /&gt;
  var userLanguage = navigator.language;&lt;br /&gt;
  var langToUse = &amp;quot;en&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  for (var lang in translation) {&lt;br /&gt;
    if (userLanguage.startsWith(lang)) {&lt;br /&gt;
      langToUse = lang;&lt;br /&gt;
      break;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return translation[langToUse];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function createDamageCalculatorInformation(chartSource) {&lt;br /&gt;
  var characters = {&lt;br /&gt;
    unsavedChanges: false,&lt;br /&gt;
    savedCharacters: {},&lt;br /&gt;
    currentCharacter: null,&lt;br /&gt;
    savedMonsters: getSavedMonsters(),&lt;br /&gt;
    characterCreation: document.getElementById(&amp;quot;character-creation&amp;quot;),&lt;br /&gt;
    addNewCharacterButton: document.getElementById(&amp;quot;add-new-character&amp;quot;),&lt;br /&gt;
    dropZone: document.getElementById(&amp;quot;character-drop-zone&amp;quot;),&lt;br /&gt;
    characterInput: document.getElementById(&amp;quot;character-input&amp;quot;),&lt;br /&gt;
    newCharacterTemplate: document.getElementById(&amp;quot;new-character-template&amp;quot;)&lt;br /&gt;
      .children[0],&lt;br /&gt;
    charactersContainer: document.getElementById(&amp;quot;characters-container&amp;quot;),&lt;br /&gt;
    newMonsterTemplate: document.getElementById(&amp;quot;new-monster-template&amp;quot;)&lt;br /&gt;
      .children[0],&lt;br /&gt;
    monstersContainer: document.getElementById(&amp;quot;monsters-container&amp;quot;),&lt;br /&gt;
    monsterListForm: document.getElementById(&amp;quot;monster-list-form&amp;quot;),&lt;br /&gt;
    searchMonster: document.getElementById(&amp;quot;search-monster&amp;quot;),&lt;br /&gt;
    monsterList: document.getElementById(&amp;quot;monster-list&amp;quot;),&lt;br /&gt;
    saveButton: document.getElementById(&amp;quot;save-character&amp;quot;),&lt;br /&gt;
    weaponCategory: document.getElementById(&amp;quot;weapon-category&amp;quot;),&lt;br /&gt;
    weaponDisplay: document.getElementById(&amp;quot;weapon-display&amp;quot;),&lt;br /&gt;
    randomAttackValue: document.getElementById(&amp;quot;random-attack-value&amp;quot;),&lt;br /&gt;
    randomMagicAttackValue: document.getElementById(&lt;br /&gt;
      &amp;quot;random-magic-attack-value&amp;quot;&lt;br /&gt;
    ),&lt;br /&gt;
    yoharaCreation: document.getElementById(&amp;quot;yohara-creation&amp;quot;),&lt;br /&gt;
    blessingCreation: document.getElementById(&amp;quot;blessing-creation&amp;quot;),&lt;br /&gt;
    marriageCreation: document.getElementById(&amp;quot;marriage-creation&amp;quot;),&lt;br /&gt;
    bonusVariation: {&lt;br /&gt;
      tab: document.getElementById(&amp;quot;Variation&amp;quot;),&lt;br /&gt;
      activation: document.getElementById(&amp;quot;bonus-variation-activation&amp;quot;),&lt;br /&gt;
      input: document.getElementById(&amp;quot;bonus-variation&amp;quot;),&lt;br /&gt;
      inputDisplay: document.getElementById(&amp;quot;bonus-variation-display&amp;quot;),&lt;br /&gt;
      container: document.getElementById(&amp;quot;bonus-variation-range&amp;quot;),&lt;br /&gt;
      minValue: document.getElementById(&amp;quot;bonus-variation-min-value&amp;quot;),&lt;br /&gt;
      maxValue: document.getElementById(&amp;quot;bonus-variation-max-value&amp;quot;),&lt;br /&gt;
    },&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  characters.bonusVariation.inputDisplay.setAttribute(&amp;quot;readonly&amp;quot;, &amp;quot;&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  for (var [pseudo, character] of Object.entries(getSavedCharacters())) {&lt;br /&gt;
    characters.savedCharacters[pseudo] = character;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  var skillContainer = document.getElementById(&amp;quot;skill-container&amp;quot;);&lt;br /&gt;
  characters.skillElementsToFilter =&lt;br /&gt;
    skillContainer.querySelectorAll(&amp;quot;[data-class]&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  var mapping = createMapping();&lt;br /&gt;
  var constants = createConstants();&lt;br /&gt;
&lt;br /&gt;
  var battle = {&lt;br /&gt;
    resetAttackType: false,&lt;br /&gt;
    savedFights: getSavedFights(),&lt;br /&gt;
    battleForm: document.getElementById(&amp;quot;create-battle&amp;quot;),&lt;br /&gt;
    attackerSelection: document.getElementById(&amp;quot;attacker-selection&amp;quot;),&lt;br /&gt;
    attackTypeSelection: document.getElementById(&amp;quot;attack-type-selection&amp;quot;),&lt;br /&gt;
    victimSelection: document.getElementById(&amp;quot;victim-selection&amp;quot;),&lt;br /&gt;
    damagesWeightedByType: {},&lt;br /&gt;
    scatterDataByType: {},&lt;br /&gt;
    damagesByBonus: [],&lt;br /&gt;
    tableResultFight: document.getElementById(&amp;quot;result-table-fight&amp;quot;),&lt;br /&gt;
    tableResultHistory: document.getElementById(&amp;quot;result-table-history&amp;quot;),&lt;br /&gt;
    deleteFightTemplate: document.getElementById(&amp;quot;delete-fight-template&amp;quot;)&lt;br /&gt;
      .children[0],&lt;br /&gt;
    errorInformation: {},&lt;br /&gt;
    fightResultContainer: document.getElementById(&amp;quot;fight-result-container&amp;quot;),&lt;br /&gt;
    downLoadRawData: document.getElementById(&amp;quot;download-raw-data&amp;quot;),&lt;br /&gt;
    downLoadRawDataVariation: document.getElementById(&lt;br /&gt;
      &amp;quot;download-raw-data-variation&amp;quot;&lt;br /&gt;
    ),&lt;br /&gt;
    bonusVariationResultContainer: document.getElementById(&lt;br /&gt;
      &amp;quot;bonus-variation-result-container&amp;quot;&lt;br /&gt;
    ),&lt;br /&gt;
    reduceChartPointsContainer: document.getElementById(&lt;br /&gt;
      &amp;quot;reduce-chart-points-container&amp;quot;&lt;br /&gt;
    ),&lt;br /&gt;
    reduceChartPoints: document.getElementById(&amp;quot;reduce-chart-points&amp;quot;),&lt;br /&gt;
    plotDamages: document.getElementById(&amp;quot;plot-damages&amp;quot;),&lt;br /&gt;
    plotBonusVariation: document.getElementById(&amp;quot;plot-bonus-variation&amp;quot;),&lt;br /&gt;
    uniqueDamagesCounters: document.querySelectorAll(&amp;quot;.unique-damages-counter&amp;quot;),&lt;br /&gt;
    possibleDamagesCounter: document.getElementById(&amp;quot;possible-damages-counter&amp;quot;),&lt;br /&gt;
    damagesTime: document.getElementById(&amp;quot;damages-time&amp;quot;),&lt;br /&gt;
    displayTime: document.getElementById(&amp;quot;display-time&amp;quot;),&lt;br /&gt;
    simulationCounter: document.getElementById(&amp;quot;simulation-counter&amp;quot;),&lt;br /&gt;
    simulationTime: document.getElementById(&amp;quot;simulation-time&amp;quot;),&lt;br /&gt;
    numberFormats: {&lt;br /&gt;
      default: new Intl.NumberFormat(undefined, {&lt;br /&gt;
        minimumFractionDigits: 0,&lt;br /&gt;
        maximumFractionDigits: 1,&lt;br /&gt;
      }),&lt;br /&gt;
      percent: new Intl.NumberFormat(undefined, {&lt;br /&gt;
        style: &amp;quot;percent&amp;quot;,&lt;br /&gt;
        maximumFractionDigits: 3,&lt;br /&gt;
      }),&lt;br /&gt;
      second: new Intl.NumberFormat(undefined, {&lt;br /&gt;
        style: &amp;quot;unit&amp;quot;,&lt;br /&gt;
        unit: &amp;quot;second&amp;quot;,&lt;br /&gt;
        unitDisplay: &amp;quot;long&amp;quot;,&lt;br /&gt;
        maximumFractionDigits: 3,&lt;br /&gt;
      }),&lt;br /&gt;
    },&lt;br /&gt;
    mapping: mapping,&lt;br /&gt;
    constants: constants,&lt;br /&gt;
    translation: getTranslation(constants.translation),&lt;br /&gt;
  };&lt;br /&gt;
&lt;br /&gt;
  attackSelectonListener(&lt;br /&gt;
    characters,&lt;br /&gt;
    battle.attackerSelection,&lt;br /&gt;
    battle.attackTypeSelection&lt;br /&gt;
  );&lt;br /&gt;
  initResultTableHistory(battle);&lt;br /&gt;
  loadScript(chartSource, function () {&lt;br /&gt;
    initDamagesChart(battle);&lt;br /&gt;
    initBonusVariationChart(battle);&lt;br /&gt;
  });&lt;br /&gt;
  reduceChartPointsListener(battle);&lt;br /&gt;
  downloadRawDataListener(battle);&lt;br /&gt;
&lt;br /&gt;
  var errorElements = document.querySelectorAll(&amp;quot;[data-error]&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  for (var index = 0; index &amp;lt; errorElements.length; index++) {&lt;br /&gt;
    var errorElement = errorElements[index];&lt;br /&gt;
    battle.errorInformation[errorElement.dataset.error] = errorElement;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  return [characters, battle];&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadScript(src, callback) {&lt;br /&gt;
  var script = document.createElement(&amp;quot;script&amp;quot;);&lt;br /&gt;
  script.src = src;&lt;br /&gt;
&lt;br /&gt;
  function onComplete() {&lt;br /&gt;
    if (script.parentNode) {&lt;br /&gt;
      script.parentNode.removeChild(script);&lt;br /&gt;
    }&lt;br /&gt;
    if (callback) {&lt;br /&gt;
      callback();&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  document.head.appendChild(script);&lt;br /&gt;
&lt;br /&gt;
  script.onload = onComplete;&lt;br /&gt;
  script.onerror = onComplete;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loadStyle(src) {&lt;br /&gt;
  var link = document.createElement(&amp;quot;link&amp;quot;);&lt;br /&gt;
  link.href = src;&lt;br /&gt;
  link.rel = &amp;quot;stylesheet&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  document.head.appendChild(link);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function loading() {&lt;br /&gt;
  var mainContainer = document.getElementById(&amp;quot;hide-all&amp;quot;);&lt;br /&gt;
  var loadingAnimation = document.getElementById(&amp;quot;loading-animation&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
  mainContainer.classList.remove(&amp;quot;tabber-noactive&amp;quot;);&lt;br /&gt;
  loadingAnimation.classList.add(&amp;quot;tabber-noactive&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
(function () {&lt;br /&gt;
  var javascriptSource =&lt;br /&gt;
    &amp;quot;/index.php?title=Utilisateur:Ankhseram/Calculator.js&amp;amp;action=raw&amp;amp;ctype=text/javascript&amp;quot;;&lt;br /&gt;
  var cssSource =&lt;br /&gt;
    &amp;quot;/index.php?title=Utilisateur:Ankhseram/Style.css&amp;amp;action=raw&amp;amp;ctype=text/css&amp;quot;;&lt;br /&gt;
  var chartSource = &amp;quot;https://cdn.jsdelivr.net/npm/chart.js&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
  loadStyle(cssSource);&lt;br /&gt;
&lt;br /&gt;
  function main() {&lt;br /&gt;
    var [characters, battle] = createDamageCalculatorInformation(chartSource);&lt;br /&gt;
&lt;br /&gt;
    characterManagement(characters, battle);&lt;br /&gt;
    monsterManagement(characters, battle);&lt;br /&gt;
&lt;br /&gt;
    updateBattleChoice(characters, battle);&lt;br /&gt;
    createBattle(characters, battle);&lt;br /&gt;
&lt;br /&gt;
    loading();&lt;br /&gt;
  }&lt;br /&gt;
  loadScript(javascriptSource, main);&lt;br /&gt;
})();&lt;/div&gt;</summary>
		<author><name>Dexter</name></author>
		
	</entry>
	<entry>
		<id>https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Common.css&amp;diff=105254</id>
		<title>MediaWiki:Common.css</title>
		<link rel="alternate" type="text/html" href="https://fr-wiki.metin2.gameforge.com/index.php?title=MediaWiki:Common.css&amp;diff=105254"/>
		<updated>2024-11-20T16:06:00Z</updated>

		<summary type="html">&lt;p&gt;Dexter : &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;/* Le CSS placé ici sera chargé sur toutes les pages */&lt;br /&gt;
&lt;br /&gt;
html {&lt;br /&gt;
  scroll-behavior: smooth;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/*&lt;br /&gt;
body {&lt;br /&gt;
  background-image: url('https://fr-wiki.metin2.gameforge.com/images/b/bf/Fondhalloween.png');&lt;br /&gt;
}&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
body {&lt;br /&gt;
  background-image: url('https://fr-wiki.metin2.gameforge.com/images/1/15/Fond2015.jpg');&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#mw-content ul {&lt;br /&gt;
    margin-bottom: 0.3em;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#mw-content ol {&lt;br /&gt;
  list-style: none;&lt;br /&gt;
  counter-reset: custom-counter;&lt;br /&gt;
  margin: 0.3em 0 0.3em 1.6em;&lt;br /&gt;
  padding: 0;&lt;br /&gt;
}&lt;br /&gt;
ol li {&lt;br /&gt;
  padding: 0;&lt;br /&gt;
  counter-increment: custom-counter;&lt;br /&gt;
}&lt;br /&gt;
ol li::marker {&lt;br /&gt;
  content: counter(custom-counter) &amp;quot;.  &amp;quot;;&lt;br /&gt;
  font-weight: bold;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
td, th {&lt;br /&gt;
  padding: 2px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.map span.mw-collapsible-toggle {&lt;br /&gt;
  padding-right: 10px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
table.map a.mw-collapsible-text,&lt;br /&gt;
.prettytable &amp;gt; span.mw-collapsible-toggle,&lt;br /&gt;
.prettytable &amp;gt; span.mw-collapsible-toggle &amp;gt; a {&lt;br /&gt;
  color: #ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.boxesheaderbackground, .cadre &amp;gt; div:first-child {&lt;br /&gt;
  background: repeat url(&amp;quot;https://fr-wiki.metin2.gameforge.com/images/a/a7/Boxheaderbrown.png&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.cadre {&lt;br /&gt;
  border: 1px solid #2f1d1f;&lt;br /&gt;
  border-radius: 15px 0;&lt;br /&gt;
  width: 100%;&lt;br /&gt;
  box-shadow: 3px 3px 9px 0px #544e41;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.cadre &amp;gt; div:first-child {&lt;br /&gt;
  text-align: center;&lt;br /&gt;
  color: white;&lt;br /&gt;
  line-height: 25px;&lt;br /&gt;
  overflow: hidden;&lt;br /&gt;
  border-top-left-radius: 15px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.fondfenetre,&lt;br /&gt;
.sous-titre,&lt;br /&gt;
table.pretty-table th { &lt;br /&gt;
  background: url(&amp;quot;https://fr-wiki.metin2.gameforge.com/images/8/89/Fondfenetre.png&amp;quot;) repeat;&lt;br /&gt;
  color: white;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
table.pretty-table td {&lt;br /&gt;
  padding: 5px 10px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
table.pretty-table th {&lt;br /&gt;
  padding: 2px 10px;&lt;br /&gt;
  font-weight: normal;&lt;br /&gt;
  font-size: 1.1em;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
table.pretty-table tbody &amp;gt; *:nth-child(2n+1) &amp;gt; td {&lt;br /&gt;
  background: rgba(0, 0, 0, .1);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
table.pretty-table tr:hover {&lt;br /&gt;
  background: rgba(0, 0, 0, .05);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
table.pretty-table tr:first-child &amp;gt; th:first-child {&lt;br /&gt;
  border-radius: 8px 0 0 0;&lt;br /&gt;
  overflow: hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
table.pretty-table caption {&lt;br /&gt;
  margin-top: 10px;&lt;br /&gt;
  font-weight: bold;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.fondfenetre a,&lt;br /&gt;
.fondfenetre span,&lt;br /&gt;
table.pretty-table th a,&lt;br /&gt;
table.pretty-table th span {&lt;br /&gt;
  color: white;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
table.sticky-header-row thead tr {&lt;br /&gt;
  position: sticky;&lt;br /&gt;
  top: 0;&lt;br /&gt;
  z-index: 10;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
table.sticky-header-column th:first-child {&lt;br /&gt;
  position: sticky;&lt;br /&gt;
  left: 0;&lt;br /&gt;
  z-index: 20;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.sous-titre {&lt;br /&gt;
  max-width: 180px;&lt;br /&gt;
  border: 1px solid black;&lt;br /&gt;
  border-radius: 8px;&lt;br /&gt;
  color: white;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.modeleAnnonce {&lt;br /&gt;
  border-image: url(&amp;quot;https://fr-wiki.metin2.gameforge.com/images/f/fb/Modeleannonce.png&amp;quot;) 17 35 3 fill / auto / 0 repeat;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.container { &lt;br /&gt;
 display: flex;&lt;br /&gt;
 flex-direction: row; &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.monster-card { &lt;br /&gt;
 border: 1px black solid;&lt;br /&gt;
 padding: 5px;&lt;br /&gt;
 max-width: 400px;&lt;br /&gt;
 box-sizing: border-box;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.monster-card &amp;gt; :first-child {&lt;br /&gt;
 display: flex;&lt;br /&gt;
 justify-content: space-between;&lt;br /&gt;
 margin-bottom: 5px;&lt;br /&gt;
 line-height: 25px;&lt;br /&gt;
 padding: 0 5px;&lt;br /&gt;
 background: none;&lt;br /&gt;
 background-color: black;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.button {&lt;br /&gt;
  border: 2px solid grey;&lt;br /&gt;
  padding: 0 12px;&lt;br /&gt;
  line-height: 25px;&lt;br /&gt;
  border-radius: 16px;&lt;br /&gt;
  background: rgba(234, 234, 234);&lt;br /&gt;
  cursor: pointer;&lt;br /&gt;
  display: inline-block;&lt;br /&gt;
  position: relative;&lt;br /&gt;
  user-select: none;&lt;br /&gt;
  white-space: nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.button:hover {&lt;br /&gt;
  background: transparent;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.modal {&lt;br /&gt;
  background-color: rgba(0, 0, 0, 0.5);&lt;br /&gt;
  display: none;&lt;br /&gt;
  height: 100%;&lt;br /&gt;
  left: 0;&lt;br /&gt;
  position: fixed;&lt;br /&gt;
  top: 0;&lt;br /&gt;
  width: 100%;&lt;br /&gt;
  z-index: 99;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.modal-content {&lt;br /&gt;
  background: url(&amp;quot;https://fr-wiki.metin2.gameforge.com/images/e/ed/Modalbackground.png&amp;quot;);&lt;br /&gt;
  border: 1px solid black;&lt;br /&gt;
  border-radius: 8px;&lt;br /&gt;
  left: 50%;&lt;br /&gt;
  padding: 30px 24px;&lt;br /&gt;
  position: fixed;&lt;br /&gt;
  top: 50%;&lt;br /&gt;
  transform: translate(-50%,-50%);&lt;br /&gt;
  width: auto;&lt;br /&gt;
  max-height: 80%;&lt;br /&gt;
  overflow-y: scroll;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.close {&lt;br /&gt;
  color: #000000;&lt;br /&gt;
  cursor: pointer;&lt;br /&gt;
  font-size: 20px;&lt;br /&gt;
  padding: 6px 12px;&lt;br /&gt;
  position: absolute;&lt;br /&gt;
  right: 0;&lt;br /&gt;
  top: 0;&lt;br /&gt;
  transition: color .2s linear, background-color .2s linear;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.close:hover {&lt;br /&gt;
  background: red;&lt;br /&gt;
  color: #ffffff;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.cacheOrdi,&lt;br /&gt;
.gen-active {&lt;br /&gt;
  display: block;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.texte-long,&lt;br /&gt;
.texte-long-2 {&lt;br /&gt;
  text-overflow: ellipsis;&lt;br /&gt;
  white-space: nowrap;&lt;br /&gt;
  overflow: hidden;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.texte-long:hover,&lt;br /&gt;
.texte-long-2:hover {&lt;br /&gt;
  white-space: normal;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.shop-img img {&lt;br /&gt;
    height: auto;&lt;br /&gt;
    width: auto;&lt;br /&gt;
    max-height: 130px;&lt;br /&gt;
    max-width: 130px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#mw-content .soulignement &amp;gt; a:link {&lt;br /&gt;
  text-decoration: none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.popContenu {&lt;br /&gt;
  display: inline-block;&lt;br /&gt;
  transition: all 0.4s ease;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.popInfo:hover .popContenu {&lt;br /&gt;
  opacity: 1 !important;&lt;br /&gt;
  transition: all 0.4s ease;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.cadreFenetre {&lt;br /&gt;
  border: solid;&lt;br /&gt;
  border-image: url(&amp;quot;https://fr-wiki.metin2.gameforge.com/images/1/11/Cadrefenetre.png&amp;quot;) 11 fill / auto / 0 repeat;&lt;br /&gt;
  padding: 10px;&lt;br /&gt;
  backdrop-filter: blur(4px);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tabber-active.button {&lt;br /&gt;
  background: rgba(75, 85, 95);&lt;br /&gt;
  color: white;&lt;br /&gt;
  border: 2px solid rgba(75, 85, 95);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
ul.subpage {&lt;br /&gt;
  display: flex;&lt;br /&gt;
  list-style: none;&lt;br /&gt;
  margin: 0 0 10px;&lt;br /&gt;
  padding: 0;&lt;br /&gt;
  background: rgba(81,36,16, 0.3);&lt;br /&gt;
  overflow: hidden;&lt;br /&gt;
  line-height: 30px;&lt;br /&gt;
  white-space: nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.subpage a {&lt;br /&gt;
  padding-left: 20px;&lt;br /&gt;
  background: #512410;&lt;br /&gt;
  display: inline-block;&lt;br /&gt;
  line-height: 30px;&lt;br /&gt;
  position: relative;&lt;br /&gt;
  color: #f1de8e;&lt;br /&gt;
  cursor: pointer;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.subpage a:before,&lt;br /&gt;
.subpage a:after { &lt;br /&gt;
  content: &amp;quot;&amp;quot;;&lt;br /&gt;
  position: absolute;&lt;br /&gt;
  width: 0;&lt;br /&gt;
  height: 0;&lt;br /&gt;
  right: 0;&lt;br /&gt;
  padding: 1px 0;&lt;br /&gt;
  border-top: 14px solid transparent;&lt;br /&gt;
  border-bottom: 14px solid transparent;&lt;br /&gt;
  border-left: 14px solid white;&lt;br /&gt;
  transform: translate(14px);&lt;br /&gt;
  z-index: 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.subpage a:after {&lt;br /&gt;
  border-left: 14px solid #512410;&lt;br /&gt;
  transform: translate(13px);&lt;br /&gt;
  z-index: 2;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.subpage &amp;gt; li:last-child {&lt;br /&gt;
  padding-left: 20px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
ul.subpage &amp;gt; li:first-child {&lt;br /&gt;
  flex-shrink: 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
ul.subpage &amp;gt; li:first-child &amp;gt; a {&lt;br /&gt;
  height: 100%;&lt;br /&gt;
  display: flex;&lt;br /&gt;
  align-items: center;&lt;br /&gt;
  padding-left: 10px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
ul.subpage &amp;gt; li &amp;gt; a:hover {&lt;br /&gt;
  background: #9D5B37;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
ul.subpage &amp;gt; li &amp;gt; a:hover:after {&lt;br /&gt;
  border-left-color: #9D5B37; &lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.image-sizing img,&lt;br /&gt;
.image-sizing-200 img,&lt;br /&gt;
.image-sizing-none img {&lt;br /&gt;
  height: auto;&lt;br /&gt;
  width: auto;&lt;br /&gt;
  max-height: 300px;&lt;br /&gt;
  max-width: 100%;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.image-sizing-200 img {&lt;br /&gt;
  max-height: 200px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.image-sizing-none img {&lt;br /&gt;
  max-height: none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
div.ul-res ul {&lt;br /&gt;
  margin: 0;&lt;br /&gt;
  list-style: none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tab-glob {&lt;br /&gt;
    display: flex;&lt;br /&gt;
    flex-direction: row;&lt;br /&gt;
    margin: 10px 0;&lt;br /&gt;
    column-gap: 2px;&lt;br /&gt;
    align-items: flex-start;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tab-glob &amp;gt; :first-child {&lt;br /&gt;
    display: grid;&lt;br /&gt;
    grid-template-columns: max-content;&lt;br /&gt;
    row-gap: 2px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tab-glob &amp;gt; :first-child &amp;gt; * {&lt;br /&gt;
    border: 1px black solid;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tab-glob &amp;gt; :first-child &amp;gt; *:not(.fondfenetre) {&lt;br /&gt;
    font-weight: bold;&lt;br /&gt;
    display: flex;&lt;br /&gt;
    justify-content: center;&lt;br /&gt;
    align-items: center;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tab-glob &amp;gt; :nth-child(2) {&lt;br /&gt;
    width: 100%;&lt;br /&gt;
    overflow-x: auto;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tab-glob &amp;gt; :nth-child(2) &amp;gt; :first-child {&lt;br /&gt;
    display: grid;&lt;br /&gt;
    grid-template-columns: repeat(10,minmax(75px,1fr));&lt;br /&gt;
    gap: 2px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tab-glob &amp;gt; :nth-child(2) &amp;gt; :first-child &amp;gt; * {&lt;br /&gt;
    border: 1px black solid;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tab-glob &amp;gt; :nth-child(2) &amp;gt; :first-child &amp;gt; :not(.fondfenetre) {&lt;br /&gt;
    display: flex;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tab-glob &amp;gt; :nth-child(2) &amp;gt; :first-child &amp;gt; :not(.fondfenetre) &amp;gt; * {&lt;br /&gt;
  margin: auto;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.list-equip {&lt;br /&gt;
  padding: 5px;&lt;br /&gt;
  border: 1px solid #2f1d1f;&lt;br /&gt;
  display: flex;&lt;br /&gt;
  flex-direction: column;&lt;br /&gt;
  align-items: center;&lt;br /&gt;
  gap: 5px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.list-equip &amp;gt; :first-child {&lt;br /&gt;
  width: 100%;&lt;br /&gt;
  line-height: 25px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.list-equip &amp;gt; :first-child &amp;gt; * {&lt;br /&gt;
  padding: 0 5px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.fabrication {&lt;br /&gt;
  position: relative;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.fabrication &amp;gt; * {&lt;br /&gt;
  position: absolute;&lt;br /&gt;
  top: -188px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.fabrication &amp;gt; .bottom-fab,&lt;br /&gt;
.fabrication &amp;gt; .bottom-fab ~ * {&lt;br /&gt;
  top: -58px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.fabrication &amp;gt; * &amp;gt; *:nth-child(2) {&lt;br /&gt;
  position: relative;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.fabrication &amp;gt; * &amp;gt; *:nth-child(2) &amp;gt; * {&lt;br /&gt;
  position: absolute;&lt;br /&gt;
  top: -18px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.fabrication &amp;gt; * &amp;gt; *:nth-child(n+3) {&lt;br /&gt;
  position: absolute;&lt;br /&gt;
  top: 100px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.info-boutique ul {&lt;br /&gt;
  list-style-image: none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.info-boutique p:last-child {&lt;br /&gt;
  margin-bottom: 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
kbd {&lt;br /&gt;
  background-color: #eee;&lt;br /&gt;
  border-radius: 3px;&lt;br /&gt;
  border: 1px solid #b4b4b4;&lt;br /&gt;
  box-shadow: 0 1px 1px rgb(0 0 0 / 20%), 0 2px 0 0 rgb(255 255 255 / 70%) inset;&lt;br /&gt;
  color: #333;&lt;br /&gt;
  display: inline-block;&lt;br /&gt;
  font-size: 0.85em;&lt;br /&gt;
  font-weight: 700;&lt;br /&gt;
  line-height: 1;&lt;br /&gt;
  padding: 2px 4px;&lt;br /&gt;
  white-space: nowrap;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.top-button {&lt;br /&gt;
  display: flex;&lt;br /&gt;
  justify-content: center;&lt;br /&gt;
  align-items: center;&lt;br /&gt;
  opacity: 0;&lt;br /&gt;
  cursor: pointer;&lt;br /&gt;
  position: fixed;&lt;br /&gt;
  bottom: 10px;&lt;br /&gt;
  right: 10px;&lt;br /&gt;
  width: 32px;&lt;br /&gt;
  height: 32px;&lt;br /&gt;
  background: linear-gradient(180deg, &lt;br /&gt;
    rgba(124, 200, 65, 1) 0%, &lt;br /&gt;
    rgba(113, 161, 85, 1) 50%, &lt;br /&gt;
    rgba(64, 117, 39, 1) 50%, &lt;br /&gt;
    rgba(46, 97, 31, 1) 100%);&lt;br /&gt;
  border: 1px solid #d0af52;&lt;br /&gt;
  box-shadow: 1px 1px 2px #000,&lt;br /&gt;
              inset 1px 1px #090200,&lt;br /&gt;
              inset -1px -1px #090200; &lt;br /&gt;
  transform: translateY(100px);&lt;br /&gt;
  transition: all 0.5s ease;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.top-button:after {&lt;br /&gt;
  content: &amp;quot;&amp;quot;;&lt;br /&gt;
  height: 32px;&lt;br /&gt;
  width: 32px;&lt;br /&gt;
  background-image: url(&amp;quot;data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fffacb' height='32' viewBox='0 -960 960 960' width='32'%3E%3Cpath d='m296-345-56-56 240-240 240 240-56 56-184-184-184 184Z'/%3E%3C/svg%3E&amp;quot;);&lt;br /&gt;
  background-repeat: no-repeat;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.show-button {&lt;br /&gt;
  opacity: 1;&lt;br /&gt;
  transform: translateY(0);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.ul-row ul {&lt;br /&gt;
  display: flex;&lt;br /&gt;
  column-gap: 30px;&lt;br /&gt;
  flex-wrap: wrap;&lt;br /&gt;
  overflow: hidden;&lt;br /&gt;
  margin: 0;&lt;br /&gt;
  list-style-image: none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.flex {&lt;br /&gt;
  display: flex;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
#catlinks {&lt;br /&gt;
  margin-top: 10px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.improved-collapsible &amp;gt; .mw-collapsible-toggle {&lt;br /&gt;
  grid-area: 1 / -1;&lt;br /&gt;
  display: flex;&lt;br /&gt;
  justify-content: flex-end;&lt;br /&gt;
  align-items: center;&lt;br /&gt;
  float: initial;&lt;br /&gt;
  z-index: 1;&lt;br /&gt;
  padding-right: 5px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.improved-collapsible .mw-collapsible-toggle:before {&lt;br /&gt;
  content: &amp;quot;&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.improved-collapsible .mw-collapsible-text {&lt;br /&gt;
  display: none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.improved-collapsible .mw-collapsible-toggle:after {&lt;br /&gt;
  width: 32px;&lt;br /&gt;
  height: 32px;&lt;br /&gt;
  content: &amp;quot;&amp;quot;;&lt;br /&gt;
  background-image: url(&amp;quot;data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23000000' height='32' viewBox='0 -960 960 960' width='32'%3E%3Cpath d='M480-345 240-585l56-56 184 184 184-184 56 56-240 240Z'/%3E%3C/svg%3E&amp;quot;);&lt;br /&gt;
  background-repeat: no-repeat;&lt;br /&gt;
  transition: transform .2s ease-in-out;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.improved-collapsible .mw-collapsible-toggle-expanded:after {&lt;br /&gt;
  transform: rotate(-180deg);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tooltip-icon {&lt;br /&gt;
  background-image: url(&amp;quot;data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' height='24' viewBox='0 -960 960 960' width='24'%3E%3Cpath d='M443-285h75v-234h-75v234Zm36.895-311Q496-596 507-606.895q11-10.894 11-27Q518-650 507.105-661q-10.894-11-27-11Q464-672 453-661.105q-11 10.894-11 27Q442-618 452.895-607q10.894 11 27 11ZM480-90q-80.907 0-152.065-30.763-71.159-30.763-123.797-83.5Q151.5-257 120.75-328.087 90-399.175 90-480q0-80.907 30.763-152.065 30.763-71.159 83.5-123.797Q257-808.5 328.087-839.25 399.175-870 480-870q80.907 0 152.065 30.763 71.159 30.763 123.797 83.5Q808.5-703 839.25-631.913 870-560.825 870-480q0 80.907-30.763 152.065-30.763 71.159-83.5 123.797Q703-151.5 631.913-120.75 560.825-90 480-90Zm0-75q131.5 0 223.25-91.75T795-480q0-131.5-91.75-223.25T480-795q-131.5 0-223.25 91.75T165-480q0 131.5 91.75 223.25T480-165Zm0-315Z'/%3E%3C/svg%3E&amp;quot;);&lt;br /&gt;
  background-repeat: no-repeat;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tooltip-info {&lt;br /&gt;
  position: absolute;&lt;br /&gt;
  bottom: calc(100% + 8px);&lt;br /&gt;
  left: 50%;&lt;br /&gt;
  transform: translateX(-50%);&lt;br /&gt;
  max-width: 290px;&lt;br /&gt;
  width: max-content;&lt;br /&gt;
  z-index: 50;&lt;br /&gt;
  opacity: 0;&lt;br /&gt;
  visibility: hidden;&lt;br /&gt;
  transition: opacity 0.2s ease, visibility 0.2s ease;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tooltip-info:after {&lt;br /&gt;
    content: &amp;quot;&amp;quot;;&lt;br /&gt;
    border: 8px solid transparent;&lt;br /&gt;
    border-top-color: inherit;&lt;br /&gt;
    position: absolute;&lt;br /&gt;
    left: calc(50% - 8px);&lt;br /&gt;
    top: 100%;&lt;br /&gt;
    z-index: 50;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.tooltip-icon:hover &amp;gt; .tooltip-info {&lt;br /&gt;
  opacity: 1;&lt;br /&gt;
  visibility: visible;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.cacheTel,&lt;br /&gt;
.tabber-container &amp;gt; :last-child &amp;gt; :not(.tabber-active),&lt;br /&gt;
.tabber-noactive {&lt;br /&gt;
  display: none;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes pnj-square {&lt;br /&gt;
  from {background-color: #f80000;}&lt;br /&gt;
  to {background-color: white;}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes pnj-circle {&lt;br /&gt;
  from {border-color: #984c48;}&lt;br /&gt;
  to {border-color: white;}&lt;br /&gt;
  from {scale: 1;}&lt;br /&gt;
  to {scale: .1;}&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
@keyframes loading {&lt;br /&gt;
  0% {&lt;br /&gt;
    transform: scale(1.5);&lt;br /&gt;
  }&lt;br /&gt;
  100% {&lt;br /&gt;
    transform: scale(1);&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
@media screen and (max-width: 768px){&lt;br /&gt;
  .texte-long {&lt;br /&gt;
    white-space: normal;&lt;br /&gt;
    overflow: visible;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  .grid2 {&lt;br /&gt;
    grid-template-columns: repeat(2, 1fr) !important;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  .grid3 {&lt;br /&gt;
    grid-template-columns: repeat(3, auto) !important;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  .modal-content {&lt;br /&gt;
    padding: 30px 0 0 10px;&lt;br /&gt;
    width: 90%;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  .container { &lt;br /&gt;
   flex-direction: column; &lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  .cacheTel,&lt;br /&gt;
  .subpage &amp;gt; li:nth-last-child(2) &amp;gt; a {&lt;br /&gt;
    display: block;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  .top-button {&lt;br /&gt;
    background: rgba(0, 0, 0, 0.7);&lt;br /&gt;
    color: #999;&lt;br /&gt;
    border: none;&lt;br /&gt;
    box-shadow: none;&lt;br /&gt;
  }&lt;br /&gt;
  &lt;br /&gt;
  .top-button::after {&lt;br /&gt;
    background-image: url(&amp;quot;data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23ffffff' height='24' viewBox='0 -960 960 960' width='24'%3E%3Cpath d='M440-80v-647L256-544l-56-56 280-280 280 280-56 57-184-184v647h-80Z'/%3E%3C/svg%3E&amp;quot;);&lt;br /&gt;
    height: 24px;&lt;br /&gt;
    width: 24px;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  .tooltip-icon {&lt;br /&gt;
    position: static;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  .tooltip-info {&lt;br /&gt;
    position: fixed;&lt;br /&gt;
    left: 20px;&lt;br /&gt;
    right: 20px;&lt;br /&gt;
    bottom: 50px;&lt;br /&gt;
    max-width: none;&lt;br /&gt;
    width: auto;&lt;br /&gt;
    transform: none;&lt;br /&gt;
    height: max-content;&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  .subpage &amp;gt; li &amp;gt; a,&lt;br /&gt;
  .cacheOrdi,&lt;br /&gt;
  .tooltip-info:after {&lt;br /&gt;
    display: none;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
@media screen and (max-width: 340px){&lt;br /&gt;
  #mw-content {&lt;br /&gt;
    padding-left: 10px;&lt;br /&gt;
    padding-right: 10px;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
@media screen and (min-width: 851px){&lt;br /&gt;
  html {&lt;br /&gt;
    scroll-padding-top: 3.325em;&lt;br /&gt;
  }&lt;br /&gt;
}&lt;/div&gt;</summary>
		<author><name>Dexter</name></author>
		
	</entry>
</feed>