Melvor Idle Corruption Helper

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

  1. // ==UserScript==
  2. // @name Melvor Idle Corruption Helper
  3. // @namespace http://tampermonkey.net/
  4. // @version 1.0.2
  5. // @description Automate rolling for specific modifiers in Corruption Mode (April Fools 2021 event)
  6. // @author Cyrogem
  7. // @helpedby Erik Gillespie, Kad
  8. // @site https://www.cyrogemgames.com/
  9. // @match https://*.melvoridle.com/*
  10. // @exclude https://wiki.melvoridle.com/*
  11. // @grant none
  12. // ==/UserScript==
  13.  
  14. const skillSpecificModifiers = [
  15. // inc skill hidden level
  16. 40,
  17. // dec skill interval
  18. 92,
  19. // dec skill interval %
  20. 93,
  21. // inc skill preserve chance
  22. 95,
  23. // inc mastery exp
  24. 103,
  25. // inc skill exp
  26. 104,
  27. // (old) probably inc skill interval
  28. 107,
  29. // (old) probably inc skill interval %
  30. 108,
  31. // inc chance to double in skill
  32. 132,
  33. ]
  34.  
  35. let allTraitsWanted = {}
  36. let newDesireTrait = -1
  37. let newDesireValue = -1
  38. let newDesireSlot = -1
  39. let newDesireSkill = -1
  40. let iterations = 0
  41. let lostItems = 0
  42. let rolls = 0
  43.  
  44. let activeModifiers = [];
  45.  
  46. /**
  47. * Roll for corruption based on the previously input information
  48. */
  49. function CyrogemRollCorruption(){
  50. if (newDesireSlot < 0){
  51. window.alert('Please select a slot to roll for')
  52. return;
  53. }
  54. let equipmentSlot = newDesireSlot
  55. let cost = getRandomModifierCost(equipmentSlot);
  56. let keepTrying = true
  57. let mods = {}
  58. lostItems = 0
  59. rolls = 0
  60.  
  61. // Test to make sure we have the things
  62. let atLeastOneKey = false
  63. for(var key in allTraitsWanted) {
  64. var value = allTraitsWanted[key];
  65. if (typeof value === 'object' && value !== null){
  66. atLeastOneKey = Object.keys(value).length > 0 || atLeastOneKey
  67. } else {
  68. atLeastOneKey = true
  69. }
  70. //console.log(key + ' ' + value)
  71. }
  72.  
  73. if (!atLeastOneKey){
  74. window.alert('Please have at least one desire')
  75. return;
  76. }
  77.  
  78. // Re-roll
  79. for(let i = 0; i < iterations && keepTrying; i++){
  80. rolls++
  81. //console.log(cost + ' ' + equippedItems[equipmentSlot])
  82. if (gp >= cost && equippedItems[equipmentSlot] > 0) {
  83. gp -= cost;
  84. updateGP();
  85. let tier = getRandomModifierTier(equipmentSlot);
  86. let chanceToDestroy = getRandomModifiersDestroyChance(tier);
  87. // Do we lose the item
  88. if (rollPercentage(chanceToDestroy)) {
  89. lostItems++
  90. let qty = getItemQtyRandomModifier(equippedItems[equipmentSlot]);
  91. if (qty[0] > 1) {
  92. if (equipmentSlot === CONSTANTS.equipmentSlot.Quiver && ammo > 1) {
  93. ammo--;
  94. equipmentSets[selectedEquipmentSet].ammo--;
  95. updateAmmo();
  96. } else
  97. updateItemInBank(qty[1], equippedItems[equipmentSlot], -1);
  98. } else {
  99. equippedItems[equipmentSlot] = 0;
  100. equipmentSets[selectedEquipmentSet].equipment[equipmentSlot] = 0;
  101. setEquipmentSet(selectedEquipmentSet);
  102. }
  103. } else {
  104. mods = rollRandomModifiers(tier, "equipment", equipmentSlot);
  105. keepTrying = !CyrogemCheckCorruption(mods)
  106. }
  107. } else {
  108. rolls--
  109. break;
  110. }
  111. }
  112. updateRandomModifierInfo(equipmentSlot);
  113. updateHTMLRandomMod(equipmentSlot, mods);
  114. window.alert('We ' + (keepTrying ? 'failed' : 'succeeded') + ' after ' + rolls + ' re-rolls and lost ' + lostItems + ' to the void')
  115. }
  116.  
  117. /**
  118. * Are these mods what we desire
  119. * @param {*} mods The newly rolled mods
  120. * @returns True if a mod matches a desire
  121. */
  122. function CyrogemCheckCorruption(mods){
  123. let success = false
  124. for (let i = 0; i < mods.length && !success; i++) {
  125. let theMod = mods[i].modifier
  126. let theValue = mods[i].value
  127. //console.log(theMod)
  128. //console.log(theValue)
  129. // Is the value a list
  130. if (theValue.length) {
  131. // This is a niche event, is this something we are looking for
  132. // Get it out of it's inner shell
  133. theValue = theValue[0]
  134. let theSkillName = skillName[theValue[0]]
  135. //console.log('skill name = ' + theSkillName)
  136. // Check if we have this defined as a desire
  137. if (allTraitsWanted[theMod] !== undefined && allTraitsWanted[theMod][theSkillName] !== undefined){
  138. // We have it defined, is it high enough of a value
  139. if (allTraitsWanted[theMod][theSkillName] <= theValue[1]){
  140. success = true
  141. }
  142. }
  143. }
  144. else{
  145. if (allTraitsWanted[theMod] !== undefined && allTraitsWanted[theMod] <= theValue) {
  146. success = true
  147. }
  148. }
  149. }
  150. // If we have one of the ones we want, return true
  151. return success
  152. }
  153.  
  154. /**
  155. * Remember current desire to check against when we roll
  156. *
  157. * Also creates button to remove desire
  158. */
  159. function CyrogemAddDesire(){
  160. if (newDesireValue === -1 || newDesireValue === '' || newDesireTrait === -1 || (skillSpecificModifiers.includes(newDesireTrait) && newDesireSkill === -1)){
  161. window.alert('Please Select a Slot, Desired Trait(s), Desired Value(s), and a Desired Skill if aplicable')
  162. return;
  163. }
  164.  
  165.  
  166.  
  167. let newmod = activeModifiers[newDesireTrait]
  168. // Is this a special case where we need a skill specified
  169. if(skillSpecificModifiers.includes(newDesireTrait)){
  170. // Initial setup in case this is our first one
  171. if (allTraitsWanted[newmod] === undefined){
  172. allTraitsWanted[newmod] = {}
  173. }
  174. // Assign this with the skillName
  175. allTraitsWanted[newmod][skillName[newDesireSkill]] = newDesireValue
  176. } else {
  177. allTraitsWanted[newmod] = newDesireValue
  178. }
  179.  
  180. // Erik Gillespie solved this issue
  181. const displayElement = document.getElementById('cyrogem-current-desires')
  182. const buttonTemplate = document.getElementById('cyrogem-button-template')
  183. const newButton = document.importNode(buttonTemplate.content.firstElementChild, true)
  184.  
  185. // Is this a skill specific desire
  186. if(skillSpecificModifiers.includes(newDesireTrait)){
  187. let trait = activeModifiers[newDesireTrait]
  188. let skill = skillName[newDesireSkill]
  189. newButton.id = 'kill-desire-' + trait + '-' + skill
  190. newButton.innerHTML = printPlayerModifier(trait, [newDesireSkill, newDesireValue])[0]
  191. newButton.addEventListener('click', () => CyrogemRemoveDesire(trait, skill))
  192. } else {
  193. let trait = activeModifiers[newDesireTrait]
  194. newButton.id = 'kill-desire-' + trait
  195. newButton.innerHTML = printPlayerModifier(trait, newDesireValue)[0]
  196. newButton.addEventListener('click', () => CyrogemRemoveDesire(trait))
  197. }
  198.  
  199. displayElement.appendChild(newButton)
  200.  
  201. CyrogemUpdatePrediction()
  202.  
  203. // Debugging
  204. /*
  205. for(var key in allTraitsWanted) {
  206. var value = allTraitsWanted[key];
  207. if(typeof value === 'object' && value !== null){
  208. for(var key2 in value){
  209. console.log(
  210. 'My path is: allTraitsWanted[' + key + '][' + key2 + ']' +
  211. '\nand I equal ' + allTraitsWanted[key][key2]
  212. )
  213. }
  214. } else {
  215. console.log(key + ' ' + value)
  216. }
  217. }
  218. */
  219. }
  220.  
  221. /**
  222. * Remove a currently listed desire
  223. * @param {*} trait What desire are we removing
  224. * @param {*} skill What skill, if any, are we removing from this trait
  225. */
  226. function CyrogemRemoveDesire(trait, skill=null){
  227. // Easy one first
  228. //console.log(allTraitsWanted[trait] + ' before')
  229. if (skill === null){
  230. delete allTraitsWanted[trait];
  231. document.getElementById('kill-desire-' + trait).remove()
  232. } else {
  233. var value = allTraitsWanted[trait];
  234. if(typeof value === 'object' && value !== null){
  235. delete value[skill];
  236. document.getElementById('kill-desire-' + trait + '-' + skill).remove()
  237. }
  238. }
  239. //console.log(allTraitsWanted.trait + ' after')
  240. CyrogemUpdatePrediction()
  241. }
  242.  
  243. // Erik Gillespie provided the solution to buttons losing eventHandlers
  244. // A lot of old code was removed thanks to him
  245. const ErikTactic = true
  246.  
  247. /**
  248. * Update the display for the player showing the expected outcome
  249. */
  250. function CyrogemUpdatePrediction(){
  251. let predictionHTML = ''
  252. // Assemble info only needed here
  253. let costPerRoll = newDesireSlot >= 0 ? getRandomModifierCost(newDesireSlot) : 0
  254. let tierOfRoll = newDesireSlot >= 0 ? getRandomModifierTier(newDesireSlot) : 0
  255. let maxValue = getRandomModifierMaxValue(tierOfRoll) - 1
  256. let items = newDesireSlot >= 0 ? getItemQtyRandomModifier(equippedItems[newDesireSlot])[0] : 0
  257. let predictedNumberOfActualRolls = iterations
  258. let rollsUntilNoItems = tierOfRoll <= 0 ? 0 : Math.floor(items / (getRandomModifiersDestroyChance(tierOfRoll) / 100))
  259.  
  260. // Find our limiting factor, either attempts, items, or gold
  261. if (rollsUntilNoItems < predictedNumberOfActualRolls){
  262. predictedNumberOfActualRolls = rollsUntilNoItems
  263. }
  264. if (gp / costPerRoll < predictedNumberOfActualRolls){
  265. predictedNumberOfActualRolls = Math.floor(gp / costPerRoll)
  266. }
  267.  
  268. // Calculate odds
  269. let oddsOfGettingWhatYouWant = 0.0
  270.  
  271. for(var trait in allTraitsWanted){
  272. let value = allTraitsWanted[trait]
  273. // It's not simple we need to take value into account
  274. if(typeof value === 'object' && value !== null){
  275. for(var skill in value){
  276. oddsOfGettingWhatYouWant += Math.max((((maxValue - allTraitsWanted[trait][skill]) / maxValue) / skillName.length) / activeModifiers.length, 0)
  277. }
  278. } else {
  279. oddsOfGettingWhatYouWant += Math.max(((maxValue - allTraitsWanted[trait]) / maxValue) / activeModifiers.length, 0)
  280. }
  281. }
  282. let oddsOfFailure = Math.pow((1.0 - oddsOfGettingWhatYouWant), tierOfRoll)
  283.  
  284. let finalSuccessChance = 1 - Math.pow(oddsOfFailure, predictedNumberOfActualRolls)
  285. const headerOpen = '<h5 class="font-w400 font-size-sm text-center text-combat-smoke m-1 mb-2">'
  286. // Time to assemble the information to the user
  287. predictionHTML += '<h3 class="font-w600 font-size-sm text-center text-danger m-1 mb-2">Corruption Prediction</h3>' +
  288. headerOpen + 'Predicted rolls accounting for gold and item loss: <span class="font-w600 text-warning">' + predictedNumberOfActualRolls + '</span></h5>' +
  289. headerOpen + 'Chance of success in those rolls: ' + CyrogemRollChanceColor(finalSuccessChance) + '</h5>' +
  290. headerOpen + 'Predicted Max Cost: <img src="assets/media/main/coins.svg" class="skill-icon-xs mr-2">' + (costPerRoll * predictedNumberOfActualRolls) + '</h5>' +
  291. headerOpen + '50% success rate achieved at: <span class="font-w600 text-warning">' + CyrogemRollsForFiftyPercent(oddsOfFailure) + '</h5>'
  292.  
  293. //document.getElementById('cyrogem-predictive-display').insertAdjacentHTML('beforeend', predictionHTML)
  294. document.getElementById('cyrogem-predictive-display').innerHTML = predictionHTML
  295. }
  296.  
  297. /**
  298. * Calculates how many rolls are required to get a 50% chance or better of success
  299. * @param {*} failChancePerRoll Odds of not getting what you want every roll
  300. * @returns Roll count and closing span tag
  301. */
  302. function CyrogemRollsForFiftyPercent(failChancePerRoll){
  303. if(failChancePerRoll < 0.0 || failChancePerRoll >= 1.0){
  304. return 'Never</span>';
  305. } else {
  306. let loops = 1
  307. let failChance = failChancePerRoll
  308. while (loops < 10000 && failChance > 0.5){
  309. loops++
  310. failChance = failChance * failChancePerRoll
  311. }
  312. if (failChance > 0.5){
  313. return 'Too Many</span>';
  314. } else {
  315. let value = loops + ' rolls</span>'
  316. return value;
  317. }
  318. }
  319. }
  320.  
  321. /**
  322. * Color and format the success chance for players
  323. * @param {*} successChance Odds of success for all rolls
  324. * @returns formatted HTML
  325. */
  326. function CyrogemRollChanceColor(successChance){
  327. let textMod = ''
  328. if(successChance <= 0.33){
  329. textMod = 'text-danger'
  330. } else if (successChance <= 0.66){
  331. textMod = 'text-warning'
  332. } else {
  333. textMod = 'text-success'
  334. }
  335. let output = '<span class="font-w600 ' + textMod + '">' + (Math.round(successChance * 10000) / 100) + '%</span>'
  336. return output;
  337. }
  338.  
  339. /**
  340. * Set the desired Trait
  341. * @param {*} index index of the trait from activeModifiers
  342. */
  343. function CyrogemDesiredTrait(index){
  344. newDesireTrait = index
  345. document.getElementById('cyrogem-desire-display-span').textContent = activeModifiers[newDesireTrait]
  346. // Does this target specific skills
  347. //console.log(newDesireTrait)
  348. if (skillSpecificModifiers.includes(newDesireTrait)){
  349. console.log('more info needed')
  350. document.getElementById('cyrogem-desire-extra').className = ""
  351. } else {
  352. document.getElementById('cyrogem-desire-extra').className = "d-none"
  353. }
  354. }
  355.  
  356. /**
  357. * Set the desired Skill
  358. * @param {*} index index of the skill from skillName
  359. */
  360. function CyrogemDesiredSkill(index){
  361. //console.log(index)
  362. newDesireSkill = index
  363. document.getElementById('cyrogem-desire-extra-span').textContent = skillName[newDesireSkill]
  364. }
  365.  
  366. /**
  367. * Set the desired value to the input field value
  368. */
  369. function CyrogemDesiredValue(){
  370. const valueHTML = document.getElementById('cyrogem-desire-value')
  371. newDesireValue = valueHTML.value
  372. document.getElementById('cyrogem-desire-display-value').textContent = newDesireValue
  373. }
  374.  
  375. /**
  376. * Set the desired tries to the input field value
  377. */
  378. function CyrogemDesiredTries(){
  379. const valueHTML = document.getElementById('cyrogem-iterations')
  380. iterations = valueHTML.value
  381. document.getElementById('cyrogem-iterations-display').textContent = iterations
  382. CyrogemUpdatePrediction()
  383. }
  384.  
  385. /**
  386. * Choose an equipment slot to roll for
  387. * @param {*} slot index of slot
  388. */
  389. function CyrogemSelectSlot(slot){
  390. newDesireSlot = slot
  391. let slotName = 'Slot'
  392. switch(slot){
  393. case 0: slotName = 'Helmet'; break;
  394. case 1: slotName = 'Body'; break;
  395. case 2: slotName = 'Legs'; break;
  396. case 3: slotName = 'Boots'; break;
  397. case 4: slotName = 'Weapon'; break;
  398. case 5: slotName = 'Shield'; break;
  399. case 6: slotName = 'Amulet'; break;
  400. case 7: slotName = 'Ring'; break;
  401. case 8: slotName = 'Gloves'; break;
  402. case 9: slotName = 'Quiver'; break;
  403. case 10: slotName = 'Cape'; break;
  404. }
  405. document.getElementById('cyrogem-desire-slot-span').textContent = slotName
  406. CyrogemUpdatePrediction()
  407. }
  408.  
  409. function CyrogemSkipModifierInDesireList(modifier) {
  410. if (modifier.includes('aprilFools')) {
  411. return true;
  412. }
  413.  
  414. let decreaseGood = false;
  415. if (modifier.includes('PlayerAttackSpeed') || modifier.includes('MonsterRespawnTimer') || modifier.includes('SkillInterval')) {
  416. decreaseGood = true;
  417. };
  418.  
  419. if (decreaseGood) {
  420. return modifier.includes('increase');
  421. } else {
  422. return modifier.includes('decrease');
  423. }
  424. }
  425.  
  426. /**
  427. * Load the tool, setup references, inject HTML
  428. */
  429. function CyrogemLoadCorruptionHelper () {
  430. let bannedModifiers = ["golbinRaidWaveSkipCostReduction", "golbinRaidIncreasedMinimumFood", "golbinRaidIncreasedMaximumAmmo", "golbinRaidIncreasedMaximumRunes", "golbinRaidPrayerUnlocked", "golbinRaidIncreasedPrayerLevel", "golbinRaidIncreasedPrayerPointsStart", "golbinRaidIncreasedPrayerPointsWave", "golbinRaidPassiveSlotUnlocked", "golbinRaidIncreasedStartingRuneCount", "golbinRaidStartingWeapon", "freeBonfires", "autoSlayerUnlocked", "increasedEquipmentSets", "dungeonEquipmentSwapping", "increasedTreeCutLimit", "increasedAttackRolls", "decreasedAttackRolls", "increasedBankSpaceShop", "decreasedBankSpaceShop", "increasedGPFromSales", "decreasedGPFromSales", ];
  431. activeModifiers = [];
  432. for (let i = 0; i < Object.keys(playerModifiersTemplate).length; i++) {
  433. if (!bannedModifiers.includes(Object.keys(playerModifiersTemplate)[i]))
  434. activeModifiers.push(Object.keys(playerModifiersTemplate)[i]);
  435. }
  436.  
  437. // Setup the entire block
  438. let playerDesiresHTML =
  439. '<div class="block block-rounded block-link-pop border-top border-info border-4x row no-gutters">'
  440.  
  441. // First Column
  442. playerDesiresHTML +=
  443. '<div class="col-sm-6 col-lg-4"><div class=block-content>'
  444. // Setup Desire Dropdown
  445. playerDesiresHTML +=
  446. '<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>' +
  447. '<div class="dropdown-menu font-size-sm" aria-labelledby="cyrogem-desire-dropdown" style="max-height: 800px; overflow-y: scroll;">'
  448. for (let i = 0; i < activeModifiers.length; i++){
  449. if (CyrogemSkipModifierInDesireList(activeModifiers[i])) continue;
  450. playerDesiresHTML += '<a class="dropdown-item" id="cyrogemDesiredTrait' + i + '" style="text-transform: capitalize;">' + activeModifiers[i] + '</a>'
  451. }
  452. playerDesiresHTML += '</div></div>' +
  453. '<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>'
  454. // Oh god we have to add another check for specific skill ones like "increasedSmithingMasteryXP"
  455. playerDesiresHTML +=
  456. '<div class="d-none" id="cyrogem-desire-extra">' +
  457. // We need a new dropdown for all the skills
  458. '<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>' +
  459. '<div class="dropdown-menu font-size-sm" aria-labelledby="cyrogem-desire-extra-dropdown">'
  460. for (let i = 0; i < skillName.length; i++){
  461. playerDesiresHTML += '<a class="dropdown-item" id="cyrogemDesiredSkill' + i + '" style="text-transform: capitalize;">' + skillName[i] + '</a>'
  462. }
  463. playerDesiresHTML += '</div></div>' +
  464. '<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>' +
  465. '</div>'
  466.  
  467. // What value do you want
  468. playerDesiresHTML += '<div class="col-12"><input type="number" class="form-control m-1" id="cyrogem-desire-value" placeholder="0"></div>' +
  469. '<span class="font-w400 font-size-sm text-combat-smoke ml-2">Minimum Level: <span id="cyrogem-desire-display-value">Enter above</span></span>'
  470.  
  471. // What slot are we changing
  472. playerDesiresHTML +=
  473. '<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>'
  474.  
  475. // Close the content block and column div
  476. playerDesiresHTML += '</div></div>'
  477.  
  478.  
  479. // Second column
  480. playerDesiresHTML += '<div class="col-sm-3"><div class=block-content>' +
  481. '<div class="col-12"><input type="number" class="form-control m-1" id="cyrogem-iterations" placeholder="0"></div>' +
  482. '<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>'
  483.  
  484. 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="">' +
  485. 'Slot to Roll For</button><div class="dropdown-menu font-size-sm" aria-labelledby="cyrogem-slot-dropdown">' +
  486. '<a class="dropdown-item" id="cyrogemSelectSlot0">Helmet</a>' +
  487. '<a class="dropdown-item" id="cyrogemSelectSlot1">Body</a>' +
  488. '<a class="dropdown-item" id="cyrogemSelectSlot2">Legs</a>' +
  489. '<a class="dropdown-item" id="cyrogemSelectSlot3">Boots</a>' +
  490. '<a class="dropdown-item" id="cyrogemSelectSlot4">Weapon</a>' +
  491. '<a class="dropdown-item" id="cyrogemSelectSlot5">Shield</a>' +
  492. '<a class="dropdown-item" id="cyrogemSelectSlot6">Amulet</a>' +
  493. '<a class="dropdown-item" id="cyrogemSelectSlot7">Ring</a>' +
  494. '<a class="dropdown-item" id="cyrogemSelectSlot8">Gloves</a>' +
  495. '<a class="dropdown-item" id="cyrogemSelectSlot9">Quiver</a>' +
  496. '<a class="dropdown-item" id="cyrogemSelectSlot10">Cape</a>' +
  497. '</div></div>'+
  498. '<span class="font-w400 font-size-sm text-combat-smoke ml-2">Slot: <span id="cyrogem-desire-slot-span">Select One</span></span>'
  499.  
  500. // Close the block and column div
  501. playerDesiresHTML += '</div></div>'
  502.  
  503.  
  504. // Third column
  505. playerDesiresHTML += '<div class="col-md-5"><div class=block-content>'
  506.  
  507. // Display current wishes
  508. 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>' +
  509. '<div class="text-center" id="cyrogem-current-desires"></div>'
  510.  
  511. // Close the block and column div
  512. playerDesiresHTML += '</div></div>'
  513.  
  514. // NEW ROW
  515. playerDesiresHTML += '<div class="col-12"><div class="block-content text-center">'
  516.  
  517. // Display aggregate info
  518. playerDesiresHTML += '<div class="col-md-10" id="cyrogem-predictive-display"></div>' +
  519. '<div class="col-md-2">' + // Button to roll
  520. '<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>'
  521. // Close the column, row, and box div
  522. playerDesiresHTML += '</div></div></div>'
  523.  
  524. //document.getElementById('aprilfools2021-container').insertAdjacentHTML('afterbegin', playerDesiresHTML)
  525. playerDesiresHTML += document.getElementById('aprilfools2021-container').innerHTML
  526. document.getElementById('aprilfools2021-container').innerHTML = playerDesiresHTML
  527.  
  528.  
  529. // Setup trait links
  530. for(let i = 0; i < activeModifiers.length; i++){
  531. //console.log(i)
  532. let option = document.getElementById('cyrogemDesiredTrait' + i)
  533. if(option !== null){
  534. option.addEventListener("click", () => CyrogemDesiredTrait(i))
  535. }
  536. }
  537. // Setup skill links
  538. for(let i = 0; i < skillName.length; i++){
  539. let option = document.getElementById('cyrogemDesiredSkill' + i)
  540. if(option !== null){
  541. option.addEventListener("click", () => CyrogemDesiredSkill(i))
  542. }
  543. }
  544. // Setup slot links
  545. for(let i = 0; i <= 10; i++){
  546. //console.log(i)
  547. document.getElementById('cyrogemSelectSlot' + i).addEventListener("click", () => CyrogemSelectSlot(i))
  548. }
  549. // Setup value link
  550. document.getElementById('cyrogem-desire-value').addEventListener("input", () => CyrogemDesiredValue())
  551. document.getElementById('cyrogem-desire-value').addEventListener("change", () => CyrogemDesiredValue())
  552. // Setup quantity link
  553. document.getElementById('cyrogem-iterations').addEventListener("input", () => CyrogemDesiredTries())
  554. // Setup roll button
  555. document.getElementById('cyrogem-roll-button').addEventListener("click", () => CyrogemRollCorruption())
  556. // Setup desire button
  557. document.getElementById('cyrogem-add-desire').addEventListener("click", () => CyrogemAddDesire())
  558.  
  559. CyrogemUpdatePrediction()
  560. }
  561.  
  562. /**
  563. * Inject after page loads
  564. */
  565. (function () {
  566. function loadScript() {
  567. //console.log(window.isLoaded + ' ' + !window.currentlyCatchingUp);// + ' ' + (typeof unsafeWindow !== 'undefined') ? ' ' + unsafeWindow.isLoaded + ' ' + !unsafeWindow.currentlyCatchingUp : '')
  568. if ((window.isLoaded && !window.currentlyCatchingUp)
  569. || (typeof unsafeWindow !== 'undefined' && unsafeWindow.isLoaded && !unsafeWindow.currentlyCatchingUp)) {
  570. // Only load script after game has opened
  571. clearInterval(scriptLoader);
  572. document.body.insertAdjacentHTML('beforeend', '<template id="cyrogem-button-template"><button class="btn btn-dark m-1" aria-label="">Button</button></template>')
  573. CyrogemLoadCorruptionHelper();
  574. }
  575. }
  576.  
  577. const scriptLoader = setInterval(loadScript, 200);
  578. })();
  579.  
  580. // Melvor backend code copied for quick reference
  581. /*
  582. function rollRandomModifiers(count=3, key, equipmentSlot=0) {
  583. if (key === "equipment") {
  584. if (randomModifiers.equipment[equipmentSlot] === undefined)
  585. randomModifiers.equipment[equipmentSlot] = {};
  586. deleteKeysFromObject(randomModifiers.equipment[equipmentSlot]);
  587. }
  588. let bannedModifiers = ["golbinRaidWaveSkipCostReduction", "golbinRaidIncreasedMinimumFood", "golbinRaidIncreasedMaximumAmmo", "golbinRaidIncreasedMaximumRunes", "golbinRaidPrayerUnlocked", "golbinRaidIncreasedPrayerLevel", "golbinRaidIncreasedPrayerPointsStart", "golbinRaidIncreasedPrayerPointsWave", "golbinRaidPassiveSlotUnlocked", "golbinRaidIncreasedStartingRuneCount", "golbinRaidStartingWeapon", "freeBonfires", "autoSlayerUnlocked", "increasedEquipmentSets", "dungeonEquipmentSwapping", "increasedTreeCutLimit", "increasedAttackRolls", "decreasedAttackRolls", "increasedBankSpaceShop", "decreasedBankSpaceShop", "increasedGPFromSales", "decreasedGPFromSales", ];
  589. let activeModifiers = [];
  590. for (let i = 0; i < Object.keys(playerModifiersTemplate).length; i++) {
  591. if (!bannedModifiers.includes(Object.keys(playerModifiersTemplate)[i]))
  592. activeModifiers.push(Object.keys(playerModifiersTemplate)[i]);
  593. }
  594. let rng = [];
  595. for (let i = 0; i < count; i++) {
  596. let rngMod = Math.floor(Math.random() * activeModifiers.length);
  597. let value;
  598. let maxValue = getRandomModifierMaxValue(count);
  599. if (playerModifiersTemplate[activeModifiers[rngMod]].length)
  600. // ------------ value is skill index 0, value index 1 ----------------------------------------------------------------------------------------------------------------------
  601. value = [[Math.floor(Math.random() * 21), Math.floor(Math.random() * maxValue)]];
  602. else
  603. value = Math.floor(Math.random() * maxValue);
  604. if ((activeModifiers[rngMod] === "increasedMaxHitFlat" || activeModifiers[rngMod] === "increasedMaxHitpoints") && value > 10)
  605. value = 10;
  606. if ((activeModifiers[rngMod] === "decreasedMaxHitFlat" || activeModifiers[rngMod] === "decreasedMaxHitpoints") && value > 10)
  607. value = 10;
  608. rng.push({
  609. modifier: activeModifiers[rngMod],
  610. value: value
  611. });
  612. if (key === "equipment")
  613. randomModifiers.equipment[equipmentSlot][activeModifiers[rngMod]] = value;
  614. }
  615. return rng;
  616. }
  617.  
  618. function getEquipmentCorruption2(equipmentSlot) {
  619. let cost = getRandomModifierCost(equipmentSlot);
  620. if (gp >= cost && equippedItems[equipmentSlot] > 0) {
  621. gp -= cost;
  622. updateGP();
  623. let tier = getRandomModifierTier(equipmentSlot);
  624. let chanceToDestroy = getRandomModifiersDestroyChance(tier);
  625. if (rollPercentage(chanceToDestroy)) {
  626. let qty = getItemQtyRandomModifier(equippedItems[equipmentSlot]);
  627. if (qty[0] > 1) {
  628. if (equipmentSlot === CONSTANTS.equipmentSlot.Quiver && ammo > 1) {
  629. ammo--;
  630. equipmentSets[selectedEquipmentSet].ammo--;
  631. updateAmmo();
  632. } else
  633. updateItemInBank(qty[1], equippedItems[equipmentSlot], -1);
  634. } else {
  635. equippedItems[equipmentSlot] = 0;
  636. equipmentSets[selectedEquipmentSet].equipment[equipmentSlot] = 0;
  637. setEquipmentSet(selectedEquipmentSet);
  638. }
  639. updateRandomModifierInfo(equipmentSlot);
  640. notifyPlayer(CONSTANTS.skill.Attack, "Your item was destroyed :(", "danger");
  641. } else {
  642. let mods = rollRandomModifiers(tier, "equipment", equipmentSlot);
  643. updateHTMLRandomMod(equipmentSlot, mods);
  644. }
  645. }
  646. }
  647. function loadCorruption() {
  648. for (let i = 0; i < Object.keys(randomModifiers.equipment).length; i++) {
  649. let html = `<h5 class="font-w600 font-size-sm mb-2">Current Modifiers:</h5>`;
  650. for (let j = 0; j < Object.keys(randomModifiers.equipment[Object.keys(randomModifiers.equipment)[i]]).length; j++) {
  651. 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]]);
  652. html += `<h5 class="font-w400 font-size-sm mb-1 ${modifier[1]}">${modifier[0]}</h5>`;
  653. }
  654. $("#corruption-equipment-slot-" + Object.keys(randomModifiers.equipment)[i]).html(html);
  655. }
  656. }
  657. function updateHTMLRandomMod(equipmentSlot, mods) {
  658. let html = `<h5 class="font-w600 font-size-sm mb-2">Current Modifiers:</h5>`;
  659. for (let i = 0; i < mods.length; i++) {
  660. if (mods[i].value.length)
  661. modifier = printPlayerModifier(mods[i].modifier, mods[i].value[0]);
  662. else
  663. modifier = printPlayerModifier(mods[i].modifier, mods[i].value);
  664. html += `<h5 class="font-w400 font-size-sm mb-1 ${modifier[1]}">${modifier[0]}</h5>`;
  665. }
  666. $("#corruption-equipment-slot-" + equipmentSlot).html(html);
  667. updatePlayerStats();
  668. }
  669. function getRandomModifiersDestroyChance(tier) {
  670. let chance = 0;
  671. if (tier >= 4)
  672. chance = 10;
  673. else if (tier >= 3)
  674. chance = 20;
  675. else if (tier >= 2)
  676. chance = 30;
  677. else if (tier >= 1)
  678. chance = 40;
  679. return chance;
  680. }
  681. function getRandomModifierMaxValue(tier) {
  682. let value = 0;
  683. if (tier >= 4)
  684. value = 100;
  685. else if (tier >= 3)
  686. value = 76;
  687. else if (tier >= 2)
  688. value = 51;
  689. else if (tier >= 1)
  690. value = 31;
  691. return value;
  692. }
  693. function getRandomModifierCost(equipmentSlot) {
  694. let cost = 0;
  695. if (equippedItems[equipmentSlot] <= 0)
  696. return cost;
  697. cost = items[equippedItems[equipmentSlot]].sellsFor;
  698. return cost;
  699. }
  700. function getRandomModifierTier(equipmentSlot) {
  701. let tier = 0;
  702. if (equippedItems[equipmentSlot] <= 0)
  703. return tier;
  704. if (items[equippedItems[equipmentSlot]].sellsFor >= 400000)
  705. tier = 4;
  706. else if (items[equippedItems[equipmentSlot]].sellsFor >= 10000)
  707. tier = 3;
  708. else if (items[equippedItems[equipmentSlot]].sellsFor >= 200)
  709. tier = 2;
  710. else
  711. tier = 1;
  712. return tier;
  713. }
  714. function updateRandomModifierInfo(equipmentSlot) {
  715. if (equippedItems[equipmentSlot] > 0) {
  716. let cost = getRandomModifierCost(equipmentSlot);
  717. let tier = getRandomModifierTier(equipmentSlot);
  718. let qty = getItemQtyRandomModifier(equippedItems[equipmentSlot]);
  719. $("#corruption-equipment-slot-" + equipmentSlot + "-img").attr("src", items[equippedItems[equipmentSlot]].media);
  720. $("#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)}`);
  721. } else {
  722. $("#corruption-equipment-slot-" + equipmentSlot + "-img").attr("src", "assets/media/bank/" + emptyGear[equipmentSlot] + ".svg");
  723. $("#corruption-equipment-slot-" + equipmentSlot + "-info").html(`Equip an item pls`);
  724. }
  725. }
  726. function getItemQtyRandomModifier(itemID) {
  727. let qty = 1;
  728. let bankID = getBankId(itemID);
  729. if (bankID >= 0)
  730. qty += bank[bankID].qty;
  731. if (items[itemID].equipmentSlot === CONSTANTS.equipmentSlot.Quiver)
  732. qty += ammo - 1;
  733. return [qty, bankID];
  734. }
  735. function deleteKeysFromObject(object) {
  736. Object.keys(object).forEach((el)=>{
  737. delete object[el];
  738. }
  739. );
  740. }
  741.  
  742. */

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址