Idlescape - Snippet

collections of snippets

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

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

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         Idlescape - Snippet
// @namespace    test
// @version      0.12
// @description  collections of snippets
// @author       snefrukai
// @match        *://*.idlescape.com/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=idlescape.com
// @grant        none
// @license MIT
// ==/UserScript==

;(function () {
  ;('use strict')

  // ========================================================================== //
  // * setDefaultPage
  // ========================================================================== //

  // Default Page on Load
  // openDefaultPage(setDefaultPage[0]) // ! test

  var setDefaultPage = [
    // ! change and comment out the default page
    'active skill',
    // 'Fighting',
    // 'Mining',
    // 'Foraging',
    // 'Fishing',
    // 'Smithing',
    // 'Farming',
    // 'Cooking',
    // 'Crafting',
    // 'Runecrafting',
    // 'Enchanting',
  ]

  function openDefaultPage(setDefaultPage = 'active skill') {
    var leftNav = document.getElementsByClassName('drawer-item-left')
    // console.log(leftNav)

    var idlingPage = 'Attack' // set idling page (no action)
    var defaultPage = ''

    // get default page from setting
    if (setDefaultPage != 'active skill') defaultPage = setDefaultPage
    else {
      // get action
      var foo = document.getElementsByClassName('status-action')[0].innerText
      var getAction = foo.match(/[A-z]+/)[0]
      if (getAction == 'Fighting') defaultPage = 'Attack'
      else if (getAction == 'Idling') defaultPage = idlingPage
      else defaultPage = getAction
    }

    // check default page w left nav. if hit, click
    for (let i = 0; i < leftNav.length; i++) {
      let sample = leftNav[i].textContent
      // console.log(sample)
      if (sample == defaultPage) {
        leftNav[i].click()
        console.log('default page loaded:', defaultPage)
      }
    }
  }

  // ========================================================================== //
  // * shortcuts
  // ========================================================================== //

  // shortcuts() // ! test}

  function shortcuts(params) {
    // ========================================================================== //
    // close popups

    var popupSelector = '.MuiDialog-container'

    // when press 'Esc'
    document.onkeydown = function (e) {
      var closePopup = e.key === 'Escape' || e.key === 'Esc'
      if (closePopup) if (checkExist(popupSelector)) clickClose()
    }

    // when click outside of popup box
    document.querySelector('#root').onclick = function (e) {
      // only when popup is shown, only add click to popup
      if (checkExist(popupSelector)) {
        var popup = document.querySelectorAll(popupSelector)[0]
        popup.onclick = function (e) {
          // document.querySelector('#root').onclick = function (e) {
          var isClosest = e.target.closest('.MuiPaper-root') // popupBox
          if (!isClosest) clickClose()
        }
      }
    }

    function checkExist(selector) {
      var tar = document.querySelectorAll(selector)
      var isExist = tar.length !== 0
      // if (isExist) console.log(selector, 'exist') // ! test
      return isExist
    }

    function clickClose() {
      foo = '.close-dialog-button'
      if (checkExist(foo)) {
        document.querySelectorAll(foo)[0].click()
      }
    }
  }

// * upgrade selected item by item ID at set interval
// window.upgradeItem_repeat = function (itemID, fn, count, minute) {
//   function upgradedItemID(itemID) {
//     return items[itemID].trimmedItemID
//   }

//   // function upgrade(itemID, qty) {
//   //   confirmUpgradeItem(itemID, upgradedItemID(itemID), qty)
//   // }

//   // ! func name 'upgradeItemAll' could cause freeze in tampermonkley
//   function upgradeAll(itemID) {
//     for (let k = 0; k < itemID.length; k++) {
//       confirmUpgradeItemAll(itemID[k], upgradedItemID(itemID[k]))
//       console.log('upgrading item ID', itemID[k])
//     }
//   }

//   function repeat(itemID, fn = upgradeAll, count = 10000, minute = 5) {
//     let i = 0
//     function recur() {
//       fn(itemID)
//       i += 1
//       console.log('upgraded', i, 'times')
//       setTimeout(function () {
//         if (i < count) {
//           recur()
//         }
//       }, 1000 * 60 * minute)
//     }
//     recur()
//   }

//   repeat(
//     (itemID = [
//       768, // air shard
//       769, // water ...
//       770, // earth ...
//       771, // fire ...
//       // 890, // mys stone
//       // 886, // mys stone charge
//     ])
//   )
// }

// * hide no gathering account's skills
window.checkNoGathering = function () {
  var noGatheringSkills = [
    0, // woodcutting
    1, // mining
    2, // firemaking
    4, // fishing
    10, // thiving
    20, // agility
    22, // astrology
  ]

  if (username && username.includes('NG')) {
    console.log('Detected "No Gathering".')

    noGatheringSkills.forEach((skill) => {
      $('#nav-skill-tooltip-' + skill.toString()).remove()

      // in-game func
      if (skillsUnlocked[skill] != false) {
        skillsUnlocked[skill] = false
        forceStopSkill(skill)
        if (
          PAGES[currentPage].skillID !== undefined &&
          PAGES[currentPage].skillID === skill
        )
          changePage(Pages.Bank)
        if (defaultPageOnLoad === skill)
          changeSetting(2, Pages.Bank, false, false)
        updateSkillWindow(skill) // update ui
        updateSkillLevelCap()
      }
    })

    console.log('"No Gathering" skills locked and hidden.')
  }
}

// * eat to full hp
window.autoEatToFull_repeat = function (sec = 1) {
  let hp = {
    current: 0,
    max: 1,
    food: 0,
  }
  let hpSelector = {
    current: '#combat-player-hitpoints-current',
    max: '#combat-player-hitpoints-max',
  }
  var activeFoodSelector = '#combat-food-container .text-combat-smoke'

  function autoEatToFull(params) {
    var hpSelectorArr = Object.entries(hpSelector)
    for (let i = 0; i < hpSelectorArr.length; i++) {
      let str = $(hpSelectorArr[i][1])[0].textContent
      hp[hpSelectorArr[i][0]] = getInt(str)
      // console.log(str)
    }

    var foodSrc = $(activeFoodSelector)[0].childNodes[1]['src']
    var foodName = foodSrc.match(/\w+\.\w+$/g)[0] // match return array
    hp['food'] = getInt($(activeFoodSelector)[0].childNodes[2].textContent)
    // console.log(foodName)

    var hpLoss = hp['max'] - hp['current']
    var eatFoodAmount = Math.floor(hpLoss / hp['food'])
    if (hpLoss > 0) {
      for (let i = 0; i < eatFoodAmount; i++) {
        $('#combat-footer-minibar-eat-btn').click()
      }
      console.log('hp loss:', hpLoss, ', ate *', eatFoodAmount, foodName)
    } else {
      console.log('hp full')
    }
  }

  function getInt(str) {
    var numb = Number(str.replace(/\D+/g, ''))
    return numb
  }

  function repeat(fn = autoEatToFull, count = 60 * 24, sec = 10) {
    let i = 0
    function recur() {
      fn()
      i += 1
      console.log('auto eat', i, 'times, next check in', sec, 'sec')
      setTimeout(function () {
        if (i < count) {
          recur()
        }
      }, 1000 * sec)
    }
    recur()
  }
  repeat(autoEatToFull, (count = (3600 / sec) * 24 * 10), (sec = sec))
}

// * add mastery pool xp to skill after overnight
window.addPoolXPForCount = function (skillID, count, sec = 30) {
  var i = 0
  var checkPool = setInterval(() => {
    checkPoint = parseFloat(
      document.querySelector('.mastery-pool-xp-progress-15').textContent
    )
    // if (checkPoint < 95.5) {
    addMasteryXPToPool(skillID, 4046897, false, true)
    i = i + 1
    console.log('add pool xp:', Skills[skillID], i, 'times')
    if (i == count) {
      clearInterval(checkPool)
      console.log('add pool xp: finished')
    }
    // }
  }, 1000 * sec)
}

// * get current gears
// getCurrentGears(3) // ! test
window.getCurrentGears = function (iSet = player.selectedEquipmentSet) {
// function getCurrentGears(iSet = player.selectedEquipmentSet) {
  var arr = []
  player.equipmentSets[iSet].slotArray.forEach((e) => {
    const s = ActiveSkills[game.activeSkill].toLowerCase()
    activeSkillNew = s[0].toUpperCase() + s.slice(1)
    const itemID = e.item.id
    const item = Items[itemID]
    const nonCombatUniversal = [
      'Crown_of_Rhaelyx',
      'Clue_Chasers_Insignia',
      'Aorpheats_Signet_Ring',
      'Ring_Of_Wealth',
      'Max_Skillcape',
      'Ancient_Ring_Of_Mastery', // passive
    ].includes(item)

    // console.log(itemID, item, nonCombatUniversal)
    if (itemID != -1 && !nonCombatUniversal) {
      arr.push(Items[itemID])
    }
  })
  console.log(`${activeSkillNew}\ncurrentGears:`, arr)
}

// ========================================================================== //
// * folked from Action Queue
window.actionQueue = function (params) {
  // setAction('Build Agility Obstacle', 1, 'Cargo Net')()
  window.setAction = function (
    actionCategory,
    actionName,
    skillItem,
    skillItem2,
    qty
  ) {
    qty = parseInt(qty, 10)
    const itemID = items.findIndex((a) => a.name == actionName)
    switch (actionCategory) {
      case 'Start Skill':
        return setSkillAction(actionName, skillItem, skillItem2)
      case 'Start Combat': {
        //slayer task selection
        if (actionName == 'Slayer Task') {
          return () => {
            if (combatManager.slayerTask.killsLeft > 0) {
              const mID = combatManager.slayerTask.monster.id
              const areaData = [
                ...areaMenus.combat.areas,
                ...areaMenus.slayer.areas,
              ].find((a) => a.monsters.includes(mID))
              if (
                combatManager.isInCombat &&
                combatManager.selectedMonster == mID
              )
                return true
              combatManager.stopCombat()
              combatManager.selectMonster(mID, areaData)
              return true
            }
            return false
          }
        }
        //dungeon selection
        const dungeonIndex = DUNGEONS.findIndex((a) => a.name == actionName)
        if (dungeonIndex >= 0) {
          return () => {
            if (
              DUNGEONS[dungeonIndex].requiresCompletion === undefined ||
              dungeonCompleteCount[DUNGEONS[dungeonIndex].requiresCompletion] >=
                1
            ) {
              combatManager.selectDungeon(dungeonIndex)
              return true
            }
            return false
          }
        }
        //regular monster selection
        const monsterIndex = MONSTERS.findIndex((a) => a.name == actionName)
        const areaData = [
          ...areaMenus.combat.areas,
          ...areaMenus.slayer.areas,
        ].find((a) => a.monsters.includes(monsterIndex))
        return () => {
          if (checkRequirements(areaData.entryRequirements)) {
            if (
              !(
                combatManager.isInCombat &&
                combatManager.selectedMonster == monsterIndex
              )
            )
              combatManager.selectMonster(monsterIndex, areaData)
            return true
          }
          return false
        }
      }
      case 'Change Attack Style': {
        if (actionName == 'Select Spell') {
          switch (skillItem) {
            case 'Normal':
              return () => {
                const spellID = SPELLS.findIndex((a) => a.name == skillItem2)
                //check level req
                if (
                  skillLevel[CONSTANTS.skill.Magic] <
                  SPELLS[spellID].magicLevelRequired
                )
                  return false
                player.toggleSpell(spellID)
                return true
              }
            case 'Curse':
              return () => {
                const spellID = CURSES.findIndex((a) => a.name == skillItem2)
                //check level req
                if (
                  skillLevel[CONSTANTS.skill.Magic] <
                  CURSES[spellID].magicLevelRequired
                )
                  return false
                player.toggleCurse(spellID)
                return true
              }
            case 'Aurora':
              return () => {
                const spellID = AURORAS.findIndex((a) => a.name == skillItem2)
                //check level req
                if (
                  skillLevel[CONSTANTS.skill.Magic] <
                  AURORAS[spellID].magicLevelRequired
                )
                  return false
                //check item req
                if (
                  AURORAS[spellID].requiredItem >= 0 &&
                  !player.equipment.slotArray
                    .map((a) => a.item.id)
                    .includes(AURORAS[spellID].requiredItem)
                )
                  return false
                player.toggleAurora(spellID)
                return true
              }
            case 'Ancient':
              return () => {
                const spellID = ANCIENT.findIndex((a) => a.name == skillItem2)
                //check level req
                if (
                  skillLevel[CONSTANTS.skill.Magic] <
                  ANCIENT[spellID].magicLevelRequired
                )
                  return false
                //check dungeon req
                if (
                  dungeonCompleteCount[
                    ANCIENT[spellID].requiredDungeonCompletion[0]
                  ] < ANCIENT[spellID].requiredDungeonCompletion[1]
                )
                  return false
                player.toggleSpellAncient(spellID)
                return true
              }
          }
        }
        const style = CONSTANTS.attackStyle[actionName]
        return () => {
          if (player.attackType == 'magic') {
            if (style < 6) return false
          } else if (player.attackType === 'ranged') {
            if (style > 5 || style < 3) return false
          } else {
            if (style > 2) return false
          }
          player.setAttackStyle(player.attackType, actionName)
          return true
        }
      }
      case 'Switch Equipment Set': {
        const equipSet = parseInt(actionName) - 1
        return () => {
          if (player.equipmentSets.length > equipSet) {
            player.changeEquipmentSet(equipSet)
            return true
          }
          return false
        }
      }
      case 'Equip Item':
        return () => {
          const bankID = getBankId(itemID)
          if (bankID === -1) return false
          if (sellItemMode) toggleSellItemMode()
          if (items[itemID].canEat) {
            selectBankItem(itemID)
            equipFoodQty = bank[bankID].qty
            equipFood()
            return getBankQty(itemID) == 0 //returns false if there is any of the item left in bank (couldn't equip)
          }
          if (items[itemID].type == 'Familiar') {
            let slot = player.equipment.slotArray
              .slice(-3)
              .findIndex((a) => a.item.id == itemID)
            if (slot >= 0) {
              player.equipItem(
                itemID,
                player.selectedEquipmentSet,
                `Summon${slot}`,
                bank[bankID].qty
              )
            } else if (player.equipment.slotArray[12].quantity == 0) {
              player.equipItem(
                itemID,
                player.selectedEquipmentSet,
                'Summon1',
                bank[bankID].qty
              )
            } else if (player.equipment.slotArray[13].quantity == 0) {
              player.equipItem(
                itemID,
                player.selectedEquipmentSet,
                'Summon2',
                bank[bankID].qty
              )
            }
            return getBankQty(itemID) == 0
          }
          if (items[itemID].validSlots[0] == 'Quiver') {
            player.equipItem(
              itemID,
              player.selectedEquipmentSet,
              'Quiver',
              bank[bankID].qty
            )
            return getBankQty(itemID) == 0 //returns false if there is any of the item left in bank (couldn't equip)
          }
          player.equipItem(itemID, player.selectedEquipmentSet)
          return (
            player.equipment.slots[items[itemID].validSlots[0]].item.id ===
            itemID
          ) //returns false if the item is not equipped
        }
      case 'Equip Passive':
        return () => {
          if (dungeonCompleteCount[15] < 1 || getBankId(itemID) === -1)
            return false
          player.equipCallback(itemID, 'Passive')
          return player.equipment.slots.Passive.item.id === itemID
        }
      case 'Unequip Item': {
        return () => {
          for (const i in player.equipment.slots) {
            if (player.equipment.slots[i].item.id == itemID) {
              player.unequipCallback(i)()
              return getBankQty(itemID) > 0 //returns false if there is 0 of the items in bank (no space to unequip)
            }
          }
          return false
        }
      }
      case 'Buy Item':
        return () => {
          return shop[actionName].buy(qty)
        }
      case 'Sell Item':
        return () => {
          if (!bank.find((a) => a.id == itemID)) return false
          if (sellItemMode) toggleSellItemMode()
          selectBankItem(itemID)
          sellItem()
          if (showSaleNotifications) swal.clickConfirm()
          return true
        }
      case 'Use Potion':
        return () => {
          if (!bank.find((a) => a.id == itemID)) return false
          usePotion(itemID)
          return true
        }
      case 'Activate Prayers': {
        let choice = []
        if (actionName != 'None') {
          choice.push(PRAYER.findIndex((a) => a.name == actionName))
          if (skillItem != 'None') {
            choice.push(PRAYER.findIndex((a) => a.name == skillItem))
          }
        }
        return () => {
          const validPrayers = choice.filter(
            (a) => skillLevel[CONSTANTS.skill.Prayer] > PRAYER[a].prayerLevel
          )
          changePrayers(validPrayers)
          return true
        }
      }
      case 'Build Agility Obstacle': {
        const obstacleID = Agility.obstacles.findIndex(
          (a) => a.name == skillItem
        )
        const obstacleNumber = parseInt(actionName) - 1
        return () => {
          if (chosenAgilityObstacles[obstacleNumber] == obstacleID) return true
          if (
            !canIAffordThis(
              Agility.obstacles[obstacleID].cost,
              Agility.obstacles[obstacleID].skillRequirements,
              obstacleID
            )
          )
            return false
          if (chosenAgilityObstacles[obstacleNumber] >= 0)
            destroyAgilityObstacle(obstacleNumber, true)
          buildAgilityObstacle(obstacleID, true)
          return true
        }
      }
      case 'Remove Agility Obstacle': {
        const obstacleNumber = parseInt(actionName) - 1
        return () => {
          if (chosenAgilityObstacles[obstacleNumber] >= 0)
            destroyAgilityObstacle(obstacleNumber, true)
          return true
        }
      }
    }
  }
}
// * start skill
// call
// start: setAction(actionCategory, actionName, skillItem, skillItem2, qty)
// result = action.start()

window.setSkillAction = function (actionName, skillItem1, skillItem2) {
  const itemID = items.findIndex((a) => a.name == skillItem1)
  let actionID = 0
  switch (actionName) {
    case 'Agility':
      return () => {
        if (game.activeSkill !== globalThis.ActiveSkills.Agility)
          game.agility.start()
        return true
      }
    case 'Astrology': {
      const constellation = Astrology.constellations.find(
        (a) => a.name == skillItem1
      ) // Find constellation
      return () => {
        if (skillLevel[CONSTANTS.skill.Astrology] < constellation.level)
          return false
        if (
          game.astrology.activeConstellation.id != constellation.id ||
          game.activeSkill != globalThis.ActiveSkills.ASTROLOGY
        )
          game.astrology.studyConstellationOnClick(constellation)
        return true
      }
    }
    case 'Cooking': {
      const itemID = items.findIndex((a) => a.name == skillItem2)
      const recipe = Cooking.recipes.find((a) => a.itemID == itemID)
      const category = recipe.category
      if (skillItem1 == 'Active') {
        return () => {
          const passives = []
          ;[0, 1, 2].forEach((c) => {
            game.cooking.onCollectStockpileClick(c)
            if (c != category && game.cooking.passiveCookTimers.has(c))
              passives.push(c)
          })
          if (skillLevel[CONSTANTS.skill.Cooking] < recipe.cookingLevel)
            return false
          if (game.cooking.selectedRecipes.get(category).itemID != itemID)
            game.cooking.onRecipeSelectionClick(recipe)
          if (
            game.activeSkill == globalThis.ActiveSkills.COOKING &&
            game.cooking.activeCookingCategory == category
          )
            return true
          game.cooking.onActiveCookButtonClick(category)
          passives.forEach((a) => game.cooking.onPassiveCookButtonClick(a))
          return true
        }
      } else {
        return () => {
          ;[0, 1, 2].forEach((category) =>
            game.cooking.onCollectStockpileClick(category)
          )
          if (
            skillLevel[CONSTANTS.skill.Cooking] <
            Cooking.recipes.find((a) => a.itemID == itemID).level
          )
            return false
          if (game.cooking.selectedRecipes.get(category).itemID != itemID)
            game.cooking.onRecipeSelectionClick(recipe)
          if (game.cooking.passiveCookTimers.has(category)) return true
          game.cooking.onPassiveCookButtonClick(category)
          return true
        }
      }
    }
    case 'Crafting':
      actionID = Crafting.recipes.find((a) => a.itemID == itemID).masteryID
      return () => {
        if (
          skillLevel[CONSTANTS.skill.Crafting] <
          Crafting.recipes[actionID].level
        )
          return false
        if (game.crafting.selectedRecipeID !== actionID)
          game.crafting.selectRecipeOnClick(actionID)
        if (game.activeSkill !== globalThis.ActiveSkills.CRAFTING)
          game.crafting.start(true)
        return true
      }
    case 'Firemaking':
      actionID = Firemaking.recipes.findIndex((x) => x.logID == itemID)
      return () => {
        if (
          skillLevel[CONSTANTS.skill.Firemaking] <
          Firemaking.recipes[actionID].levelRequired
        )
          return false
        if (
          !game.firemaking.activeRecipe ||
          game.firemaking.activeRecipe.logID !== actionID
        )
          game.firemaking.selectLog(actionID)
        if (!game.firemaking.isActive) game.firemaking.burnLog()
        return true
      }
    case 'Fishing': {
      const fish = Fishing.data.find((a) => a.itemID == itemID)
      const area = Fishing.areas.find((a) => a.fish.includes(fish))
      return () => {
        if (
          (!player.equipment.slotArray
            .map((a) => a.item.id)
            .includes(CONSTANTS.item.Barbarian_Gloves) &&
            area.id == 6) ||
          (!game.fishing.secretAreaUnlocked && area.id == 7) ||
          skillLevel[CONSTANTS.skill.Fishing] < fish.level
        )
          return false
        game.fishing.onAreaFishSelection(area, fish)
        if (
          game.activeSkill !== globalThis.ActiveSkills.FISHING ||
          game.fishing.activeFishingArea != area
        ) {
          game.fishing.onAreaStartButtonClick(area)
        }
        return true
      }
    }
    case 'Fletching':
      actionID = Fletching.recipes.find((a) => a.itemID == itemID).masteryID
      const log = items.findIndex((a) => a.name == skillItem2)
      if (skillItem1 != 'Arrow Shafts') {
        return () => {
          if (
            skillLevel[CONSTANTS.skill.Fletching] <
            Fletching.recipes[actionID].level
          )
            return false
          if (game.fletching.selectedRecipeID !== actionID)
            game.fletching.selectRecipeOnClick(actionID)
          if (game.activeSkill !== globalThis.ActiveSkills.FLETCHING)
            game.fletching.start()
          return true
        }
      }
      return () => {
        if (
          skillLevel[CONSTANTS.skill.Fletching] <
            Fletching.recipes[actionID].level ||
          !checkBankForItem(log)
        )
          return false
        if (
          game.fletching.selectedAltRecipe != log ||
          selectedFletch !== actionID
        )
          game.fletching.selectAltRecipeOnClick(log)
        if (game.activeSkill !== globalThis.ActiveSkills.FLETCHING)
          game.fletching.start()
        return true
      }
    case 'Herblore':
      actionID = Herblore.potions.findIndex((a) => a.name == skillItem1)
      return () => {
        if (
          skillLevel[CONSTANTS.skill.Herblore] <
          Herblore.potions[actionID].level
        )
          return false
        if (game.herblore.selectedRecipeID !== actionID)
          game.herblore.selectRecipeOnClick(actionID)
        if (!game.herblore.isActive) game.herblore.start()
        return true
      }
    case 'Mining':
      actionID = Mining.rockData.findIndex((a) => a.name == skillItem1)
      // game.mining.onRockClick(actionID)

      return () => {
        if (
          (actionID === 9 && !game.mining.canMineDragonite) ||
          skillLevel[CONSTANTS.skill.Mining] <
            Mining.rockData[actionID].levelRequired
        )
          return false
        if (!game.mining.isActive || game.mining.selectedRockId != actionID)
          game.mining.onRockClick(actionID)
        return true
      }
    case 'Magic': {
      actionID = AltMagic.spells.findIndex((a) => a.name == skillItem1)
      const magicItem = items.findIndex((a) => a.name == skillItem2)
      return () => {
        if (skillLevel[CONSTANTS.skill.Magic] < AltMagic.spells[actionID].level)
          return false
        if (game.altMagic.selectedSpellID !== actionID)
          game.altMagic.selectSpellOnClick(actionID)
        switch (AltMagic.spells[actionID].consumes) {
          case 3:
          case 2:
            const bar = Smithing.recipes.find((a) => a.itemID == magicItem)
            if (skillLevel[CONSTANTS.skill.Smithing] < bar.level) return false
            if (game.altMagic.selectedSmithingRecipe != bar)
              game.altMagic.selectBarOnClick(bar)
            break
          case 1:
          case 0:
            if (game.altMagic.selectedConversionItem != magicItem)
              game.altMagic.selectItemOnClick(magicItem)
            break
        }
        if (!game.altMagic.isActive) game.altMagic.start()
        return true
      }
    }
    case 'Runecrafting':
      actionID = Runecrafting.recipes.findIndex((a) => a.itemID == itemID)
      return () => {
        if (
          skillLevel[CONSTANTS.skill.Runecrafting] <
          Runecrafting.recipes[actionID].level
        )
          return false
        if (game.runecrafting.selectedRecipeID !== actionID)
          game.runecrafting.selectRecipeOnClick(actionID)
        if (game.activeSkill !== globalThis.ActiveSkills.RUNECRAFTING)
          game.runecrafting.start(true)
        return true
      }
    case 'Smithing':
      actionID = Smithing.recipes.findIndex((a) => a.itemID == itemID)
      return () => {
        if (
          skillLevel[CONSTANTS.skill.Smithing] <
          Smithing.recipes[actionID].level
        )
          return false
        if (game.smithing.selectedRecipeID !== actionID)
          game.smithing.selectRecipeOnClick(actionID)
        if (!game.smithing.isActive) game.smithing.start()
        return true
      }
    case 'Summoning': {
      const summonID = Summoning.marks.findIndex((a) => a.itemID == itemID)
      let recipeID = 0
      if (options.actions['Start Skill']['Summoning'][skillItem1] != null) {
        const ingredientID = items.findIndex((a) => a.name == skillItem2)
        recipeID = Summoning.marks[summonID].nonShardItemCosts.findIndex(
          (a) => a == ingredientID
        )
      }
      return () => {
        //exit if low level
        if (
          skillLevel[CONSTANTS.skill.Summoning] <
          Summoning.marks[summonID].level
        )
          return false
        //if summon is not selected, choose it
        if (
          game.summoning.selectedRecipeID != summonID ||
          game.summoning.selectedAltRecipe != recipeID
        ) {
          game.summoning.selectRecipeOnClick(summonID)
          game.summoning.selectAltRecipeOnClick(recipeID)
        }
        if (game.activeSkill !== globalThis.ActiveSkills.SUMMONING)
          game.summoning.start()
        return game.activeSkill === globalThis.ActiveSkills.SUMMONING
      }
    }
    case 'Thieving': {
      const npc = Thieving.npcs.find((a) => a.name == skillItem1)
      const area = Thieving.areas.find((a) => a.npcs.includes(npc.id))
      const panel = thievingMenu.areaPanels.find((a) => a.area == area)
      return () => {
        if (skillLevel[CONSTANTS.skill.Thieving] < npc.level) return false
        if (
          game.activeSkill == globalThis.ActiveSkills.THIEVING &&
          game.thieving.currentNPC == npc
        )
          return true
        thievingMenu.selectNPCInPanel(npc, panel)
        game.thieving.startThieving(area, npc)
        return true
      }
    }
    case 'Woodcutting':
      actionID = [itemID, items.findIndex((a) => a.name == skillItem2)].slice(
        0,
        playerModifiers.increasedTreeCutLimit + 1
      )
      return () => {
        let result = true
        let currentTrees = []
        game.woodcutting.activeTrees.forEach((a) => currentTrees.push(a.id))
        currentTrees.forEach((tree) => {
          if (actionID.includes(tree)) {
            actionID.splice(
              actionID.findIndex((a) => a == tree),
              1
            )
          } else {
            actionID.unshift(tree)
          }
        })

        actionID.forEach((i) => {
          if (
            skillLevel[CONSTANTS.skill.Woodcutting] >=
            Woodcutting.trees[i].levelRequired
          ) {
            game.woodcutting.selectTree(Woodcutting.trees[i])
          } else {
            result = false
          }
        })
        return result
      }
  }
}

  // ========================================================================== //
  // * footer
  // ========================================================================== //

  function onGameReady(callback) {
    const foo = 'play-area-container'
    // const foo = 'status-action'
    const gameContainer = document.getElementsByClassName(foo)
    // gameContainer.length
    if (gameContainer.length === 0) {
      setTimeout(function () {
        onGameReady(callback)
      }, 500)
    } else {
      callback()
    }
  }

  function init() {
    openDefaultPage(setDefaultPage[0])
    shortcuts()
  }

  onGameReady(function () {
    init()
  })
})()