Module:Items/UseTables

From Melvor Idle
< Module:Items
Revision as of 20:36, 2 October 2021 by Auron956 (talk | contribs) (Substitute links with Icons.Icon() where possible to benefit from ambiguous link handling)
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.

Documentation for this module may be created at Module:Items/UseTables/doc

local p = {}

local MonsterData = mw.loadData('Module:Monsters/data')
local ItemData = mw.loadData('Module:Items/data')
local SkillData = mw.loadData('Module:Skills/data')

local Constants = require('Module:Constants')
local Shared = require('Module:Shared')
local Magic = require('Module:Magic')
local Areas = require('Module:CombatAreas')
local Items = require('Module:Items')
local Icons = require('Module:Icons')
local Agility = require('Module:Skills/Agility')
local Shop = require('Module:Shop')


--Brute forcing some item uses to make things easier
local itemUseArray = {
  Agility = {},
  Attack = {},
  Combat = {'Gold Emerald Ring'},
  Cooking = {'Cooking Gloves', 'Crown of Rhaelyx'},
  Crafting = {'Crown of Rhaelyx'},
  Defence = {},
  Farming = {'Compost', 'Weird Gloop', 'Bob&apos;s Rake'},
  Firemaking = {'Crown of Rhaelyx'},
  Fishing = {'Amulet of Fishing', 'Message in a Bottle'},
  Fletching = {'Crown of Rhaelyx'},
  Herblore = {'Crown of Rhaelyx'},
  Hitpoints = {},
  Magic = {},
  Mining = {'Mining Gloves', 'Gem Gloves'},
  Prayer = {},
  Ranged = {},
  Runecrafting = {'Crown of Rhaelyx'},
  Slayer = {},
  Smithing = {'Smithing Gloves', 'Crown of Rhaelyx'},
  Strength = {},
  Summoning = {'Crown of Rhaelyx'},
  Thieving = {'Chapeau Noir', 'Thieving Gloves', 'Gloves of Silence'},
  Woodcutting = {},
  }
local potionUseArray = {
  [0] = 'Combat',
  [1] = 'Combat',
  [2] = 'Combat',
  [3] = 'Combat',
  [4] = 'Combat',
  [5] = 'Combat',
  [6] = 'Combat',
  [7] = 'Woodcutting',
  [8] = 'Fishing',
  [9] = 'Firemaking',
  [10] = 'Cooking',
  [11] = 'Mining',
  [12] = 'Smithing',
  [13] = 'Thieving',
  [14] = 'Farming',
  [15] = 'Fletching',
  [16] = 'Crafting',
  [17] = 'Runecrafting',
  [18] = 'Herblore',
  [19] = 'Combat',
  [20] = 'Combat',
  [21] = 'Combat',
  [22] = 'Combat',
  [23] = 'Combat',
  [24] = 'Agility',
  [25] = 'Summoning'
}

function p._getItemUses(item, asList, addCategories)
  local useArray = {}
  local categoryArray = {}
  local chr = asList and '* ' or ''
  --Another fun one. This time getting all the different possible ways an item can be used

  --Before anything else, if this is a potion add it to the appropriate override section
  if item.masteryID ~= nil and item.masteryID[1] == 19 then
    table.insert(itemUseArray[potionUseArray[item.masteryID[2]]], item.name)
  end

  --If the item has any modifiers that affect a given skill, add it to those lists
  if item.modifiers ~= nil then
    local skillArray = Constants.getModifierSkills(item.modifiers)
    for i, skillName in Shared.skpairs(skillArray) do
      table.insert(itemUseArray[skillName], item.name)
    end
  end

  --First things added to the list are non-skill things that are easy to check
  if Items.hasCombatStats(item) or Shared.contains(itemUseArray.Combat, item.name) then
    table.insert(useArray, chr..Icons.Icon({'Combat'}))
  end

  if item.healsFor ~= nil then
    table.insert(categoryArray, '[[Category:Food Items]]')
    table.insert(useArray, chr..'[[Food]]')
  end

  if item.dropTable ~= nil then
    table.insert(categoryArray, '[[Category:Openable Items]]')
    table.insert(useArray, chr..'[[Chest Drop Tables|Can Be Opened]]')
  end

  -- Check if the item is an entry requirement for any Slayer area
  local isSlayerAreaReq = false
  if item.isEquipment then
    local slayerAreas = Areas.getAreas(function(area) return area.type == 'slayer' end)
    for i, area in pairs(slayerAreas) do
      if area.entryRequirements ~= nil and type(area.entryRequirements) == 'table' then
        for j, req in pairs(area.entryRequirements) do
          if req.type == "SlayerItem" and req.itemID == item.id then
            isSlayerAreaReq = true
            break
          end
        end
        if isSlayerAreaReq then break end
      end
    end
  end

  --Next, upgrading, crafting, herblore, fletching, and runecrafting since we have to sift through other items for these
  local canUpgrade = false
  local canCraft = false
  local canFletch = false
  local canRunecraft = false
  local canHerblore = false
  local canAgile = false
  local canSummon = false
  local canCook = false

  if item.trimmedItemID ~= nil then
    canUpgrade = true
  end

  for i, item2 in pairs(ItemData.Items) do
    if item2.itemsRequired ~= nil then
      for j, req in pairs(item2.itemsRequired) do
        if req[1] == item.id then
          canUpgrade = true
          break
        end
      end
    end

    if item2.craftReq ~= nil then
      for j, req in pairs(item2.craftReq) do
        if req.id == item.id then
          canCraft = true
          break
        end
      end
    end
    if item2.fletchReq ~= nil then
      for j, req in pairs(item2.fletchReq) do
        if req.id == item.id then
          canFletch = true
          break
        end
      end
    end
    if item2.runecraftReq ~= nil then
      for j, req in pairs(item2.runecraftReq) do
        if req.id == item.id then
          canRunecraft = true
          break
        end
      end
    end

    if item2.herbloreReq ~= nil then
      for j, req in pairs(item2.herbloreReq) do
        if req.id == item.id then
          canHerblore = true
          break
        end
      end
    end

    if item2.summoningReq ~= nil then
      for j, reqSet in pairs(item2.summoningReq) do
        for k, req in pairs(reqSet) do
          if req.id == item.id then
            canSummon = true
            break
          end
        end
      end
    end
    
    --Handling for new Cooking method
    if item2.recipeRequirements ~= nil and item2.recipeRequirements[1] ~= nil then
    	for j, reqSet in pairs(item2.recipeRequirements) do
	    	for k, req in pairs(reqSet) do
	    		if req.id == item.id then
	    			canCook = true
	    			break
	    		end
	    	end
	    end
    end
  end

  --Check if Agility applies here
  canAgile = Shared.tableCount(Agility.getObstaclesForItem(item.id)) > 0

  --Agility
  if canAgile or Shared.contains(itemUseArray.Agility, item.name) then
    table.insert(useArray, chr..Icons.Icon({'Agility', type='skill'}))
  end
  --Cooking
  if canCook or Shared.contains(itemUseArray.Cooking, item.name) then
    table.insert(useArray, chr..Icons.Icon({'Cooking', type='skill'}))
  end
  --Crafting
  if canCraft or Shared.contains(itemUseArray.Crafting, item.name) then
    table.insert(useArray, chr..Icons.Icon({'Crafting', type='skill'}))
  end
  --Farming
  if item.grownItemID ~= nil or Shared.contains(itemUseArray.Farming, item.name) then
    table.insert(useArray, chr..Icons.Icon({'Farming', type='skill'}))
  end
  --Firemaking
  if item.firemakingID ~= nil or Shared.contains(itemUseArray.Firemaking, item.name) then
    table.insert(useArray, chr..Icons.Icon({'Firemaking', type='skill'}))
  end
  --Fishing
  if Shared.contains(itemUseArray.Fishing, item.name) then
    table.insert(useArray, chr..Icons.Icon({'Fishing', type='skill'}))
  end
  --Fletching
  if canFletch or Shared.contains(itemUseArray.Fletching, item.name) then
    table.insert(useArray, chr..Icons.Icon({'Fletching', type='skill'}))
  end
  --Herblore
  if canHerblore or Shared.contains(itemUseArray.Herblore, item.name) then
    table.insert(useArray, chr..Icons.Icon({'Herblore', type='skill'}))
  end
  --Mining
  if Shared.contains(itemUseArray.Mining, item.name) then
    table.insert(useArray, chr..Icons.Icon({'Mining', type='skill'}))
  end
  --Prayer
  if item.prayerPoints ~= nil or (Shared.contains(itemUseArray.Prayer, item.name) and not Shared.contains(itemUseArray.Combat, item.name)) then
    if item.prayerPoints ~= nil then table.insert(categoryArray, '[[Category:Buriable Items]]') end
    table.insert(useArray, chr..Icons.Icon({'Prayer', type='skill'}))
  end
  --Runecrafting
  if canRunecraft or Shared.contains(itemUseArray.Runecrafting, item.name) then
    table.insert(useArray, chr..Icons.Icon({'Runecrafting', type='skill'}))
  end
  --Slayer
  if isSlayerAreaReq or Shared.contains(itemUseArray.Slayer, item.name) then
    table.insert(useArray, chr..Icons.Icon({'Slayer', type='skill'}))
  end
  --Smithing
  if item.type == 'Bar' or item.type == 'Ore' or Shared.contains(itemUseArray.Smithing, item.name) then
    table.insert(useArray, chr..Icons.Icon({'Smithing', type='skill'}))
  end
  --Summoning
  if canSummon or (item.type == 'Shard' and item.category == 'Summoning') or item.type == 'Familiar' or Shared.contains(itemUseArray.Summoning, item.name) then
    table.insert(useArray, chr..Icons.Icon({'Summoning', type='skill'}))
  end
  --Thieving
  if Shared.contains(itemUseArray.Thieving, item.name) then
    table.insert(useArray, chr..Icons.Icon({'Thieving', type='skill'}))
  end
  --Woodcutting
  if Shared.contains(itemUseArray.Woodcutting, item.name) then
    table.insert(useArray, chr..Icons.Icon({'Woodcutting', type='skill'}))
  end

  --Other odds and ends:

  --Mastery Tokens are tied to 'Mastery'
  if item.isToken and item.skill ~= nil then
    table.insert(useArray, chr..Icons.Icon({'Mastery'}))
  end

  --Skillcapes are tied to the appropriate skill
  --Except Maximum Skillcape, which is tied to all skills. (And so is the Signet Ring)
  --And combat skillcapes, since combat skills don't get special treatment

  local ignoreCapes = {'Ranged Skillcape', 'Attack Skillcape', 'Strength Skillcape', 'Hitpoints Skillcape', 'Defence Skillcape'}
  if Shared.contains({'Maximum Skillcape', 'Aorpheat&apos;s Signet Ring', 'Cape of Completion'}, item.name) then
    table.insert(useArray, chr..'All skills')
  elseif item.name == 'Magic Skillcape' then
    table.insert(useArray, chr..Icons.Icon({'Magic', type='skill'}))
    table.insert(useArray, chr..Icons.Icon({'Alt. Magic', type='skill'}))
  elseif Shared.contains(item.name, 'Skillcape') and not Shared.contains(ignoreCapes, item.name) then
    local skillName = Shared.splitString(item.name, ' ')[1]
    --Avoiding double-listing the same skill twice
    if not Shared.contains(itemUseArray[skillName], item.name) then
      table.insert(useArray, chr..Icons.Icon({skillName, type='skill'}))
    end
  end

  if Shared.contains(item.name, 'Skillcape') or item.name == 'Cape of Completion' then table.insert(categoryArray, '[[Category:Skillcapes]]') end

  --Special note for Charge Stone of Rhaelyx
  if item.name == 'Charge Stone of Rhaelyx' then
    table.insert(useArray, chr..'Powering '..Icons.Icon({'Crown of Rhaelyx', type='item'}))
  end

  --Some items are needed to make shop purchases
  local shopArray = Shop.getItemCostArray(item.id)
  if Shared.tableCount(shopArray) > 0 then
    table.insert(useArray, chr..Icons.Icon({'Shop'}))
  end

  if canUpgrade then
    if item.canUpgrade or (item.type == 'Armour' and item.canUpgrade == nil) then
      table.insert(categoryArray, '[[Category:Upgradeable Items]]')
    end
    table.insert(useArray, chr..'[[Upgrading Items]]')
  end

  local resultPart = {}
  table.insert(resultPart, asList and table.concat(useArray,'\r\n') or table.concat(useArray, '<br/>'))
  if addCategories then table.insert(resultPart, table.concat(categoryArray, '')) end
  return table.concat(resultPart)
end

function p.getItemUses(frame)
  local itemName = frame.args ~= nil and frame.args[1] or frame
  local item = Items.getItem(itemName)
  local addCategories = false
  local asList = true
  if frame.args ~= nil then
    addCategories = frame.args.addCategories ~= nil and frame.args.addCategories ~= '' and frame.args.addCategories ~= 'false'
    asList = frame.args.addCategories == nil or frame.args.addCategories == '' or frame.args.addCategories == 'true'
  end
  if item == nil then
    return "ERROR: No item named "..itemName.." exists in the data module"
  end

  return p._getItemUses(item, asList, addCategories)
end

function p._getItemUseTable(item)
  local useArray = {}
  local potTierMastery = {[0] = 0, [1] = 20, [2] = 50, [3] = 90}

  --First, loop through all items to find anything that can be made or upgraded into using our source
  for i, item2 in pairs(ItemData.Items) do
    if item2.itemsRequired ~= nil then
      for j, req in pairs(item2.itemsRequired) do
        if req[1] == item.id then
          local mat = item2.itemsRequired
          local xp = 'N/A'
          local rowReq = 'None'
          --Potions do have upgrade requirements though
          if item2.potionTier ~= nil then
            rowReq = Icons._MasteryReq(item2.name, potTierMastery[item2.potionTier])
          end
          table.insert(useArray, {item = item2, qty = 1, mats = mat, skill = 'Upgrade', req = rowReq, xp = xp, gp = item2.trimmedGPCost})
          break
        end
      end
    end
    if item2.craftReq ~= nil then
      for j, req in pairs(item2.craftReq) do
        if req.id == item.id then
          local mat = item2.craftReq
          local xp = item2.craftingXP
          local rowReq = item2.craftingLevel
          local qty = item2.craftQty
          table.insert(useArray, {item = item2, qty = qty, mats = mat, skill = 'Crafting', req = rowReq, xp = xp, gp = item2.craftGPCost})
          break
        end
      end
    end
    if item2.fletchReq ~= nil then
      for j, req in pairs(item2.fletchReq) do
        if req.id == item.id then
          local xp = item2.fletchingXP
          local rowReq = item2.fletchingLevel
          --Arrow Shafts are special and have to be treated specially
          local qty = item2.fletchQty
          local mat = item2.fletchReq
          if item2.name == 'Arrow Shafts' then
            mat = {{id = item.id, qty = 1}}
            qty =  qty + (qty * item.id)
          end
          table.insert(useArray, {item = item2, qty = qty, mats = mat, skill = 'Fletching', req = rowReq, xp = xp})
          break
        end
      end
    end
    if item2.smithReq ~= nil then
      for j, req in pairs(item2.smithReq) do
        if req.id == item.id then
          local mat = item2.smithReq
          local xp = item2.smithingXP
          local rowReq = item2.smithingLevel
          local qty = item2.smithingQty
          table.insert(useArray, {item = item2, qty = qty, mats = mat, skill = 'Smithing', req = rowReq, xp = xp})
          break
        end
      end
    end
    --Handling for new Cooking method
    if item2.recipeRequirements ~= nil then
    	for j, reqSet in pairs(item2.recipeRequirements) do
	    	for k, req in pairs(reqSet) do
	    		if req.id == item.id then
		    		local mat = reqSet
		    		local xp = item2.cookingXP
		    		local rowReq = item2.cookingLevel
		    		local qty = item2.cookingQty
		    		table.insert(useArray, {item = item2, qty = qty, mats = mat, skill = 'Cooking', req = rowReq, xp = xp})
		    		
		    		if item2.perfectItem ~= nil then
		    			local perfectItem = Items.getItemByID(item2.perfectItem)
		    			table.insert(useArray, {item = perfectItem, qty = qty, mats = mat, skill = 'Cooking', req = rowReq, xp = xp})
		    		end
		    	end
	    	end
	    end
    end
    if item2.runecraftReq ~= nil then
      for j, req in pairs(item2.runecraftReq) do
        if req.id == item.id then
          local mat = item2.runecraftReq
          local xp = item2.runecraftingXP
          local rowReq = item2.runecraftingLevel
          local qty = item2.runecraftQty
          table.insert(useArray, {item = item2, qty = qty, mats = mat, skill = 'Runecrafting', req = rowReq, xp = xp})
          break
        end
      end
    end
    if item2.herbloreReq ~= nil then
      for j, req in pairs(item2.herbloreReq) do
        if req.id == item.id then
          local potionData = SkillData.Herblore.ItemData[item2.masteryID[2] + 1]
          local mat = item2.herbloreReq
          local xp = potionData.herbloreXP
          --Potions do have upgrade requirements though
          local rowReq = Icons._SkillReq('Herblore', potionData.level)
          local masteryLvl = potTierMastery[item2.potionTier]
          if masteryLvl > 0 then
            rowReq = rowReq..'<br/>'..Icons._MasteryReq(item2.name, masteryLvl)
          end
          local reqVal = potionData.level + (masteryLvl * 0.01)
          table.insert(useArray, {item = item2, qty = 1, mats = mat, skill = 'Herblore', reqVal = reqVal, req = rowReq, xp = xp})
          break
        end
      end
    end

    if item2.summoningReq ~= nil then
      for j, reqSet in pairs(item2.summoningReq) do
        for k, req in pairs(reqSet) do
          if req.id == item.id then
            local mat = Shared.clone(reqSet)
            mat[k].qty = math.max(math.floor(1000 / math.max(item.sellsFor, 20)), 1)
            local xp = 5 + 2 * math.floor(item2.summoningLevel * 0.2)
            local rowReq = item2.summoningLevel
            table.insert(useArray, {item = item2, qty = 25, mats = mat, skill = 'Summoning', req = rowReq, xp = xp})
          end
        end
      end
    end
  end
  if item.grownItemID ~= nil then
    local item2 = Items.getItemByID(item.grownItemID)
    local mat = {{id = item.id, qty = item.seedsRequired}}
    local xp = item.farmingXP
    local rowReq = item.farmingLevel
    local qty = 5
    table.insert(useArray, {item = item2, qty = qty, mats = mat, skill = 'Farming', req = rowReq, xp = xp})
  end

  --Handle shop purchases using Module:Shop
  local shopUses = Shop.getItemCostArray(item.id)
  for i, purchase in Shared.skpairs(shopUses) do
    local rowReq = Shop.getRequirementString(purchase.unlockRequirements)
    local iconType = (purchase.contains.items ~= nil and Shared.tableCount(purchase.contains.items) > 0) and 'item' or 'upgrade'
    table.insert(useArray, {item = {name = purchase.name}, qty = 1, mats = purchase.cost.items, skill = 'Shop', req = rowReq, xp = 'N/A', gp = purchase.cost.gp, type = iconType})
  end

  --Finally build the table using what we've learned
  table.sort(useArray, function(a, b)
                         local aReqVal = a.reqVal ~= nil and a.reqVal or a.req
                         local bReqVal = b.reqVal ~= nil and b.reqVal or b.req
                         if a.skill ~= b.skill then
                           return a.skill < b.skill
                         elseif type(aReqVal) ~= type(bReqVal) then
                           return tostring(aReqVal) < tostring(bReqVal)
                         elseif aReqVal ~= bReqVal then
                           return aReqVal < bReqVal
                         else
                           return a.item.name < b.item.name
                         end end)

  local obstacles = Agility.getObstaclesForItem(item.id)

  local spellUseTable = p._getSpellUseTable(item)
  local resultPart = {}
  if Shared.tableCount(useArray) == 0 and Shared.tableCount(obstacles) == 0 then
    if string.len(spellUseTable) > 0 then
      return '==Uses==\r\n==='..Icons.Icon({'Magic', type='skill', size='30'})..'===\r\n'..spellUseTable
    else
      return ''
    end
  end
  table.insert(resultPart, '{| class="wikitable sortable"')
  table.insert(resultPart, '\r\n!colspan=2|Item Created!!Type!!Requirements!!XP!!Ingredients')
  for i, row in pairs(useArray) do
    local qty = row.qty ~= nil and row.qty or 1
    local iconType = row.type ~= nil and row.type or 'item'
    table.insert(resultPart, '\r\n|-\r\n|data-sort-value="'..row.item.name..'"|')
    table.insert(resultPart, Icons.Icon({row.item.name, type=iconType, notext=true, size=50})..'||')
    if qty > 1 then table.insert(resultPart, "'''"..qty.."x''' ") end
    table.insert(resultPart, Icons.Icon({row.item.name, type='item', noicon=true}))
    if row.skill == 'Upgrade' then
      table.insert(resultPart, '||data-sort-value="Upgrade"|[[Upgrading Items|Upgrade]]')
    elseif row.skill == 'Shop' then
      table.insert(resultPart, '||data-sort-value="Shop"|'..Icons.Icon({'Shop'}))
    else
      table.insert(resultPart, '||data-sort-value="'..row.skill..'"|'..Icons.Icon({row.skill, type='skill'}))
    end
    if type(row.req) == 'number' then
      table.insert(resultPart, '|| style="text-align:right" data-sort-value="'..row.req..'"|'..Icons._SkillReq(row.skill, row.req))
    elseif row.reqVal ~= nil then
      table.insert(resultPart, '|| style="text-align:right" data-sort-value="'..row.reqVal..'"|'..row.req)
    else
      table.insert(resultPart, '||'..row.req)
    end
    if type(row.xp) == 'string' then
      table.insert(resultPart, '||style="text-align:right" data-sort-value="0"|'..row.xp)
    else
      table.insert(resultPart, '||style="text-align:right" data-sort-value="'..row.xp..'"|'..row.xp..' '..Icons.Icon({row.skill, type='skill', notext=true})..' XP')
    end
    table.insert(resultPart, '||')
    for i, mat in Shared.skpairs(row.mats) do
      local matID = mat.id ~= nil and mat.id or mat[1]
      local matQty = mat.qty ~= nil and mat.qty or mat[2]
      local matText = ''

      if i > 1 then table.insert(resultPart, '<br/>') end
      if matID >= 0 then
        -- Item
        local matItem = Items.getItemByID(matID)
        if matItem == nil then
          matText = 'ERROR: Failed to find item with ID ' .. matID .. '[[Category:Pages with Script Errors]]'
        else
          matText = Icons.Icon({matItem.name, type='item', qty=matQty})
        end
      elseif matID == -4 then
        -- GP
        matText = Icons.GP(SkillData.Summoning.Settings.recipeGPCost)
      elseif matID == -5 then
        -- Slayer Coins
        matText = Icons.SC(SkillData.Summoning.Settings.recipeGPCost)
      else
        matText = 'ERROR: Unknown item ID: ' .. matID .. ' [[Category:Pages with Script Errors]]'
      end
      table.insert(resultPart, matText)
    end
    if row.gp ~= nil then table.insert(resultPart, '<br/>'..Icons.GP(row.gp)) end
  end

  --Agility obstacles are weird and get their own section
  for i, obst in Shared.skpairs(obstacles) do
    table.insert(resultPart, '\r\n|-\r\n|')
    table.insert(resultPart, Icons.Icon({"Agility", type="skill", size="50", notext=true}))
    table.insert(resultPart, '||[[Agility#Obstacles|'..obst.name..']]')
    table.insert(resultPart, '||'..Icons.Icon({"Agility", type="skill"}))

    --Adding the requirements for the Agility Obstacle
    local reqArray = {}
    if obst.category == nil then --nil category means this is a passive pillar
      table.insert(reqArray, Icons._SkillReq('Agility', 99))
    elseif obst.category > 0 then --Otherwise it's category * 10
      table.insert(reqArray, Icons._SkillReq('Agility', obst.category * 10))
    end
    --Then the other skill levels if any are added
    if obst.requirements ~= nil and obst.requirements.skillLevel ~= nil then
      for j, req in Shared.skpairs(obst.requirements.skillLevel) do
        table.insert(reqArray, Icons._SkillReq(Constants.getSkillName(req[1]), req[2]))
      end
    end
    table.insert(resultPart, '||style="text-align:right"|'..table.concat(reqArray, '<br/>'))

    --Just including 'N/A' for XP since it doesn't really apply for Agility Obstacles
    table.insert(resultPart, '||style="text-align:right"|N/A')

    --Finally the cost
    local cost = obst.cost
    local costArray = {}
    if cost.gp ~= nil and cost.gp > 0 then
      table.insert(costArray, Icons.GP(cost.gp))
    end
    if cost.slayerCoins ~= nil and cost.slayerCoins > 0 then
      table.insert(costArray, Icons.SC(cost.slayerCoins))
    end
    for j, mat in Shared.skpairs(cost.items) do
      local item = Items.getItemByID(mat[1])
      table.insert(costArray, Icons.Icon({item.name, type="item", qty=mat[2]}))
    end

    table.insert(resultPart, '||'..table.concat(costArray, '<br/>'))

  end

  table.insert(resultPart, '\r\n|}')
  if string.len(spellUseTable) > 0 then
    table.insert(resultPart, '\r\n==='..Icons.Icon({'Magic', type='skill', size='30'})..'===\r\n'..spellUseTable)
  end
  return '==Uses==\r\n'..table.concat(resultPart)
end

function p.getItemUseTable(frame)
  local itemName = frame.args ~= nil and frame.args[1] or frame
  local item = Items.getItem(itemName)
  if item == nil then
    return "ERROR: No item named "..itemName.." exists in the data module"
  end

  return p._getItemUseTable(item)
end

function p._getSpellUseTable(item)
  local spellList = Magic.getSpellsForRune(item.id)
  --Bail immediately if no spells are found
  if Shared.tableCount(spellList) == 0 then
    return ''
  end

  local resultPart = {}
  table.insert(resultPart, '{|class="wikitable sortable"\r\n!colspan="2"|Spell')
  table.insert(resultPart, '!!Requirements')
  table.insert(resultPart, '!!Type!!style="width:275px"|Description')
  table.insert(resultPart, '!!Runes')
  for i, spell in pairs(spellList) do
    local rowPart = {}
    table.insert(rowPart, '\r\n|-\r\n|data-sort-value="'..spell.name..'"|')
    local iconType = (spell.type == 'Auroras' and 'aurora') or (spell.type == 'Curses' and 'curse') or 'spell'
    table.insert(rowPart, Icons.Icon({spell.name, type=iconType, notext=true, size=50}))
    table.insert(rowPart, '||'..Icons.Icon({spell.name, type=iconType, noicon=true}))
    table.insert(rowPart, '||data-sort-value="'..spell.level..'"|'..Icons._SkillReq('Magic', spell.level))
    --Handle required items/dungeon clears
    if spell.requiredItem ~= nil and spell.requiredItem >= 0 then
      local reqItem = Items.getItemByID(spell.requiredItem)
      table.insert(rowPart, '<br/>'..Icons.Icon({reqItem.name, type='item', notext=true})..' equipped')
    end
    if spell.requiredDungeonCompletion ~= nil then
      local dung = Areas.getAreaByID('dungeon', spell.requiredDungeonCompletion[1])
      table.insert(rowPart, '<br/>'..Icons.Icon({dung.name, type='dungeon', notext=true, qty=spell.requiredDungeonCompletion[2]})..' Clears')
    end
    table.insert(rowPart, '||data-sort-value="'..Magic.getSpellTypeIndex(spell.type)..'"|')
    table.insert(rowPart, Magic.getSpellTypeLink(spell.type))
    table.insert(rowPart, '||'..Magic._getSpellStat(spell, 'description'))
    table.insert(rowPart, '||style="text-align:center"|')
    table.insert(rowPart, Magic._getSpellRunes(spell))
    table.insert(resultPart, table.concat(rowPart))
  end
   --Add the table end and add the table to the result string
  table.insert(resultPart, '\r\n|}')
  return table.concat(resultPart)
end

function p.getSpellUseTable(frame)
  local itemName = frame.args ~= nil and frame.args[1] or frame
  local item = Items.getItem(itemName)
  if item == nil then
    return "ERROR: No item named "..itemName.." exists in the data module"
  end

  return p._getSpellUseTable(item)
end

return p