Anonymous

Module:Items/UseTables: Difference between revisions

From Melvor Idle
_getItemUseTable: Support GP & SC in various artisan skills
(right-aligning some stuff)
(_getItemUseTable: Support GP & SC in various artisan skills)
(24 intermediate revisions by 3 users not shown)
Line 1: Line 1:
local p = {}
local p = {}


local MonsterData = mw.loadData('Module:Monsters/data')
local ItemData = mw.loadData('Module:Items/data')
local ItemData = mw.loadData('Module:Items/data')
local SkillData = mw.loadData('Module:Skills/data')
local SkillData = mw.loadData('Module:Skills/data')
Line 14: Line 13:
local Shop = require('Module:Shop')
local Shop = require('Module:Shop')


local SkillEnum = mw.loadData('Module:Constants/data').skill


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


function p._getItemUses(item, asList, addCategories)
function p._getItemUses(item, asList, addCategories)
  local useArray = {}
-- Another fun one. This time getting all the different possible ways an item can be used
  local categoryArray = {}
local categoryArray = {}
  local chr = asList and '* ' or ''
local skillUses = {}
  --Another fun one. This time getting all the different possible ways an item can be used
local otherUses = {}
local otherUseText = {
["Combat"] = Icons.Icon({'Combat'}),
["Upgrade"] = '[[Upgrading Items]]',
["Food"] = '[[Food]]',
["Chest"] = '[[Chest Drop Tables|Can Be Opened]]',
["Mastery"] = Icons.Icon({'Mastery'}),
["AllSkills"] = 'All skills',
["AltMagic"] = Icons.Icon({'Alt. Magic', type='skill'}),
["ChargeStone"] = 'Powering ' .. Icons.Icon({'Crown of Rhaelyx', type='item'}),
["Shop"] = Icons.Icon({'Shop'})
}


  --Before anything else, if this is a potion add it to the appropriate override section
local addUse = function(useName)
  if item.masteryID ~= nil and item.masteryID[1] == 19 then
local skillID = (type(useName) == 'number' and useName) or SkillEnum[useName]
    table.insert(itemUseArray[potionUseArray[item.masteryID[2]]], item.name)
if type(skillID) == 'number' then
  end
if skillUses[skillID] == nil then
skillUses[skillID] = Constants.getSkillName(skillID)
end
elseif not otherUses[useName] then
otherUses[useName] = true
end
end
local hasUse = function(useName)
local skillID = (type(useName) == 'number' and useName) or SkillEnum[useName]
if type(skillID) == 'number' then
return (skillUses[skillID] ~= nil) or false
else
return otherUses[useName] or false
end
end


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


  --First things added to the list are non-skill things that are easy to check
-- If this is a potion add it to the appropriate uses table
  if Items.hasCombatStats(item) or Shared.contains(itemUseArray.Combat, item.name) then
if type(item.masteryID) == 'table' and item.masteryID[1] == SkillEnum.Herblore then
    table.insert(useArray, chr..Icons.Icon({'Combat'}))
-- Default to 'Combat' if unknown
  end
local potionUse = potionUseArray[item.masteryID[2]] or 'Combat'
addUse(potionUseArray[item.masteryID[2]] or 'Combat')
end


  if item.healsFor ~= nil then
-- If the item has any modifiers that affect a given skill, add it to those tables
    table.insert(categoryArray, '[[Category:Food Items]]')
-- Added an exception for Mastery Tokens since they were being incorrectly flagged as usable for all skills
    table.insert(useArray, chr..'[[Food]]')
if item.modifiers ~= nil and (item.isToken == nil or not item.isToken) then
  end
local skillArray = Constants.getModifierSkills(item.modifiers)
for i, skillName in ipairs(skillArray) do
addUse(skillName)
end
end


  if item.dropTable ~= nil then
--First things added to the list are non-skill things that are easy to check
    table.insert(categoryArray, '[[Category:Openable Items]]')
if not hasUse('Combat') and (Items.hasCombatStats(item) or item.specialAttacks ~= nil) then
    table.insert(useArray, chr..'[[Chest Drop Tables|Can Be Opened]]')
addUse('Combat')
  end
end


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


  --Next, upgrading, crafting, herblore, fletching, and runecrafting since we have to sift through other items for these
-- Can the item be upgraded, or is it part of an upgrade recipe?
  local canUpgrade = false
if item.canUpgrade then
  local canCraft = false
addUse('Upgrade')
  local canFletch = false
else
  local canRunecraft = false
for i, item2 in pairs(ItemData.Items) do
  local canHerblore = false
if item2.itemsRequired ~= nil then
  local canAgile = false
for j, req in ipairs(item2.itemsRequired) do
  local canSummon = false
if req[1] == item.id then
addUse('Upgrade')
break
end
end
if hasUse('Upgrade') then
break
end
end
end
end
if hasUse('Upgrade') then
table.insert(categoryArray, '[[Category:Upgradeable Items]]')
end


  if item.trimmedItemID ~= nil then
if item.healsFor ~= nil then
    canUpgrade = true
table.insert(categoryArray, '[[Category:Food Items]]')
  end
addUse('Food')
end


  for i, item2 in pairs(ItemData.Items) do
if item.canOpen then
    if item2.itemsRequired ~= nil then
table.insert(categoryArray, '[[Category:Openable Items]]')
      for j, req in pairs(item2.itemsRequired) do
addUse('Chest')
        if req[1] == item.id then
end
          canUpgrade = true
          break
        end
      end
    end


    if item2.craftReq ~= nil then
-- Cooking, Smithing, Fletching, Crafting, Runecrafting, Herblore
      for j, req in pairs(item2.craftReq) do
-- All have somewhat consistent recipe data structures
        if req.id == item.id then
local recipeSkillIDs = {
          canCraft = true
SkillEnum.Cooking,
          break
SkillEnum.Smithing,
        end
SkillEnum.Fletching,
      end
SkillEnum.Crafting,
    end
SkillEnum.Runecrafting,
    if item2.fletchReq ~= nil then
SkillEnum.Herblore
      for j, req in pairs(item2.fletchReq) do
}
        if req.id == item.id then
for i, recipeSkillID in ipairs(recipeSkillIDs) do
          canFletch = true
if not hasUse(recipeSkillID) then
          break
local recipeKey = (recipeSkillID == SkillEnum.Herblore and 'Potions') or 'Recipes'
        end
local skillName = Constants.getSkillName(recipeSkillID)
      end
-- Iterate over all recipes for the current skill
    end
for j, recipe in ipairs(SkillData[skillName][recipeKey]) do
    if item2.runecraftReq ~= nil then
for k, itemCost in ipairs(recipe.itemCosts) do
      for j, req in pairs(item2.runecraftReq) do
if itemCost.id == item.id then
        if req.id == item.id then
addUse(recipeSkillID)
          canRunecraft = true
break
          break
end
        end
end
      end
-- Some items (such as Arrow shafts) have multiple recipes
    end
if not hasUse(recipeSkillID) and type(recipe.alternativeCosts) == 'table' then
for k, altCost in ipairs(recipe.alternativeCosts) do
for m, itemCost in ipairs(altCost.itemCosts) do
if itemCost.id == item.id then
addUse(recipeSkillID)
break
end
end
if hasUse(recipeSkillID) then
break
end
end
end
if hasUse(recipeSkillID) then
break
end
end
end
end


    if item2.herbloreReq ~= nil then
-- Firemaking
      for j, req in pairs(item2.herbloreReq) do
if not hasUse(SkillEnum.Firemaking) and type(item.masteryID) == 'table' and item.masteryID[1] == SkillEnum.Firemaking then
        if req.id == item.id then
addUse(SkillEnum.Firemaking)
          canHerblore = true
end
          break
        end
      end
    end


    if item2.summoningReq ~= nil then
-- Farming
      for j, reqSet in pairs(item2.summoningReq) do
if not hasUse(SkillEnum.Farming) and item.grownItemID ~= nil then
        for k, req in pairs(reqSet) do
addUse(SkillEnum.Farming)
          if req.id == item.id then
end
            canSummon = true
            break
          end
        end
      end
    end
  end


  --Check if Agility applies here
-- Agility
  canAgile = Shared.tableCount(Agility.getObstaclesForItem(item.id)) > 0
if not hasUse(SkillEnum.Agility) and Shared.tableCount(Agility.getObstaclesForItem(item.id)) > 0 then
addUse(SkillEnum.Agility)
end


  --Agility
-- Summoning
  if canAgile or Shared.contains(itemUseArray.Agility, item.name) then
if not hasUse(SkillEnum.Summoning) then
    table.insert(useArray, chr..Icons.Icon({'Agility', type='skill'}))
for i, recipe in ipairs(SkillData.Summoning.Marks) do
  end
-- Tablets & Non-shard items
  --Cooking
if recipe.itemID == item.id or Shared.contains(recipe.nonShardItemCosts, item.id) then
  if item.cookedItemID ~= nil or Shared.contains(itemUseArray.Cooking, item.name) then
addUse(SkillEnum.Summoning)
    table.insert(useArray, chr..Icons.Icon({'Cooking', type='skill'}))
break
  end
else
  --Crafting
-- Shards
  if canCraft or Shared.contains(itemUseArray.Crafting, item.name) then
for j, itemCost in ipairs(recipe.itemCosts) do
    table.insert(useArray, chr..Icons.Icon({'Crafting', type='skill'}))
if itemCost.id == item.id then
  end
addUse(SkillEnum.Summoning)
  --Farming
break
  if item.grownItemID ~= nil or Shared.contains(itemUseArray.Farming, item.name) then
end
    table.insert(useArray, chr..Icons.Icon({'Farming', type='skill'}))
end
  end
if hasUse(SkillEnum.Summoning) then
  --Firemaking
break
  if item.firemakingID ~= nil or Shared.contains(itemUseArray.Firemaking, item.name) then
end
    table.insert(useArray, chr..Icons.Icon({'Firemaking', type='skill'}))
end
  end
end
  --Fishing
end
  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:
-- Prayer
if item.prayerPoints ~= nil then
table.insert(categoryArray, '[[Category:Buriable Items]]')
if not hasUse(SkillEnum.Prayer) then
addUse(SkillEnum.Prayer)
end
end


  --Mastery Tokens are tied to 'Mastery'
-- Magic
  if item.isToken and item.skill ~= nil then
if not (hasUse('Magic') and hasUse('AltMagic')) then
    table.insert(useArray, chr..Icons.Icon({'Mastery'}))
-- First check if the item its self is used in any spells
  end
local spellList = Magic.getSpellsForItem(item.id, true)
for i, spell in ipairs(spellList) do
local useKey = (spell.type == 'AltMagic' and 'AltMagic' or 'Magic')
if not hasUse(useKey) then
addUse(useKey)
end
end
-- Check if the item provides runes, if it does check where they are used also
if item.providesRune ~= nil then
for i, runeID in ipairs(item.providesRune) do
if hasUse('Magic') and hasUse('AltMagic') then
break
else
local spellList = Magic.getSpellsForItem(runeID, false)
for j, spell in ipairs(spellList) do
local useKey = (spell.type == 'AltMagic' and 'AltMagic' or 'Magic')
if not hasUse(useKey) then
addUse(useKey)
end
end
end
end
end
end


  --Skillcapes are tied to the appropriate skill
-- Other odds and ends:
  --Except Max 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'}
-- Mastery Tokens are tied to 'Mastery'
  if Shared.contains({'Max Skillcape', 'Aorpheat's Signet Ring', 'Cape of Completion'}, item.name) then
if item.isToken and item.skill ~= nil then
    table.insert(useArray, chr..'All skills')
addUse('Mastery')
  elseif item.name == 'Magic Skillcape' then
end
    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
-- 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', 'HP Skillcape', 'Defence Skillcape'}
if Shared.contains({'Maximum Skillcape', "Aorpheat's Signet Ring", 'Ring of Wealth', 'Cape of Completion'}, item.name) then
addUse('AllSkills')
elseif item.name == 'Magic Skillcape' then
addUse(SkillEnum.Magic)
addUse('AltMagic')
elseif Shared.contains(item.name, 'Skillcape') and not Shared.contains(ignoreCapes, item.name) then
local skillName = Shared.splitString(item.name, ' ')[1]
addUse(skillName)
end


  --Special note for Charge Stone of Rhaelyx
if Shared.contains(item.name, 'Skillcape') or item.name == 'Cape of Completion' then
  if item.name == 'Charge Stone of Rhaelyx' then
table.insert(categoryArray, '[[Category:Skillcapes]]')
    table.insert(useArray, chr..'Powering '..Icons.Icon({'Crown of Rhaelyx', type='item'}))
end
  end


  --Some items are needed to make shop purchases
--Special note for Charge Stone of Rhaelyx
  local shopArray = Shop.getItemCostArray(item.id)
if item.name == 'Charge Stone of Rhaelyx' then
  if Shared.tableCount(shopArray) > 0 then
addUse('ChargeStone')
    table.insert(useArray, chr..Icons.Icon({'Shop'}))
end
  end


  if canUpgrade then
--Some items are needed to make shop purchases
    if item.canUpgrade or (item.type == 'Armour' and item.canUpgrade == nil) then
local shopArray = Shop.getItemCostArray(item.id)
      table.insert(categoryArray, '[[Category:Upgradeable Items]]')
if Shared.tableCount(shopArray) > 0 then
    end
addUse('Shop')
    table.insert(useArray, chr..'[[Upgrading Items]]')
end
  end


  local resultPart = {}
-- Generate result text
  table.insert(resultPart, asList and table.concat(useArray,'\r\n') or table.concat(useArray, '<br/>'))
local useArray = {}
  if addCategories then table.insert(resultPart, table.concat(categoryArray, '')) end
local prefix, delim = asList and '* ' or '', asList and '\r\n' or '<br/>'
  return table.concat(resultPart)
for skillID, skillName in Shared.spairs(skillUses, function(t, a, b) return t[a] < t[b] end) do
table.insert(useArray, prefix .. Icons.Icon({skillName, type='skill'}))
end
for use, _ in Shared.skpairs(otherUses) do
table.insert(useArray, prefix .. (otherUseText[use] or use))
end
 
return table.concat(useArray, delim) .. (addCategories and table.concat(categoryArray, '') or '')
end
end


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


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


function p._getItemUseTable(item)
function p._getItemUseTable(item)
  local useArray = {}
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})
          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
    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.herbloreLevel)
          local masteryLvl = potTierMastery[item2.potionTier]
          if masteryLvl > 0 then
            rowReq = rowReq..'<br/>'..Icons._MasteryReq(item2.name, masteryLvl)
          end
          local reqVal = potionData.herbloreLevel + (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
-- Loop through all items to find anything that can be upgraded using our source
  if item.grownItemID ~= nil then
for i, item2 in ipairs(ItemData.Items) do
    local item2 = Items.getItemByID(item.grownItemID)
if item2.itemsRequired ~= nil then
    local mat = {{id = item.id, qty = item.seedsRequired}}
for j, req in pairs(item2.itemsRequired) do
    local xp = item.farmingXP
if req[1] == item.id then
    local rowReq = item.farmingLevel
local mat = item2.itemsRequired
    local qty = 5
local xp = 'N/A'
    table.insert(useArray, {item = item2, qty = qty, mats = mat, skill = 'Farming', req = rowReq, xp = xp})
local rowReq = nil
  end
--Potions do have upgrade requirements though
  if item.cookedItemID ~= nil then
if item2.potionTier ~= nil then
    local item2 = Items.getItemByID(item.cookedItemID)
rowReq = Icons._MasteryReq(item2.name, SkillData.Herblore.TierMasteryLevels[item2.potionTier + 1])
    local mat = {{id = item.id, qty = 1}}
end
    local xp = item.cookingXP
table.insert(useArray, {item = {id = item2.id, name = item2.name}, qty = 1, mats = mat, skill = 'Upgrade', req = rowReq, xp = xp, gp = item2.trimmedGPCost})
    local rowReq = item.cookingLevel
break
    local qty = 1
end
    table.insert(useArray, {item = item2, qty = qty, mats = mat, skill = 'Cooking', req = rowReq, xp = xp})
end
  end
end
  if item.burntItemID ~= nil then
end
    local item2 = Items.getItemByID(item.burntItemID)
    local mat = {{id = item.id, qty = 1}}
    local xp = 1
    local rowReq = item.cookingLevel
    local qty = 1
    table.insert(useArray, {item = item2, qty = qty, mats = mat, skill = 'Cooking', req = rowReq, xp = xp})
  end


  --Handle shop purchases using Module:Shop
-- Cooking, Smithing, Fletching, Crafting, Runecrafting, Herblore
  local shopUses = Shop.getItemCostArray(item.id)
-- All have somewhat consistent recipe data structures
  for i, purchase in Shared.skpairs(shopUses) do
local recipeSkillIDs = {
    local rowReq = Shop.getRequirementString(purchase.unlockRequirements)
SkillEnum.Cooking,
    local iconType = (purchase.contains.items ~= nil and Shared.tableCount(purchase.contains.items) > 0) and 'item' or 'upgrade'
SkillEnum.Smithing,
    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})
SkillEnum.Fletching,
  end
SkillEnum.Crafting,
SkillEnum.Runecrafting,
SkillEnum.Herblore
}
for i, recipeSkillID in ipairs(recipeSkillIDs) do
local skillName = Constants.getSkillName(recipeSkillID)
local recipeKey = (recipeSkillID == SkillEnum.Herblore and 'Potions') or 'Recipes'
-- Iterate over all recipes for the current skill
for j, recipe in ipairs(SkillData[skillName][recipeKey]) do
local costLists = {recipe.alternativeCosts or {}, {{["itemCosts"] = recipe.itemCosts}}}
for k, costList in pairs(costLists) do
for m, costDef in pairs(costList) do
for n, itemCost in ipairs(costDef.itemCosts) do
if itemCost.id == item.id then
local recipeItemIDs = nil
if recipeSkillID == SkillEnum.Herblore then
recipeItemIDs = recipe.potionIDs
elseif recipeSkillID == SkillEnum.Cooking then
recipeItemIDs = {recipe.itemID, recipe.perfectCookID}
else
recipeItemIDs = {recipe.itemID}
end
for o, recipeItemID in ipairs(recipeItemIDs) do
local recipeItem = Items.getItemByID(recipeItemID)
if recipeItem ~= nil then
local itemDef = {id = recipe.itemID, name = recipeItem.name}
local qty = (recipe.baseQuantity or 1) * (costDef.quantityMultiplier or 1)
local rowReq = recipe.level
local reqVal = nil
if recipeSkillID == SkillEnum.Herblore then
-- Herblore may also have a mastery requirement
local masteryLvl = SkillData.Herblore.TierMasteryLevels[o]
if masteryLvl ~= nil and masteryLvl > 1 then
local masteryReq = Icons._MasteryReq(recipeItem.name, masteryLvl)
reqVal = rowReq + masteryLvl * 0.01
rowReq = Icons._SkillReq(skillName, rowReq) .. '<br/>' .. masteryReq
end
end
table.insert(useArray, {item = itemDef, qty = qty, mats = costDef.itemCosts, gp = recipe.gpCost, sc = recipe.scCost, skill = skillName, reqVal = reqVal, req = rowReq, xp = recipe.baseXP})
end
end
break
end
end
end
end
end
end


  --Finally build the table using what we've learned
-- Farming
  table.sort(useArray, function(a, b)
if item.grownItemID ~= nil then
                        local aReqVal = a.reqVal ~= nil and a.reqVal or a.req
local item2 = Items.getItemByID(item.grownItemID)
                        local bReqVal = b.reqVal ~= nil and b.reqVal or b.req
local mat = {{id = item.id, qty = item.seedsRequired}}
                        if a.skill ~= b.skill then
local xp = item.farmingXP
                          return a.skill < b.skill
local rowReq = item.farmingLevel
                        elseif type(aReqVal) ~= type(bReqVal) then
local qty = (item.tier ~= nil and item.tier == 'Tree' and 35 or 15)
                          return tostring(aReqVal) < tostring(bReqVal)
table.insert(useArray, {item = {id = item2.id, name = item2.name}, qty = qty, mats = mat, skill = 'Farming', req = rowReq, xp = xp})
                        elseif aReqVal ~= bReqVal then
end
                          return aReqVal < bReqVal
                        else
                          return a.item.name < b.item.name
                        end end)


  local obstacles = Agility.getObstaclesForItem(item.id)
-- Agility
local obstacles = Agility.getObstaclesForItem(item.id)
for i, obstacle in ipairs(obstacles) do
local itemCosts = {}
for j, itemDef in ipairs(obstacle.cost.items) do
table.insert(itemCosts, {id = itemDef[1], qty = itemDef[2]})
end
local req = Agility._getObstacleRequirements(obstacle)
--local objType = (obstacle.category == nil and 'Pillar') or 'Obstacle'
table.insert(useArray, {item = {id = obstacle.id, name = obstacle.name}, qty = 1, mats = itemCosts, gp = obstacle.cost.gp, sc = obstacle.cost.slayerCoins, skill = 'Agility', req = req, type = 'skill'})
end


  local spellUseTable = p._getSpellUseTable(item)
-- Summoning
  local resultPart = {}
for i, recipe in ipairs(SkillData.Summoning.Marks) do
  if Shared.tableCount(useArray) == 0 and Shared.tableCount(obstacles) == 0 then
local recipeGPCost = SkillData.Summoning.RecipeGPCost
    if string.len(spellUseTable) > 0 then
local useShards = false
      return '==Uses==\r\n==='..Icons.Icon({'Magic', type='skill', size='30'})..'===\r\n'..spellUseTable
local recipeItem = nil
    else
for j, itemCost in ipairs(recipe.itemCosts) do
      return ''
if itemCost.id == item.id then
    end
useShards = true
  end
break
  table.insert(resultPart, '{| class="wikitable sortable"')
end
  table.insert(resultPart, '\r\n!colspan=2|Item Created!!Type!!Requirements!!XP!!Ingredients')
end
  for i, row in pairs(useArray) do
-- Non-shard items
    local qty = row.qty ~= nil and row.qty or 1
for j, nonShardItemID in ipairs(recipe.nonShardItemCosts) do
    local iconType = row.type ~= nil and row.type or 'item'
if useShards or nonShardItemID == item.id then
    table.insert(resultPart, '\r\n|-\r\n|data-sort-value="'..row.item.name..'"|')
-- Item is used in this particular synergy recipe
    table.insert(resultPart, Icons.Icon({row.item.name, type=iconType, notext=true, size=50})..'||')
if recipeItem == nil then
    if qty > 1 then table.insert(resultPart, "'''"..qty.."x''' ") end
recipeItem = Items.getItemByID(recipe.itemID)
    table.insert(resultPart, '[['..row.item.name..']]')
end
    if row.skill == 'Upgrade' then
local nonShardItem = Items.getItemByID(nonShardItemID)
      table.insert(resultPart, '||data-sort-value="Upgrade"|[[Upgrading Items|Upgrade]]')
local itemValue = math.max(nonShardItem.sellsFor, 20)
    elseif row.skill == 'Shop' then
local nonShardQty = math.max(1, math.floor(recipeGPCost / itemValue))
      table.insert(resultPart, '||data-sort-value="Shop"|'..Icons.Icon({'Shop'}))
local recipeCosts = Shared.clone(recipe.itemCosts)
    else
table.insert(recipeCosts, {id = nonShardItemID, qty = nonShardQty})
      table.insert(resultPart, '||data-sort-value="'..row.skill..'"|'..Icons.Icon({row.skill, type='skill'}))
table.insert(useArray, {item = {id = recipe.itemID, name = recipeItem.name}, qty = recipe.baseQuantity, mats = recipeCosts, gp = recipe.gpCost, sc = recipe.scCost, skill = 'Summoning', req = recipe.level, xp = recipe.baseXP})
    end
end
    if type(row.req) == 'number' then
end
      table.insert(resultPart, '|| style="text-align:right" data-sort-value="'..row.req..'"|'..Icons._SkillReq(row.skill, row.req))
end
    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
--Handle shop purchases using Module:Shop
      if matID >= 0 then
local shopUses = Shop.getItemCostArray(item.id)
        -- Item
for i, purchase in ipairs(shopUses) do
        local matItem = Items.getItemByID(matID)
local rowReq = Shop.getRequirementString(purchase.unlockRequirements)
        if matItem == nil then
local iconType = (purchase.contains.items ~= nil and Shared.tableCount(purchase.contains.items) > 0) and 'item' or 'upgrade'
          matText = 'ERROR: Failed to find item with ID ' .. matID .. '[[Category:Pages with Script Errors]]'
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})
        else
end
          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
--Finally build the table using what we've learned
  for i, obst in Shared.skpairs(obstacles) do
table.sort(useArray, function(a, b)
    table.insert(resultPart, '\r\n|-\r\n|')
local aReqVal = a.reqVal ~= nil and a.reqVal or a.req
    table.insert(resultPart, Icons.Icon({"Agility", type="skill", size="50", notext=true}))
local bReqVal = b.reqVal ~= nil and b.reqVal or b.req
    table.insert(resultPart, '||[[Agility#Obstacles|'..obst.name..']]')
if a.skill ~= b.skill then
    table.insert(resultPart, '||'..Icons.Icon({"Agility", type="skill"}))
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)


    --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, '||'..table.concat(reqArray, '<br/>'))


    --Just including 'N/A' for XP since it doesn't really apply for Agility Obstacles
local resultPart = {}
    table.insert(resultPart, '||N/A')
if Shared.tableCount(useArray) > 0 then
local typeTextList = {
["Shop"] = Icons.Icon({'Shop'}),
["Upgrade"] = '[[Upgrading Items|Upgrade]]'
}


    --Finally the cost
-- Header
    local cost = obst.cost
table.insert(resultPart, '{| class="wikitable stickyHeader sortable"')
    local costArray = {}
table.insert(resultPart, '\r\n|- class="headerRow-0"')
    if cost.gp ~= nil and cost.gp > 0 then
table.insert(resultPart, '\r\n!colspan=2|Item Created!!Type!!Requirements!!XP!!Ingredients')
      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/>'))
-- Rows
 
for i, row in ipairs(useArray) do
  end
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|}')
local iconName = row.item.name
  if string.len(spellUseTable) > 0 then
if row.skill == 'Agility' then
    table.insert(resultPart, '\r\n==='..Icons.Icon({'Magic', type='skill', size='30'})..'===\r\n'..spellUseTable)
iconName = 'Agility'
  end
end
  return '==Uses==\r\n'..table.concat(resultPart)
local typeName = row.skill ~= nil and row.skill or ''
local typeText = typeTextList[typeName] or Icons.Icon({typeName, type='skill'}) or ''
local reqVal, reqText = row.reqVal, 'None'
if type(row.req) == 'number' then
reqVal = row.req
reqText = Icons._SkillReq(typeName, row.req)
elseif type(row.req) == 'string' then
reqText = row.req
end
local xpVal, xpText = 0, 'N/A'
if type(row.xp) == 'string' then
xpText = row.xp
elseif type(row.xp) == 'number' then
xpVal = row.xp
xpText = Shared.formatnum(row.xp) .. ' ' .. Icons.Icon({typeName, type='skill', notext=true}) .. ' XP'
end
local matRow = {}
if type(row.mats) == 'table' then
for j, itemCost in ipairs(row.mats) do
local matItemID = itemCost.id or itemCost[1] or -1
local matItem = Items.getItemByID(matItemID)
local matQty = itemCost.qty or itemCost[2] or 1
if matItem == nil then
table.insert(matRow, 'ERROR: Failed to find item with ID ' .. itemCost.id .. '[[Category:Pages with script errors]]')
elseif type(matQty) == 'number' then
table.insert(matRow, Icons.Icon({matItem.name, type='item', qty=matQty}))
else
table.insert(matRow, Icons.Icon({matItem.name, type='item'}))
end
end
end
if row.gp ~= nil and row.gp > 0 then
table.insert(matRow, Icons.GP(row.gp))
end
if row.sc ~= nil and row.sc > 0 then
table.insert(matRow, Icons.SC(row.sc))
end
-- Item created
table.insert(resultPart, '\r\n|-\r\n|data-sort-value="' .. row.item.name .. '"| ')
table.insert(resultPart, Icons.Icon({iconName, row.item.name, type=iconType, notext=true, size=50}))
table.insert(resultPart, '\r\n| ')
if qty > 1 then
table.insert(resultPart, "'''" .. Shared.formatnum(qty) .. "x''' ")
end
table.insert(resultPart, Icons.Icon({iconName, row.item.name, type=iconType, noicon=true}))
-- Type
table.insert(resultPart, '\r\n|data-sort-value="' .. typeName .. '"| ' .. typeText)
-- Requirements
table.insert(resultPart, '\r\n|style="text-align:right;"')
if row.reqVal ~= nil then
table.insert(resultPart, ' data-sort-value="' .. reqVal .. '"')
end
table.insert(resultPart, '| ' .. reqText)
-- XP
table.insert(resultPart, '\r\n|style="text-align:right;" data-sort-value="' .. xpVal .. '"| ' .. xpText)
-- Ingredients
table.insert(resultPart, '\r\n| ' .. table.concat(matRow, '<br/>'))
end
table.insert(resultPart, '\r\n|}')
end
local spellUseTable = p._getSpellUseTable(item)
if spellUseTable ~= nil and spellUseTable ~= '' then
table.insert(resultPart, '\r\n===' .. Icons.Icon({'Magic', type='skill', size=30}) .. '===\r\n' .. spellUseTable)
end
if Shared.tableCount(resultPart) == 0 then
return ''
else
return '==Uses==\r\n' .. table.concat(resultPart)
end
end
end


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


  return p._getItemUseTable(item)
return p._getItemUseTable(item)
end
end


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


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


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


  return p._getSpellUseTable(item)
--[==[
-- Uncomment this block and execute 'p.test()' within the debug console
-- to test after making changes
function p.test()
local checkItems = {
'Gold Bar',
'Raw Shrimp',
'Coal Ore',
'Rune Platebody',
'Arrow Shafts',
'Garum Seeds',
'Rune Essence',
'Runite Bar',
'Water Rune',
'Steam Rune',
'Controlled Heat Potion II',
'Wolf',
'Cyclops',
'Leprechaun',
'Redwood Logs',
'Carrot Cake',
'Carrot Cake (Perfect)',
'Mantalyme Herb',
'Carrot',
'Topaz',
'Rune Essence',
'Infernal Claw',
'Chapeau Noir',
'Stardust',
'Rope',
'Ancient Ring of Mastery',
'Mysterious Stone',
'Mastery Token (Cooking)',
'Gem Gloves',
'Basic Bag'
}
local checkFuncs = {
p.getItemUses,
p.getItemUseTable
}
local errCount = 0
for i, item in ipairs(checkItems) do
local param = {args={item}}
mw.log('=' .. item .. '=')
for j, func in ipairs(checkFuncs) do
local callSuccess, retVal = pcall(func, param)
if not callSuccess then
errCount = errCount + 1
mw.log('Error with item "' .. item .. '": ' .. retVal)
else
mw.log(retVal)
end
end
end
if errCount == 0 then
mw.log('Test successful')
else
mw.log('Test failed with ' .. errCount .. ' failures')
end
end
end
--]==]


return p
return p