Melvor Idle Corruption Helper

Automate rolling for specific modifiers in Corruption Mode (April Fools 2021 event)

K instalaci tototo skriptu si budete muset nainstalovat rozšíření jako Tampermonkey, Greasemonkey nebo Violentmonkey.

K instalaci tohoto skriptu si budete muset nainstalovat rozšíření jako Tampermonkey nebo Violentmonkey.

K instalaci tohoto skriptu si budete muset nainstalovat rozšíření jako Tampermonkey nebo Violentmonkey.

K instalaci tohoto skriptu si budete muset nainstalovat rozšíření jako Tampermonkey nebo Userscripts.

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

K instalaci tohoto skriptu si budete muset nainstalovat manažer uživatelských skriptů.

(Už mám manažer uživatelských skriptů, nechte mě ho nainstalovat!)

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

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

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

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

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

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

(Už mám manažer uživatelských stylů, nechte mě ho nainstalovat!)

// ==UserScript==
// @name         Melvor Idle Corruption Helper
// @namespace    http://tampermonkey.net/
// @version      1.0.2
// @description  Automate rolling for specific modifiers in Corruption Mode (April Fools 2021 event)
// @author       Cyrogem
// @helpedby     Erik Gillespie, Kad
// @site         https://www.cyrogemgames.com/
// @match        https://*.melvoridle.com/*
// @exclude      https://wiki.melvoridle.com/*
// @grant        none
// ==/UserScript==

const skillSpecificModifiers = [
  // inc skill hidden level
  40,
  // dec skill interval
  92,
  // dec skill interval %
  93,
  // inc skill preserve chance
  95,
  // inc mastery exp
  103,
  // inc skill exp
  104,
  // (old) probably inc skill interval
  107,
  // (old) probably inc skill interval %
  108,
  // inc chance to double in skill
  132,
]

let allTraitsWanted = {}
let newDesireTrait = -1
let newDesireValue = -1
let newDesireSlot = -1
let newDesireSkill = -1
let iterations = 0
let lostItems = 0
let rolls = 0

let activeModifiers = [];

/**
 * Roll for corruption based on the previously input information
 */
function CyrogemRollCorruption(){
  if (newDesireSlot < 0){
    window.alert('Please select a slot to roll for')
    return;
  }
  let equipmentSlot = newDesireSlot
  let cost = getRandomModifierCost(equipmentSlot);
  let keepTrying = true
  let mods = {}
  lostItems = 0
  rolls = 0

  // Test to make sure we have the things
  let atLeastOneKey = false
  for(var key in allTraitsWanted) {
    var value = allTraitsWanted[key];
    if (typeof value === 'object' && value !== null){
      atLeastOneKey = Object.keys(value).length > 0 || atLeastOneKey
    } else {
      atLeastOneKey = true
    }
    //console.log(key + ' ' + value)
  }

  if (!atLeastOneKey){
    window.alert('Please have at least one desire')
    return;
  }

  // Re-roll
  for(let i = 0; i < iterations && keepTrying; i++){
    rolls++
    //console.log(cost + ' ' + equippedItems[equipmentSlot])
    if (gp >= cost && equippedItems[equipmentSlot] > 0) {
      gp -= cost;
      updateGP();
      let tier = getRandomModifierTier(equipmentSlot);
      let chanceToDestroy = getRandomModifiersDestroyChance(tier);
      // Do we lose the item
      if (rollPercentage(chanceToDestroy)) {
        lostItems++
        let qty = getItemQtyRandomModifier(equippedItems[equipmentSlot]);
        if (qty[0] > 1) {
            if (equipmentSlot === CONSTANTS.equipmentSlot.Quiver && ammo > 1) {
                ammo--;
                equipmentSets[selectedEquipmentSet].ammo--;
                updateAmmo();
            } else
                updateItemInBank(qty[1], equippedItems[equipmentSlot], -1);
        } else {
            equippedItems[equipmentSlot] = 0;
            equipmentSets[selectedEquipmentSet].equipment[equipmentSlot] = 0;
            setEquipmentSet(selectedEquipmentSet);
        }
      } else {
        mods = rollRandomModifiers(tier, "equipment", equipmentSlot);
        keepTrying = !CyrogemCheckCorruption(mods)
      }
    } else {
      rolls--
      break;
    }
  }
  updateRandomModifierInfo(equipmentSlot);
  updateHTMLRandomMod(equipmentSlot, mods);
  window.alert('We ' + (keepTrying ? 'failed' : 'succeeded') + ' after ' + rolls + ' re-rolls and lost ' + lostItems + ' to the void')
}

/**
 * Are these mods what we desire
 * @param {*} mods The newly rolled mods
 * @returns True if a mod matches a desire
 */
function CyrogemCheckCorruption(mods){
  let success = false
  for (let i = 0; i < mods.length && !success; i++) {
    let theMod = mods[i].modifier
    let theValue = mods[i].value
    //console.log(theMod)
    //console.log(theValue)
    // Is the value a list
    if (theValue.length) {
      // This is a niche event, is this something we are looking for
      // Get it out of it's inner shell
      theValue = theValue[0]
      let theSkillName = skillName[theValue[0]]
      //console.log('skill name = ' + theSkillName)
      // Check if we have this defined as a desire
      if (allTraitsWanted[theMod] !== undefined && allTraitsWanted[theMod][theSkillName] !== undefined){
        // We have it defined, is it high enough of a value
        if (allTraitsWanted[theMod][theSkillName] <= theValue[1]){
          success = true
        }
      }
    }
    else{
      if (allTraitsWanted[theMod] !== undefined && allTraitsWanted[theMod] <= theValue) {
        success = true
      }
    }
  }
  // If we have one of the ones we want, return true
  return success
}

/**
 * Remember current desire to check against when we roll
 *
 * Also creates button to remove desire
 */
function CyrogemAddDesire(){
  if (newDesireValue === -1 || newDesireValue === '' || newDesireTrait === -1 || (skillSpecificModifiers.includes(newDesireTrait) && newDesireSkill === -1)){
    window.alert('Please Select a Slot, Desired Trait(s), Desired Value(s), and a Desired Skill if aplicable')
    return;
  }



  let newmod = activeModifiers[newDesireTrait]
  // Is this a special case where we need a skill specified
  if(skillSpecificModifiers.includes(newDesireTrait)){
    // Initial setup in case this is our first one
    if (allTraitsWanted[newmod] === undefined){
      allTraitsWanted[newmod] = {}
    }
    // Assign this with the skillName
    allTraitsWanted[newmod][skillName[newDesireSkill]] = newDesireValue
  } else {
    allTraitsWanted[newmod] = newDesireValue
  }

  // Erik Gillespie solved this issue
  const displayElement = document.getElementById('cyrogem-current-desires')
  const buttonTemplate = document.getElementById('cyrogem-button-template')
  const newButton = document.importNode(buttonTemplate.content.firstElementChild, true)

  // Is this a skill specific desire
  if(skillSpecificModifiers.includes(newDesireTrait)){
    let trait = activeModifiers[newDesireTrait]
    let skill = skillName[newDesireSkill]
    newButton.id = 'kill-desire-' + trait + '-' + skill
    newButton.innerHTML = printPlayerModifier(trait, [newDesireSkill, newDesireValue])[0]
    newButton.addEventListener('click', () => CyrogemRemoveDesire(trait, skill))
  } else {
    let trait = activeModifiers[newDesireTrait]
    newButton.id = 'kill-desire-' + trait
    newButton.innerHTML = printPlayerModifier(trait, newDesireValue)[0]
    newButton.addEventListener('click', () => CyrogemRemoveDesire(trait))
  }

  displayElement.appendChild(newButton)

  CyrogemUpdatePrediction()

  // Debugging
  /*
  for(var key in allTraitsWanted) {
    var value = allTraitsWanted[key];
    if(typeof value === 'object' && value !== null){
      for(var key2 in value){
        console.log(
          'My path is: allTraitsWanted[' + key + '][' + key2 + ']' +
          '\nand I equal ' + allTraitsWanted[key][key2]
        )
      }
    } else {
      console.log(key + ' ' + value)
    }
  }
  */
}

/**
 * Remove a currently listed desire
 * @param {*} trait What desire are we removing
 * @param {*} skill What skill, if any, are we removing from this trait
 */
function CyrogemRemoveDesire(trait, skill=null){
  // Easy one first
  //console.log(allTraitsWanted[trait] + ' before')
  if (skill === null){
    delete allTraitsWanted[trait];
    document.getElementById('kill-desire-' + trait).remove()
  } else {
    var value = allTraitsWanted[trait];
    if(typeof value === 'object' && value !== null){
      delete value[skill];
      document.getElementById('kill-desire-' + trait + '-' + skill).remove()
    }
  }
  //console.log(allTraitsWanted.trait + ' after')
  CyrogemUpdatePrediction()
}

// Erik Gillespie provided the solution to buttons losing eventHandlers
// A lot of old code was removed thanks to him
const ErikTactic = true

/**
 * Update the display for the player showing the expected outcome
 */
function CyrogemUpdatePrediction(){
  let predictionHTML = ''
  // Assemble info only needed here
  let costPerRoll = newDesireSlot >= 0 ? getRandomModifierCost(newDesireSlot) : 0
  let tierOfRoll = newDesireSlot >= 0 ? getRandomModifierTier(newDesireSlot) : 0
  let maxValue = getRandomModifierMaxValue(tierOfRoll) - 1
  let items = newDesireSlot >= 0 ? getItemQtyRandomModifier(equippedItems[newDesireSlot])[0] : 0
  let predictedNumberOfActualRolls = iterations
  let rollsUntilNoItems = tierOfRoll <= 0 ? 0 : Math.floor(items / (getRandomModifiersDestroyChance(tierOfRoll) / 100))

  // Find our limiting factor, either attempts, items, or gold
  if (rollsUntilNoItems < predictedNumberOfActualRolls){
    predictedNumberOfActualRolls = rollsUntilNoItems
  }
  if (gp / costPerRoll < predictedNumberOfActualRolls){
    predictedNumberOfActualRolls = Math.floor(gp / costPerRoll)
  }

  // Calculate odds
  let oddsOfGettingWhatYouWant = 0.0

  for(var trait in allTraitsWanted){
    let value = allTraitsWanted[trait]
    // It's not simple we need to take value into account
    if(typeof value === 'object' && value !== null){
      for(var skill in value){
        oddsOfGettingWhatYouWant += Math.max((((maxValue - allTraitsWanted[trait][skill]) / maxValue) / skillName.length) / activeModifiers.length, 0)
      }
    } else {
      oddsOfGettingWhatYouWant += Math.max(((maxValue - allTraitsWanted[trait]) / maxValue) / activeModifiers.length, 0)
    }
  }
  let oddsOfFailure = Math.pow((1.0 - oddsOfGettingWhatYouWant), tierOfRoll)

  let finalSuccessChance = 1 - Math.pow(oddsOfFailure, predictedNumberOfActualRolls)
  const headerOpen = '<h5 class="font-w400 font-size-sm text-center text-combat-smoke m-1 mb-2">'
  // Time to assemble the information to the user
  predictionHTML += '<h3 class="font-w600 font-size-sm text-center text-danger m-1 mb-2">Corruption Prediction</h3>' +
  headerOpen + 'Predicted rolls accounting for gold and item loss: <span class="font-w600 text-warning">' + predictedNumberOfActualRolls + '</span></h5>' +
  headerOpen + 'Chance of success in those rolls: ' + CyrogemRollChanceColor(finalSuccessChance) + '</h5>' +
  headerOpen + 'Predicted Max Cost: <img src="assets/media/main/coins.svg" class="skill-icon-xs mr-2">' + (costPerRoll * predictedNumberOfActualRolls) + '</h5>' +
  headerOpen + '50% success rate achieved at: <span class="font-w600 text-warning">' + CyrogemRollsForFiftyPercent(oddsOfFailure) + '</h5>'

  //document.getElementById('cyrogem-predictive-display').insertAdjacentHTML('beforeend', predictionHTML)
  document.getElementById('cyrogem-predictive-display').innerHTML = predictionHTML
}

/**
 * Calculates how many rolls are required to get a 50% chance or better of success
 * @param {*} failChancePerRoll Odds of not getting what you want every roll
 * @returns Roll count and closing span tag
 */
function CyrogemRollsForFiftyPercent(failChancePerRoll){
  if(failChancePerRoll < 0.0 || failChancePerRoll >= 1.0){
    return 'Never</span>';
  } else {
    let loops = 1
    let failChance = failChancePerRoll
    while (loops < 10000 && failChance > 0.5){
      loops++
      failChance = failChance * failChancePerRoll
    }
    if (failChance > 0.5){
      return 'Too Many</span>';
    } else {
      let value = loops + ' rolls</span>'
      return value;
    }
  }
}

/**
 * Color and format the success chance for players
 * @param {*} successChance Odds of success for all rolls
 * @returns formatted HTML
 */
function CyrogemRollChanceColor(successChance){
  let textMod = ''
  if(successChance <= 0.33){
    textMod = 'text-danger'
  } else if (successChance <= 0.66){
    textMod = 'text-warning'
  } else {
    textMod = 'text-success'
  }
  let output = '<span class="font-w600 ' + textMod + '">' + (Math.round(successChance * 10000) / 100) + '%</span>'
  return output;
}

/**
 * Set the desired Trait
 * @param {*} index index of the trait from activeModifiers
 */
function CyrogemDesiredTrait(index){
  newDesireTrait = index
  document.getElementById('cyrogem-desire-display-span').textContent = activeModifiers[newDesireTrait]
  // Does this target specific skills
  //console.log(newDesireTrait)
  if (skillSpecificModifiers.includes(newDesireTrait)){
    console.log('more info needed')
    document.getElementById('cyrogem-desire-extra').className = ""
  } else {
    document.getElementById('cyrogem-desire-extra').className = "d-none"
  }
}

/**
 * Set the desired Skill
 * @param {*} index index of the skill from skillName
 */
function CyrogemDesiredSkill(index){
  //console.log(index)
  newDesireSkill = index
  document.getElementById('cyrogem-desire-extra-span').textContent = skillName[newDesireSkill]
}

/**
 * Set the desired value to the input field value
 */
function CyrogemDesiredValue(){
  const valueHTML = document.getElementById('cyrogem-desire-value')
  newDesireValue = valueHTML.value
  document.getElementById('cyrogem-desire-display-value').textContent = newDesireValue
}

/**
 * Set the desired tries to the input field value
 */
function CyrogemDesiredTries(){
  const valueHTML = document.getElementById('cyrogem-iterations')
  iterations = valueHTML.value
  document.getElementById('cyrogem-iterations-display').textContent = iterations
  CyrogemUpdatePrediction()
}

/**
 * Choose an equipment slot to roll for
 * @param {*} slot index of slot
 */
function CyrogemSelectSlot(slot){
  newDesireSlot = slot
  let slotName = 'Slot'
  switch(slot){
    case 0: slotName = 'Helmet'; break;
    case 1: slotName = 'Body'; break;
    case 2: slotName = 'Legs'; break;
    case 3: slotName = 'Boots'; break;
    case 4: slotName = 'Weapon'; break;
    case 5: slotName = 'Shield'; break;
    case 6: slotName = 'Amulet'; break;
    case 7: slotName = 'Ring'; break;
    case 8: slotName = 'Gloves'; break;
    case 9: slotName = 'Quiver'; break;
    case 10: slotName = 'Cape'; break;
  }
  document.getElementById('cyrogem-desire-slot-span').textContent = slotName
  CyrogemUpdatePrediction()
}

function CyrogemSkipModifierInDesireList(modifier) {
  if (modifier.includes('aprilFools')) {
      return true;
  }

  let decreaseGood = false;
  if (modifier.includes('PlayerAttackSpeed') || modifier.includes('MonsterRespawnTimer') || modifier.includes('SkillInterval')) {
      decreaseGood = true;
  };

  if (decreaseGood) {
      return modifier.includes('increase');
  } else {
      return modifier.includes('decrease');
  }
}

/**
 * Load the tool, setup references, inject HTML
 */
function CyrogemLoadCorruptionHelper () {
  let bannedModifiers = ["golbinRaidWaveSkipCostReduction", "golbinRaidIncreasedMinimumFood", "golbinRaidIncreasedMaximumAmmo", "golbinRaidIncreasedMaximumRunes", "golbinRaidPrayerUnlocked", "golbinRaidIncreasedPrayerLevel", "golbinRaidIncreasedPrayerPointsStart", "golbinRaidIncreasedPrayerPointsWave", "golbinRaidPassiveSlotUnlocked", "golbinRaidIncreasedStartingRuneCount", "golbinRaidStartingWeapon", "freeBonfires", "autoSlayerUnlocked", "increasedEquipmentSets", "dungeonEquipmentSwapping", "increasedTreeCutLimit", "increasedAttackRolls", "decreasedAttackRolls", "increasedBankSpaceShop", "decreasedBankSpaceShop", "increasedGPFromSales", "decreasedGPFromSales", ];
  activeModifiers = [];
  for (let i = 0; i < Object.keys(playerModifiersTemplate).length; i++) {
    if (!bannedModifiers.includes(Object.keys(playerModifiersTemplate)[i]))
    activeModifiers.push(Object.keys(playerModifiersTemplate)[i]);
  }

  // Setup the entire block
  let playerDesiresHTML =
  '<div class="block block-rounded block-link-pop border-top border-info border-4x row no-gutters">'

  // First Column
  playerDesiresHTML +=
  '<div class="col-sm-6 col-lg-4"><div class=block-content>'
  // Setup Desire Dropdown
  playerDesiresHTML +=
  '<div class="dropdown"><button type="button" class="btn btn-secondary dropdown-toggle mt-2" id="cyrogem-desire-dropdown" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Desired Attribute</button>' +
  '<div class="dropdown-menu font-size-sm" aria-labelledby="cyrogem-desire-dropdown" style="max-height: 800px; overflow-y: scroll;">'
  for (let i = 0; i < activeModifiers.length; i++){
    if (CyrogemSkipModifierInDesireList(activeModifiers[i])) continue;
    playerDesiresHTML += '<a class="dropdown-item" id="cyrogemDesiredTrait' + i + '" style="text-transform: capitalize;">' + activeModifiers[i] + '</a>'
  }
  playerDesiresHTML += '</div></div>' +
  '<span class="font-w400 font-size-sm text-combat-smoke ml-2">Desire: <span id="cyrogem-desire-display-span" style="text-transform: capitalize;">Select One</span></span>'
  // Oh god we have to add another check for specific skill ones like "increasedSmithingMasteryXP"
  playerDesiresHTML +=
  '<div class="d-none" id="cyrogem-desire-extra">' +
  // We need a new dropdown for all the skills
  '<div class="dropdown"><button type="button" class="btn btn-secondary dropdown-toggle mt-2" id="cyrogem-desire-extra-dropdown" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Skill</button>' +
  '<div class="dropdown-menu font-size-sm" aria-labelledby="cyrogem-desire-extra-dropdown">'
  for (let i = 0; i < skillName.length; i++){
    playerDesiresHTML += '<a class="dropdown-item" id="cyrogemDesiredSkill' + i + '" style="text-transform: capitalize;">' + skillName[i] + '</a>'
  }
  playerDesiresHTML += '</div></div>' +
  '<span class="font-w400 font-size-sm text-combat-smoke ml-2">Target Skill: <span id="cyrogem-desire-extra-span" style="text-transform: capitalize;">Select One</span></span>' +
  '</div>'

  // What value do you want
  playerDesiresHTML += '<div class="col-12"><input type="number" class="form-control m-1" id="cyrogem-desire-value" placeholder="0"></div>' +
  '<span class="font-w400 font-size-sm text-combat-smoke ml-2">Minimum Level: <span id="cyrogem-desire-display-value">Enter above</span></span>'

  // What slot are we changing
  playerDesiresHTML +=
  '<div class="col-12"><button type="button" class="swal2-confirm swal2-styled" id="cyrogem-add-desire" aria-label="" style="display: inline-block; border-left-color: rgb(48, 133, 214); border-right-color: rgb(48, 133, 214);">Add Desire</button></div>'

  // Close the content block and column div
  playerDesiresHTML += '</div></div>'


  // Second column
  playerDesiresHTML += '<div class="col-sm-3"><div class=block-content>' +
  '<div class="col-12"><input type="number" class="form-control m-1" id="cyrogem-iterations" placeholder="0"></div>' +
  '<span class="font-w400 font-size-sm text-combat-smoke ml-2">Try how many times<br>(Assuming you can afford it): <span id="cyrogem-iterations-display">0</span></span>'

  playerDesiresHTML += '<div class="dropdown"><button type="button" class="btn btn-secondary dropdown-toggle mt-2" id="cyrogem-slot-dropdown" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" onclick="">' +
  'Slot to Roll For</button><div class="dropdown-menu font-size-sm" aria-labelledby="cyrogem-slot-dropdown">' +
  '<a class="dropdown-item" id="cyrogemSelectSlot0">Helmet</a>' +
  '<a class="dropdown-item" id="cyrogemSelectSlot1">Body</a>' +
  '<a class="dropdown-item" id="cyrogemSelectSlot2">Legs</a>' +
  '<a class="dropdown-item" id="cyrogemSelectSlot3">Boots</a>' +
  '<a class="dropdown-item" id="cyrogemSelectSlot4">Weapon</a>' +
  '<a class="dropdown-item" id="cyrogemSelectSlot5">Shield</a>' +
  '<a class="dropdown-item" id="cyrogemSelectSlot6">Amulet</a>' +
  '<a class="dropdown-item" id="cyrogemSelectSlot7">Ring</a>' +
  '<a class="dropdown-item" id="cyrogemSelectSlot8">Gloves</a>' +
  '<a class="dropdown-item" id="cyrogemSelectSlot9">Quiver</a>' +
  '<a class="dropdown-item" id="cyrogemSelectSlot10">Cape</a>' +
  '</div></div>'+
  '<span class="font-w400 font-size-sm text-combat-smoke ml-2">Slot: <span id="cyrogem-desire-slot-span">Select One</span></span>'

  // Close the block and column div
  playerDesiresHTML += '</div></div>'


  // Third column
  playerDesiresHTML += '<div class="col-md-5"><div class=block-content>'

  // Display current wishes
  playerDesiresHTML += '<h5 class="font-w700 font-size-sm text-center text-success m-1 mb-2">Desired Mods, Must have one, select any mod to remove it</h5>' +
  '<div class="text-center" id="cyrogem-current-desires"></div>'

  // Close the block and column div
  playerDesiresHTML += '</div></div>'

  // NEW ROW
  playerDesiresHTML += '<div class="col-12"><div class="block-content text-center">'

  // Display aggregate info
  playerDesiresHTML += '<div class="col-md-10" id="cyrogem-predictive-display"></div>' +
  '<div class="col-md-2">' + // Button to roll
  '<button type="button" class="swal2-confirm swal2-styled" id="cyrogem-roll-button" aria-label="" style="display: inline-block; border-left-color: rgb(48, 133, 214); border-right-color: rgb(48, 133, 214);">Roll For It</button></div>'
  // Close the column, row, and box div
  playerDesiresHTML += '</div></div></div>'

  //document.getElementById('aprilfools2021-container').insertAdjacentHTML('afterbegin', playerDesiresHTML)
  playerDesiresHTML += document.getElementById('aprilfools2021-container').innerHTML
  document.getElementById('aprilfools2021-container').innerHTML = playerDesiresHTML


  // Setup trait links
  for(let i = 0; i < activeModifiers.length; i++){
    //console.log(i)
    let option = document.getElementById('cyrogemDesiredTrait' + i)
    if(option !== null){
      option.addEventListener("click", () => CyrogemDesiredTrait(i))
    }
  }
  // Setup skill links
  for(let i = 0; i < skillName.length; i++){
    let option = document.getElementById('cyrogemDesiredSkill' + i)
    if(option !== null){
      option.addEventListener("click", () =>  CyrogemDesiredSkill(i))
    }
  }
  // Setup slot links
  for(let i = 0; i <= 10; i++){
    //console.log(i)
    document.getElementById('cyrogemSelectSlot' + i).addEventListener("click", () => CyrogemSelectSlot(i))
  }
  // Setup value link
  document.getElementById('cyrogem-desire-value').addEventListener("input", () => CyrogemDesiredValue())
  document.getElementById('cyrogem-desire-value').addEventListener("change", () => CyrogemDesiredValue())
  // Setup quantity link
  document.getElementById('cyrogem-iterations').addEventListener("input", () => CyrogemDesiredTries())
  // Setup roll button
  document.getElementById('cyrogem-roll-button').addEventListener("click", () => CyrogemRollCorruption())
  // Setup desire button
  document.getElementById('cyrogem-add-desire').addEventListener("click", () => CyrogemAddDesire())

  CyrogemUpdatePrediction()
}

/**
 * Inject after page loads
 */
(function () {
  function loadScript() {
      //console.log(window.isLoaded + ' ' + !window.currentlyCatchingUp);// + ' ' + (typeof unsafeWindow !== 'undefined') ? ' ' + unsafeWindow.isLoaded + ' ' + !unsafeWindow.currentlyCatchingUp : '')
      if ((window.isLoaded && !window.currentlyCatchingUp)
          || (typeof unsafeWindow !== 'undefined' && unsafeWindow.isLoaded && !unsafeWindow.currentlyCatchingUp)) {
          // Only load script after game has opened
          clearInterval(scriptLoader);
          document.body.insertAdjacentHTML('beforeend', '<template id="cyrogem-button-template"><button class="btn btn-dark m-1" aria-label="">Button</button></template>')
          CyrogemLoadCorruptionHelper();
      }
  }

  const scriptLoader = setInterval(loadScript, 200);
})();

// Melvor backend code copied for quick reference
/*
function rollRandomModifiers(count=3, key, equipmentSlot=0) {
  if (key === "equipment") {
    if (randomModifiers.equipment[equipmentSlot] === undefined)
    randomModifiers.equipment[equipmentSlot] = {};
    deleteKeysFromObject(randomModifiers.equipment[equipmentSlot]);
  }
  let bannedModifiers = ["golbinRaidWaveSkipCostReduction", "golbinRaidIncreasedMinimumFood", "golbinRaidIncreasedMaximumAmmo", "golbinRaidIncreasedMaximumRunes", "golbinRaidPrayerUnlocked", "golbinRaidIncreasedPrayerLevel", "golbinRaidIncreasedPrayerPointsStart", "golbinRaidIncreasedPrayerPointsWave", "golbinRaidPassiveSlotUnlocked", "golbinRaidIncreasedStartingRuneCount", "golbinRaidStartingWeapon", "freeBonfires", "autoSlayerUnlocked", "increasedEquipmentSets", "dungeonEquipmentSwapping", "increasedTreeCutLimit", "increasedAttackRolls", "decreasedAttackRolls", "increasedBankSpaceShop", "decreasedBankSpaceShop", "increasedGPFromSales", "decreasedGPFromSales", ];
  let activeModifiers = [];
  for (let i = 0; i < Object.keys(playerModifiersTemplate).length; i++) {
    if (!bannedModifiers.includes(Object.keys(playerModifiersTemplate)[i]))
        activeModifiers.push(Object.keys(playerModifiersTemplate)[i]);
  }
  let rng = [];
  for (let i = 0; i < count; i++) {
      let rngMod = Math.floor(Math.random() * activeModifiers.length);
      let value;
      let maxValue = getRandomModifierMaxValue(count);
      if (playerModifiersTemplate[activeModifiers[rngMod]].length)
      // ------------ value is skill index 0, value index 1 ----------------------------------------------------------------------------------------------------------------------
          value = [[Math.floor(Math.random() * 21), Math.floor(Math.random() * maxValue)]];
      else
          value = Math.floor(Math.random() * maxValue);
      if ((activeModifiers[rngMod] === "increasedMaxHitFlat" || activeModifiers[rngMod] === "increasedMaxHitpoints") && value > 10)
          value = 10;
      if ((activeModifiers[rngMod] === "decreasedMaxHitFlat" || activeModifiers[rngMod] === "decreasedMaxHitpoints") && value > 10)
          value = 10;
      rng.push({
          modifier: activeModifiers[rngMod],
          value: value
      });
      if (key === "equipment")
          randomModifiers.equipment[equipmentSlot][activeModifiers[rngMod]] = value;
  }
  return rng;
}

function getEquipmentCorruption2(equipmentSlot) {
  let cost = getRandomModifierCost(equipmentSlot);
  if (gp >= cost && equippedItems[equipmentSlot] > 0) {
      gp -= cost;
      updateGP();
      let tier = getRandomModifierTier(equipmentSlot);
      let chanceToDestroy = getRandomModifiersDestroyChance(tier);
      if (rollPercentage(chanceToDestroy)) {
          let qty = getItemQtyRandomModifier(equippedItems[equipmentSlot]);
          if (qty[0] > 1) {
              if (equipmentSlot === CONSTANTS.equipmentSlot.Quiver && ammo > 1) {
                  ammo--;
                  equipmentSets[selectedEquipmentSet].ammo--;
                  updateAmmo();
              } else
                  updateItemInBank(qty[1], equippedItems[equipmentSlot], -1);
          } else {
              equippedItems[equipmentSlot] = 0;
              equipmentSets[selectedEquipmentSet].equipment[equipmentSlot] = 0;
              setEquipmentSet(selectedEquipmentSet);
          }
          updateRandomModifierInfo(equipmentSlot);
          notifyPlayer(CONSTANTS.skill.Attack, "Your item was destroyed :(", "danger");
      } else {
          let mods = rollRandomModifiers(tier, "equipment", equipmentSlot);
          updateHTMLRandomMod(equipmentSlot, mods);
      }
  }
}
function loadCorruption() {
  for (let i = 0; i < Object.keys(randomModifiers.equipment).length; i++) {
      let html = `<h5 class="font-w600 font-size-sm mb-2">Current Modifiers:</h5>`;
      for (let j = 0; j < Object.keys(randomModifiers.equipment[Object.keys(randomModifiers.equipment)[i]]).length; j++) {
          let modifier = printPlayerModifier(Object.keys(randomModifiers.equipment[Object.keys(randomModifiers.equipment)[i]])[j], randomModifiers.equipment[Object.keys(randomModifiers.equipment)[i]][Object.keys(randomModifiers.equipment[Object.keys(randomModifiers.equipment)[i]])[j]]);
          html += `<h5 class="font-w400 font-size-sm mb-1 ${modifier[1]}">${modifier[0]}</h5>`;
      }
      $("#corruption-equipment-slot-" + Object.keys(randomModifiers.equipment)[i]).html(html);
  }
}
function updateHTMLRandomMod(equipmentSlot, mods) {
  let html = `<h5 class="font-w600 font-size-sm mb-2">Current Modifiers:</h5>`;
  for (let i = 0; i < mods.length; i++) {
      if (mods[i].value.length)
          modifier = printPlayerModifier(mods[i].modifier, mods[i].value[0]);
      else
          modifier = printPlayerModifier(mods[i].modifier, mods[i].value);
      html += `<h5 class="font-w400 font-size-sm mb-1 ${modifier[1]}">${modifier[0]}</h5>`;
  }
  $("#corruption-equipment-slot-" + equipmentSlot).html(html);
  updatePlayerStats();
}
function getRandomModifiersDestroyChance(tier) {
  let chance = 0;
  if (tier >= 4)
      chance = 10;
  else if (tier >= 3)
      chance = 20;
  else if (tier >= 2)
      chance = 30;
  else if (tier >= 1)
      chance = 40;
  return chance;
}
function getRandomModifierMaxValue(tier) {
  let value = 0;
  if (tier >= 4)
      value = 100;
  else if (tier >= 3)
      value = 76;
  else if (tier >= 2)
      value = 51;
  else if (tier >= 1)
      value = 31;
  return value;
}
function getRandomModifierCost(equipmentSlot) {
  let cost = 0;
  if (equippedItems[equipmentSlot] <= 0)
      return cost;
  cost = items[equippedItems[equipmentSlot]].sellsFor;
  return cost;
}
function getRandomModifierTier(equipmentSlot) {
  let tier = 0;
  if (equippedItems[equipmentSlot] <= 0)
      return tier;
  if (items[equippedItems[equipmentSlot]].sellsFor >= 400000)
      tier = 4;
  else if (items[equippedItems[equipmentSlot]].sellsFor >= 10000)
      tier = 3;
  else if (items[equippedItems[equipmentSlot]].sellsFor >= 200)
      tier = 2;
  else
      tier = 1;
  return tier;
}
function updateRandomModifierInfo(equipmentSlot) {
  if (equippedItems[equipmentSlot] > 0) {
      let cost = getRandomModifierCost(equipmentSlot);
      let tier = getRandomModifierTier(equipmentSlot);
      let qty = getItemQtyRandomModifier(equippedItems[equipmentSlot]);
      $("#corruption-equipment-slot-" + equipmentSlot + "-img").attr("src", items[equippedItems[equipmentSlot]].media);
      $("#corruption-equipment-slot-" + equipmentSlot + "-info").html(`Qty: ${qty[0]} | Tier: ${tier}<br>Cost: <img src="assets/media/main/coins.svg" class="skill-icon-xs mr-2">${numberWithCommas(cost)}`);
  } else {
      $("#corruption-equipment-slot-" + equipmentSlot + "-img").attr("src", "assets/media/bank/" + emptyGear[equipmentSlot] + ".svg");
      $("#corruption-equipment-slot-" + equipmentSlot + "-info").html(`Equip an item pls`);
  }
}
function getItemQtyRandomModifier(itemID) {
  let qty = 1;
  let bankID = getBankId(itemID);
  if (bankID >= 0)
      qty += bank[bankID].qty;
  if (items[itemID].equipmentSlot === CONSTANTS.equipmentSlot.Quiver)
      qty += ammo - 1;
  return [qty, bankID];
}
function deleteKeysFromObject(object) {
  Object.keys(object).forEach((el)=>{
      delete object[el];
  }
  );
}

*/