Module:Items/UseTables

From Melvor Idle
< Module:Items
Revision as of 19:16, 8 December 2021 by Falterfire (talk | contribs) (Fixed indenting)
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 = {},
	Astrology = {'Stardust', 'Golden Stardust'},
	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',
	[26] = 'Combat',
	[27] = 'Combat',
	[28] = 'Combat',
	[29] = 'Astrology'
}

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
		if potionUseArray[item.masteryID[2]] ~= nil then
			table.insert(itemUseArray[potionUseArray[item.masteryID[2]]], item.name)
		else
			table.insert(itemUseArray["Combat"], item.name)
		end
	end

	--If the item has any modifiers that affect a given skill, add it to those lists
	--Added an exception for Mastery Tokens since they were being incorrectly flagged as usable for all skills
	if item.modifiers ~= nil and (item.isToken == nil or not item.isToken) 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 item.specialAttacks ~= nil 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
	--Astrology
	if Shared.contains(itemUseArray.Astrology, item.name) then
		table.insert(useArray, chr..Icons.Icon({'Astrology', 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', 'HP 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 = (item.tier ~= nil and item.tier == 'Tree' and 35 or 15)
		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