您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Agility course planner that allows you to filter agility obstacles based on skill of interest.
// ==UserScript== // @name Melvor Obstacle Filter // @namespace http://tampermonkey.net/ // @version 0.1.8 // @description Agility course planner that allows you to filter agility obstacles based on skill of interest. // @author GMiclotte // @include https://melvoridle.com/* // @include https://*.melvoridle.com/* // @exclude https://melvoridle.com/index.php // @exclude https://*.melvoridle.com/index.php // @exclude https://wiki.melvoridle.com/* // @exclude https://*.wiki.melvoridle.com/* // @inject-into page // @noframes // @grant none // ==/UserScript== ((main) => { const script = document.createElement('script'); script.textContent = `try { (${main})(); } catch (e) { console.log(e); }`; document.body.appendChild(script).parentNode.removeChild(script); })(() => { function startObstacleFilter() { if (window.obstacleFilter !== undefined) { console.error('Obstacle Filter is already loaded!'); } else { createObstacleFilter(); // load after 5s to give Melvor Show Modifiers time to load setTimeout(loadObstacleFilter, 200); } } function createObstacleFilter() { window.obstacleFilter = {}; obstacleFilter.log = function (...args) { console.log('Melvor Obstacle Filter:', ...args) } obstacleFilter.loadTries = 0; obstacleFilter.courseData = { course: Array(10).fill(-1), courseMastery: Array(10).fill(false), pillar: -1, } obstacleFilter.createMenu = () => { // create show modifiers instance obstacleFilter.showModifiers = new MICSR.ShowModifiers('', 'Melvor Obstacle Filter'); // set names obstacleFilter.modalID = 'obstacleFilterModal'; obstacleFilter.menuItemID = 'obstacleFilterButton'; // clean up in case elements already exist MICSR.destroyMenu(obstacleFilter.menuItemID, obstacleFilter.modalID); // create wrapper obstacleFilter.content = document.createElement('div'); obstacleFilter.content.className = 'mcsTabContent'; obstacleFilter.content.style.flexWrap = 'nowrap'; // create modal and access point obstacleFilter.modal = MICSR.addModal('Obstacle Filter', obstacleFilter.modalID, [obstacleFilter.content]); let style = document.createElement("style"); document.head.appendChild(style); let sheet = style.sheet; sheet.insertRule('#obstacleFilterModal.show { display: flex !important; }') sheet.insertRule('#obstacleFilterModal .modal-dialog { max-width: 95%; display: inline-block; }') MICSR.addMenuItem('Obstacle Filter', 'assets/media/main/stamina.svg', obstacleFilter.menuItemID, obstacleFilter.modalID); // add filter card obstacleFilter.addFilterCard(); // log obstacleFilter.log('added settings menu!') } obstacleFilter.addFilterCard = () => { obstacleFilter.filterCard = new MICSR.Card(obstacleFilter.content, '', '150px', true); obstacleFilter.filterCard.addButton('Import Agility Course', () => { const chosenAgilityObstacles = []; game.agility.builtObstacles.forEach(x => chosenAgilityObstacles.push(x.id)); const agilityPassivePillarActive = game.agility.builtPassivePillar === undefined ? -1 : game.agility.builtPassivePillar.id; obstacleFilter.agilityCourse.importAgilityCourse( chosenAgilityObstacles, MASTERY[Skills.Agility].xp.map(x => x > 13034431), agilityPassivePillarActive, ); }); const filterData = [ [ {tag: 'all', text: 'All', media: 'assets/media/main/completion_log.svg'}, // {tag: 'golbinRaid', text: 'Golbin Raid', media: 'assets/media/main/raid_coins.svg'}, {tag: 'combat', text: 'Combat', media: 'assets/media/skills/combat/combat.svg'}, {tag: 'melee', text: 'Melee', media: 'assets/media/skills/attack/attack.svg'}, {tag: 'ranged', text: 'Ranged', media: 'assets/media/skills/ranged/ranged.svg'}, {tag: 'magic', text: 'Combat Magic', media: 'assets/media/skills/combat/spellbook.svg'}, {tag: 'slayer', text: 'Slayer', media: 'assets/media/skills/slayer/slayer.svg'}, ], obstacleFilter.showModifiers.gatheringSkills.map(skill => { return { tag: skill, text: skill, media: `assets/media/skills/${skill.toLowerCase()}/${skill.toLowerCase()}.svg`, } }), [ ...obstacleFilter.showModifiers.productionSkills.map(skill => { return { tag: skill, text: skill, media: `assets/media/skills/${skill.toLowerCase()}/${skill.toLowerCase()}.svg`, } }), {tag: 'altMagic', text: 'Alt. Magic', media: 'assets/media/skills/magic/magic.svg'}, ], ]; filterData.forEach(row => { const container = obstacleFilter.filterCard.createCCContainer(); container.style.display = 'block'; container.style.flexWrap = 'nowrap'; row.forEach(data => { const id = `Obstacle Filter ${data.tag} Button` const callback = () => { const previousButton = document.getElementById(`Obstacle Filter ${obstacleFilter.filter.tag} Button`); obstacleFilter.unselectButton(previousButton); obstacleFilter.createCourse({...data}); const button = document.getElementById(`Obstacle Filter ${obstacleFilter.filter.tag} Button`); obstacleFilter.selectButton(button); }; const button = obstacleFilter.filterCard.createImageButton(data.media, id, callback, 'Small', data.text); button.id = id; container.appendChild(button); }); obstacleFilter.filterCard.container.appendChild(container); }); const modifierDiv = document.createElement('div'); modifierDiv.id = 'show-obstacle-modifiers'; obstacleFilter.filterCard.container.appendChild(modifierDiv); // collapse filterData obstacleFilter.filterData = [...filterData[0], ...filterData[1], ...filterData[2]]; //create course card obstacleFilter.createCourse(obstacleFilter.filterData[0]); const button = document.getElementById(`Obstacle Filter ${obstacleFilter.filter.tag} Button`); obstacleFilter.selectButton(button); } obstacleFilter.createCourse = (filter) => { obstacleFilter.filter = filter; if (!obstacleFilter.courseCard) { obstacleFilter.courseCard = new MICSR.Card(obstacleFilter.content, '', '150px', true); obstacleFilter.agilityCourse = new MICSR.AgilityCourse( obstacleFilter, obstacleFilter.courseData, obstacleFilter.filterData, ); } else { obstacleFilter.courseCard.clearContainer(); } obstacleFilter.agilityCourse.createAgilityCourseContainer(obstacleFilter.courseCard, filter); // finalize tooltips const tippyOptions = {allowHTML: true, animation: false, hideOnClick: false}; obstacleFilter.tippyInstances = tippy('#obstacleFilterModal [data-tippy-content]', tippyOptions); obstacleFilter.tippySingleton = tippy.createSingleton(obstacleFilter.tippyInstances, {delay: [0, 200], ...tippyOptions}); // select current setup const masteryMap = {}; obstacleFilter.courseData.courseMastery.forEach((mastery, category) => { if (!mastery) { return; } masteryMap[obstacleFilter.courseData.course[category]] = obstacleFilter.courseData.course[category] !== -1; }); obstacleFilter.agilityCourse.importAgilityCourse([...obstacleFilter.courseData.course], masteryMap, obstacleFilter.courseData.pillar); obstacleFilter.agilityCourseCallback(); } obstacleFilter.agilityCourseCallback = () => { obstacleFilter.modifiers = new PlayerModifiers(); const course = obstacleFilter.courseData.course; const courseMastery = obstacleFilter.courseData.courseMastery; const pillar = obstacleFilter.courseData.pillar; // compute agility modifiers MICSR.addAgilityModifiers(course, courseMastery, pillar, obstacleFilter.modifiers) // print $('#show-obstacle-modifiers').replaceWith( obstacleFilter.showModifiers.printRelevantModifiersHtml( obstacleFilter.modifiers, `${obstacleFilter.filter.text} Obstacle Modifiers`, obstacleFilter.filter.tag, 'show-obstacle-modifiers', ), ); }; obstacleFilter.selectButton = (button) => { button.classList.add('btn-primary'); button.classList.remove('btn-outline-dark'); } obstacleFilter.unselectButton = (button) => { button.classList.remove('btn-primary'); button.classList.add('btn-outline-dark'); } } function loadObstacleFilter() { // Loading script if (obstacleFilter.loadTries === 0) { obstacleFilter.log('loading...'); } // check requirements obstacleFilter.loadTries++ if (!checkRequirements(obstacleFilter.loadTries === 10)) { if (obstacleFilter.loadTries < 10) { setTimeout(loadObstacleFilter, 200); } return; } // create menu obstacleFilter.createMenu(); } function checkRequirements(print = false) { let requirementsMet = true; const reqMicsrMajorVersion = 1; const reqMicsrMinorVersion = 6; const reqMicsrPatchVersion = 4; const reqMicsrPreReleaseVersion = undefined; let reqMicsrversion = `v${reqMicsrMajorVersion}.${reqMicsrMinorVersion}.${reqMicsrPatchVersion}`; if (reqMicsrPreReleaseVersion !== undefined) { reqMicsrversion = `${reqMicsrversion}-${reqMicsrPreReleaseVersion}`; } if (window.MICSR === undefined || !MICSR.versionCheck(false, reqMicsrMajorVersion, reqMicsrMinorVersion, reqMicsrPatchVersion, reqMicsrPreReleaseVersion)) { if (print) { obstacleFilter.log('Failed to load Melvor Obstacle Filter! ' + `\nMelvor Obstacle Filter requires "Melvor Idle Combat Simulator Reloaded" ${reqMicsrversion} or later.` + '\nFind it here: https://github.com/visua0/Melvor-Idle-Combat-Simulator-Reloaded'); } requirementsMet = false; } return requirementsMet; } function loadScript() { if (typeof confirmedLoaded !== typeof undefined && confirmedLoaded) { // Only load script after game has opened clearInterval(scriptLoader); startObstacleFilter(); } } const scriptLoader = setInterval(loadScript, 200); });