Module:Skills/Artisan

From Melvor Idle
< Module:Skills
Revision as of 04:06, 30 December 2021 by Falterfire (talk | contribs) (added GP icon to item price column in crafting tables)

Documentation for this module may be created at Module:Skills/Artisan/doc

--Splitting some functions into here to avoid bloating a single file
--Contains function for skills that consume resources (ie smithing, cooking, herblore, etc.)
local p = {}

local SkillData = mw.loadData('Module:Skills/data')

local Shared = require('Module:Shared')
local Items = require('Module:Items')
local Icons = require('Module:Icons')

function p.getCookedItemsTable(frame)
	local category = frame.args ~= nil and frame.args[1] or frame
	local itemArray = nil
	
	if category == "Cooking Fire" then 
		itemArray = Items.getItems(function(item) return item.cookingCategory == 0 end)
	elseif category == "Furnace" then 
		itemArray = Items.getItems(function(item) return item.cookingCategory == 1 and item.name ~= 'Lemon Cake' end)
	elseif category == "Pot"  then 
		itemArray = Items.getItems(function(item) return item.cookingCategory == 2 end)
	else
		itemArray = Items.getItems(function(item) return item.cookingCategory ~= nil and item.name ~= 'Lemon Cake' end)
	end
	table.sort(itemArray, function(a, b) return a.cookingLevel < b.cookingLevel end)
	
	-- Logic for generating some cells of the table which are consistent for normal & perfect items
	local getHealingCell = function(item, qty)
		if item ~= nil then
			return 'data-sort-value="'..(math.floor(item.healsFor) * qty)..'"|'..Icons.Icon({"Hitpoints", type="skill", notext=true})..' '..math.floor(item.healsFor * 10)..(qty > 1 and ' (x'..qty..')' or '')
		else
			return ' '
		end
	end
	local getSaleValueCell = function(item, qty)
		if item ~= nil then
			return 'data-sort-value="'..(math.floor(item.sellsFor) * qty)..'"|'..Icons.GP(math.floor(item.sellsFor))..(qty > 1 and ' (x'..qty..')' or '')
		else
			return ' '
		end
	end
	
	local result = '{| class="wikitable sortable stickyHeader"'
	result = result..'\r\n|- class="headerRow-0"'
	result = result..'\r\n!colspan="3" rowspan="2"|Cooked Item!!rowspan="2"|'..Icons.Icon({'Cooking', type='skill', notext=true})..' Level'
	result = result..'!!rowspan="2"|Cook Time!!rowspan="2"|XP!!colspan="2"|Healing!!colspan="2"|Value!!rowspan="2"|Ingredients'
	result = result..'\r\n|- class="headerRow-1"'
	result = result..'\r\n!Normal!!' .. Icons.Icon({'Perfect', type='bonus', ext='png', notext=true, nolink=true}) .. '!!Normal!!' .. Icons.Icon({'Perfect', type='bonus', ext='png', notext=true, nolink=true})
	
	for i, item in Shared.skpairs(itemArray) do
		local perfectItem = nil
		if item.perfectItem ~= nil then
			perfectItem = Items.getItemByID(item.perfectItem)
		end
		local qty = item.cookingQty
		if qty == nil then
			qty = 1
		end
		result = result..'\r\n|-'
		result = result..'\r\n|style="min-width:25px"|'..Icons.Icon({item.name, type='item', notext=true, size='50'})
		result = result..'\r\n|style="min-width:25px"| '
		if perfectItem ~= nil then
			result = result..Icons.Icon({perfectItem.name, type='item', notext=true, size='50'})
		end
		result = result..'||'
		if qty > 1 then
			result = result..qty..'x '
		end
		result = result..Icons.Icon({item.name, type='item', noicon = true})
		result = result..'||style="text-align:right"|'..item.cookingLevel
		result = result..'||style="text-align:right" data-sort-value="' .. item.cookingInterval .. '"|'..Shared.timeString(item.cookingInterval / 1000, true)
		result = result..'||style="text-align:right"|'..item.cookingXP
		result = result..'||'..getHealingCell(item, qty)..'||'..getHealingCell(perfectItem, qty)
		result = result..'||'..getSaleValueCell(item, qty)..'||'..getSaleValueCell(perfectItem, qty)
			local matArray = {}
			for j, reqSet in pairs(item.recipeRequirements)  do
				for k, mat in pairs(reqSet) do
				local matItem = Items.getItemByID(mat.id)
				table.insert(matArray, Icons.Icon({matItem.name, type='item', notext=true, qty=mat.qty}))
				end
		end
			result = result..'\r\n|'..table.concat(matArray, ' ')
	end

	result = result..'\r\n|}'
	return result
end

local tierSuffix = { 'I', 'II', 'III', 'IV' }
function p._getHerblorePotionTable(category)
	if string.upper(category) == 'COMBAT' then
		category = 0
	elseif string.upper(category) == 'SKILL' then
		category = 1
	elseif type(category) == 'string' then
		category = tonumber(category)
	end

	local potionArray = {}
	for i, potion in Shared.skpairs(SkillData.Herblore.ItemData) do
		if potion.category == category then
			table.insert(potionArray, potion)
		end
	end

	local result = '{|class = "wikitable sortable stickyHeader"'
	result = result..'\r\n|- class="headerRow-0"'
	result = result..'\r\n!Potion!!'..Icons.Icon({'Herblore', type='skill', notext=true})..' Level'
	result = result..'!!XP!!Ingredients!!colspan="2"|Tier!!Value!!Charges!!Effect'

	table.sort(potionArray, function(a, b) return a.level < b.level end)

	for i, potion in Shared.skpairs(potionArray) do
		local tierPots = {}
		for j = 1, 4, 1 do
			table.insert(tierPots, Items.getItemByID(potion.itemID[j]))
		end
		result = result..'\r\n|-'
		if potion.name == 'Bird Nests Potion' then
			result = result..'\r\n|rowspan="4"|[[Bird Nest Potion]]'
		else
			result = result..'\r\n|rowspan="4"|[['..potion.name..']]'
		end
		result = result..'||rowspan="4" style="text-align:right"|'..potion.level
		result = result..'||rowspan="4" style="text-align:right"|'..potion.herbloreXP

		local matArray = {}
		for j, mat in Shared.skpairs(tierPots[1].herbloreReq) do
			local matItem = Items.getItemByID(mat.id)
			table.insert(matArray, Icons.Icon({matItem.name, type='item', notext=true, qty=mat.qty}))
		end
		result = result..'||rowspan="4"|'..table.concat(matArray, ', ')..'||'
		
		local tierRows = {}
		for j, tierPot in Shared.skpairs(tierPots) do
			local rowTxt = Icons.Icon({tierPot.name, type='item', notext=true})
			rowTxt = rowTxt..'||'..Icons.Icon({tierPot.name, tierSuffix[j], type = 'item', noicon = true})
			rowTxt = rowTxt..'||style="text-align:right;" data-sort-value="'..tierPot.sellsFor..'"|'..Icons.GP(tierPot.sellsFor)
			rowTxt = rowTxt..'||style="text-align:right;"|'..tierPot.potionCharges..'||'..tierPot.description
			table.insert(tierRows, rowTxt)
		end
		result = result..table.concat(tierRows, '\r\n|-\r\n|')
	end

	result = result..'\r\n|}'
	return result
end

function p.getHerblorePotionTable(frame)
	local category = frame.args ~= nil and frame.args[1] or frame
	return p._getHerblorePotionTable(category)
end

function p.getRunecraftingTable(frame)
	local category = frame.args ~= nil and frame.args[1] or frame
	local data = nil

	if     category == "Runes"      then data = 
				 Items.getItems(function(item) return item.runecraftingCategory == 0 end)
	elseif category == "ComboRunes" then data = 
				 Items.getItems(function(item) return item.runecraftingCategory == 1 end)
	elseif category == "Weapons"    then data = 
				 Items.getItems(function(item) return item.runecraftingCategory == 2 and item.runecraftingID end)
	elseif category == "AirGear"    then data = 
				 Items.getItems(function(item) return item.runecraftingCategory == 3 end)
	elseif category == "WaterGear"  then data = 
				 Items.getItems(function(item) return item.runecraftingCategory == 4 end)
	elseif category == "EarthGear"  then data = 
				 Items.getItems(function(item) return item.runecraftingCategory == 5 end)
	elseif category == "FireGear"   then data = 
				 Items.getItems(function(item) return item.runecraftingCategory == 6 end)
	end

	if data == nil then
		return "ERROR: Invalid Runecrafting category name.[[Category:Pages with script errors]]"
	end

	local result = '{| class="wikitable sortable stickyHeader"'
	result = result..'\r\n|- class="headerRow-0"'
	result = result..'\r\n!Item\r\n!Name\r\n!'..Icons.Icon({'Runecrafting', type='skill', notext=true})..' Level\r\n!Experience'
	result = result..'\r\n!Item Price\r\n!Ingredients\r\n!XP/s\r\n!GP/s'

	table.sort(data, function(a, b) return (a.runecraftingLevel == b.runecraftingLevel and a.id < b.id) 
																			 or a.runecraftingLevel <  b.runecraftingLevel end)

	for i, rune in Shared.skpairs(data) do
		result = result..'\r\n|-'
		result = result..'\r\n| style="text-align: left;" | '..Icons.Icon({rune.name, type='item', size='50', notext=true})
		result = result..'\r\n| style ="text-align: left;" |'..Icons.Icon({rune.name, type='item', noicon=true})
		result = result..'\r\n| style="text-align:right"|'..rune.runecraftingLevel
		result = result..'\r\n| style="text-align:right"|'..rune.runecraftingXP
		result = result..'\r\n| style="text-align:right"|'..rune.sellsFor

		local matArray = {}
		for j, mat in Shared.skpairs(rune.runecraftReq) do
			local matItem = Items.getItemByID(mat.id)
			table.insert(matArray, Icons.Icon({matItem.name, type='item', notext=true, qty=mat.qty}))
		end
		result = result..'\r\n|'..table.concat(matArray, ' ')

		local rcCraftTime = 2.00
		local xps = rune.runecraftingXP / rcCraftTime
		local gps = rune.sellsFor / rcCraftTime
		result = result..'\r\n| style="text-align:right"|'..string.format("%.2f", xps)
		result = result..'\r\n| style="text-align:right"|'..string.format("%.2f", gps)
	end

	result = result..'\r\n|}'
	return result
end

function p.getFletchingTable(frame)
	local category = frame.args ~= nil and frame.args[1] or frame
	local data = nil

	if     category == "Arrows"    then 
		data = Items.getItems(function(item) return item.fletchingCategory == 0 end)
	elseif category == "Shortbows" then 
		data = Items.getItems(function(item) return item.fletchingCategory == 1 end)
	elseif category == "Longbows"  then 
		data = Items.getItems(function(item) return item.fletchingCategory == 2 end)
	elseif category == "Bolts"     then 
		data =  Items.getItems(function(item) return item.fletchingCategory == 3 end)
	elseif category == "Crossbows" then 
		data = Items.getItems(function(item) return item.fletchingCategory == 4 end)
	elseif category == "Javelins"  then 
		data = Items.getItems(function(item) return item.fletchingCategory == 5 end)
	end

	if data == nil then
		return "ERROR: Invalid Fletching category name.[[Category:Pages with script errors]]"
	end

	local result = '{| class="wikitable sortable stickyHeader"'
	result = result..'\r\n|- class="headerRow-0"'
	result = result..'\r\n!Item\r\n!Name\r\n!Fletching Level\r\n!Experience'
	result = result..'\r\n!Quantity\r\n!Sells For\r\n!Ingredients'

	table.sort(data, function(a, b) return (a.fletchingLevel == b.fletchingLevel and a.id < b.id) 
											 or a.fletchingLevel <  b.fletchingLevel end)

	for i, fletch in Shared.skpairs(data) do
		result = result..'\r\n|-'
		result = result..'\r\n| style="text-align: left;" | '..Icons.Icon({fletch.name, type='item', size='50', notext=true})
		result = result..'\r\n| style ="text-align: left;" |'..Icons.Icon({fletch.name, type='item', noicon=true})
		result = result..'\r\n| style="text-align:right"|'..fletch.fletchingLevel
		result = result..'\r\n| style="text-align:right"|'..fletch.fletchingXP
		result = result..'\r\n| style="text-align:right"|'..fletch.fletchQty
		result = result..'\r\n| style="text-align:right"|'..fletch.sellsFor

		local matArray = {}
		for j, mat in Shared.skpairs(fletch.fletchReq) do
			local matItem = Items.getItemByID(mat.id)
			table.insert(matArray, Icons.Icon({matItem.name, type='item', notext=true, qty=mat.qty}))
		end
		result = result..'\r\n|'..table.concat(matArray, ' ')
	end

	result = result..'\r\n|}'
	return result
end

function p.getCraftingTable(frame)
	local category = frame.args ~= nil and frame.args[1] or frame
	local data = nil

	if     category == "Leather"    then data = 
				 Items.getItems(function(item) return item.tier == "Leather" or item.tier == "Hard Leather" end)
	elseif category == "Dragonhide" then data = 
				 Items.getItems(function(item) return item.tier == "Dragonhide" and item.craftingLevel ~= nil end)
	elseif category == "Rings"      then data = 
				 Items.getItems(function(item) return (item.validSlots ~= nil and Shared.contains(item.validSlots, 'Ring')) and item.craftingLevel ~= nil end)
	elseif category == "Necklaces"  then data = 
				 Items.getItems(function(item) return (item.validSlots ~= nil and Shared.contains(item.validSlots, 'Amulet')) and item.craftingLevel ~= nil end)
	elseif category == "Bags"			then data =
			 Items.getItems(function(item) return item.type == 'Bag' and item.craftingLevel ~= nil end)
	end

	if data == nil then
		return "ERROR: Invalid Crafting category name.[[Category:Pages with script errors]]"
	end

	table.sort(data, function(a, b) return (a.craftingLevel == b.craftingLevel and a.id < b.id) 
													or a.craftingLevel <  b.craftingLevel end)

	local result = '{| class="wikitable sortable stickyHeader"'
	result = result..'\r\n|- class="headerRow-0"'
	result = result..'\r\n!Item\r\n!Name\r\n!'..Icons.Icon({'Crafting', type='skill', notext=true})..' Level\r\n!Experience'
	result = result..'\r\n!Item Price\r\n!Ingredients'

	for i, craft in Shared.skpairs(data) do
		result = result..'\r\n|-'
		result = result..'\r\n| style="text-align: left;" | '..Icons.Icon({craft.name, type='item', size='50', notext=true})
		result = result..'\r\n| style ="text-align: left;" |'..Icons.Icon({craft.name, type='item', noicon=true})
		result = result..'\r\n| style="text-align:right"|'..craft.craftingLevel
		result = result..'\r\n| style="text-align:right"|'..craft.craftingXP
		result = result..'\r\n| style="text-align:right" data-sort-value="'..craft.sellsFor..'"|'..Icons.GP(craft.sellsFor)

		local matArray = {}
		if craft.craftGPCost ~= nil and craft.craftGPCost > 0 then
			table.insert(matArray, Icons.GP(craft.craftGPCost))
		end
		for j, mat in Shared.skpairs(craft.craftReq) do
			local matItem = Items.getItemByID(mat.id)
			table.insert(matArray, Icons.Icon({matItem.name, type='item', notext=true, qty=mat.qty}))
		end
		result = result..'\r\n|'..table.concat(matArray, ', ')
	end

	result = result..'\r\n|}'
	return result
end

return p