<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.runerealm.org/index.php?action=history&amp;feed=atom&amp;title=Module%3ASandbox%2FUser%3AWolaznik%2FUses_tool_list</id>
	<title>Module:Sandbox/User:Wolaznik/Uses tool list - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.runerealm.org/index.php?action=history&amp;feed=atom&amp;title=Module%3ASandbox%2FUser%3AWolaznik%2FUses_tool_list"/>
	<link rel="alternate" type="text/html" href="https://wiki.runerealm.org/index.php?title=Module:Sandbox/User:Wolaznik/Uses_tool_list&amp;action=history"/>
	<updated>2026-04-30T14:05:33Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.41.1</generator>
	<entry>
		<id>https://wiki.runerealm.org/index.php?title=Module:Sandbox/User:Wolaznik/Uses_tool_list&amp;diff=35221&amp;oldid=prev</id>
		<title>Alex: Created page with &quot;local p = {}  local commas = require(&#039;Module:Addcommas&#039;) local skillPic = require(&#039;Module:SCP&#039;)._main local yesNo = require(&#039;Module:Yesno&#039;) local lang = mw.getContentLanguage() local trim = mw.text.trim local split = mw.text.split local jsonDecode = mw.text.jsonDecode  function buildRow(recipe, tool) 	local ret = mw.html.create(&#039;tr&#039;) 	 	-- Outputs 	ret:tag(&#039;td&#039;):wikitext(recipe.output.image) 	ret:tag(&#039;td&#039;):attr(&#039;data-sort-value&#039;, recipe.output.name):wikitext(commas._add(...&quot;</title>
		<link rel="alternate" type="text/html" href="https://wiki.runerealm.org/index.php?title=Module:Sandbox/User:Wolaznik/Uses_tool_list&amp;diff=35221&amp;oldid=prev"/>
		<updated>2024-10-16T23:13:23Z</updated>

		<summary type="html">&lt;p&gt;Created page with &amp;quot;local p = {}  local commas = require(&amp;#039;Module:Addcommas&amp;#039;) local skillPic = require(&amp;#039;Module:SCP&amp;#039;)._main local yesNo = require(&amp;#039;Module:Yesno&amp;#039;) local lang = mw.getContentLanguage() local trim = mw.text.trim local split = mw.text.split local jsonDecode = mw.text.jsonDecode  function buildRow(recipe, tool) 	local ret = mw.html.create(&amp;#039;tr&amp;#039;) 	 	-- Outputs 	ret:tag(&amp;#039;td&amp;#039;):wikitext(recipe.output.image) 	ret:tag(&amp;#039;td&amp;#039;):attr(&amp;#039;data-sort-value&amp;#039;, recipe.output.name):wikitext(commas._add(...&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;local p = {}&lt;br /&gt;
&lt;br /&gt;
local commas = require(&amp;#039;Module:Addcommas&amp;#039;)&lt;br /&gt;
local skillPic = require(&amp;#039;Module:SCP&amp;#039;)._main&lt;br /&gt;
local yesNo = require(&amp;#039;Module:Yesno&amp;#039;)&lt;br /&gt;
local lang = mw.getContentLanguage()&lt;br /&gt;
local trim = mw.text.trim&lt;br /&gt;
local split = mw.text.split&lt;br /&gt;
local jsonDecode = mw.text.jsonDecode&lt;br /&gt;
&lt;br /&gt;
function buildRow(recipe, tool)&lt;br /&gt;
	local ret = mw.html.create(&amp;#039;tr&amp;#039;)&lt;br /&gt;
	&lt;br /&gt;
	-- Outputs&lt;br /&gt;
	ret:tag(&amp;#039;td&amp;#039;):wikitext(recipe.output.image)&lt;br /&gt;
	ret:tag(&amp;#039;td&amp;#039;):attr(&amp;#039;data-sort-value&amp;#039;, recipe.output.name):wikitext(commas._add(recipe.output.quantity) .. &amp;#039; × [[&amp;#039; .. recipe.output.name .. &amp;#039;]]&amp;#039; .. (recipe.output.subtxt ~= nil and &amp;#039;&amp;lt;br/&amp;gt;&amp;lt;small&amp;gt;(&amp;#039; .. recipe.output.subtxt .. &amp;#039;)&amp;lt;/small&amp;gt;&amp;#039; or &amp;#039;&amp;#039;))&lt;br /&gt;
&lt;br /&gt;
	-- Members&lt;br /&gt;
	if(yesNo(recipe.members)) then&lt;br /&gt;
		ret:tag(&amp;#039;td&amp;#039;):wikitext(&amp;quot;[[File:Member icon.png|center|link=Members|alt=Members]]&amp;quot;)&lt;br /&gt;
	elseif(not yesNo(recipe.members)) then&lt;br /&gt;
		ret:tag(&amp;#039;td&amp;#039;):wikitext(&amp;quot;[[File:Free-to-play icon.png|center|link=Free-to-play|alt=Free-to-play]]&amp;quot;)&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	--Tools&lt;br /&gt;
	local toolList = mw.html.create(&amp;#039;ul&amp;#039;):addClass(&amp;#039;products-materials&amp;#039;)&lt;br /&gt;
	local toolSortValue = nil&lt;br /&gt;
	local tools = split(recipe.tools, &amp;quot;,&amp;quot;)&lt;br /&gt;
	for i, toolV in ipairs(tools) do&lt;br /&gt;
		toolList:tag(&amp;#039;li&amp;#039;):attr(&amp;#039;data-sort-value&amp;#039;, i == 1 and tooV or &amp;#039;&amp;#039;):wikitext(toolV) -- For highlighting _all_ tools --- :addClass(&amp;#039;production-selected&amp;#039;)&lt;br /&gt;
	end&lt;br /&gt;
	ret:tag(&amp;#039;td&amp;#039;):addClass(&amp;#039;plainlist&amp;#039;):node(toolList)&lt;br /&gt;
	&lt;br /&gt;
	-- Skills (level)&lt;br /&gt;
	-- Skills (xp)&lt;br /&gt;
	local skillList = mw.html.create(&amp;#039;ul&amp;#039;):addClass(&amp;#039;skills-list&amp;#039;)&lt;br /&gt;
	local xpList = mw.html.create(&amp;#039;ul&amp;#039;):addClass(&amp;#039;skills-list&amp;#039;)&lt;br /&gt;
	&lt;br /&gt;
	if(#recipe.skills == 0) then&lt;br /&gt;
		skillList:tag(&amp;#039;li&amp;#039;):wikitext(&amp;#039;None&amp;#039;)&lt;br /&gt;
		xpList:tag(&amp;#039;li&amp;#039;):wikitext(&amp;#039;None&amp;#039;)&lt;br /&gt;
		ret:tag(&amp;#039;td&amp;#039;):addClass(&amp;#039;table-na plainlist&amp;#039;):node(skillList)&lt;br /&gt;
		ret:tag(&amp;#039;td&amp;#039;):addClass(&amp;#039;table-na plainlist&amp;#039;):node(xpList)&lt;br /&gt;
	else&lt;br /&gt;
		for i, skill in ipairs(recipe.skills) do&lt;br /&gt;
			skillList:tag(&amp;#039;li&amp;#039;):attr(&amp;#039;data-sort-value&amp;#039;, i == 1 and skill.level or &amp;#039;&amp;#039;):wikitext(skillPic(lang:ucfirst(skill.name), skill.level))&lt;br /&gt;
			xpList:tag(&amp;#039;li&amp;#039;):attr(&amp;#039;data-sort-value&amp;#039;, i == 1 and skill.experience or &amp;#039;&amp;#039;):wikitext(commas._strip(skill.experience) ~= nil and skillPic(lang:ucfirst(skill.name), skill.experience) or skill.experience)&lt;br /&gt;
		end&lt;br /&gt;
		ret:tag(&amp;#039;td&amp;#039;):addClass(&amp;#039;plainlist&amp;#039;):node(skillList)&lt;br /&gt;
		ret:tag(&amp;#039;td&amp;#039;):addClass(&amp;#039;plainlist&amp;#039;):node(xpList)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- Inputs&lt;br /&gt;
	local matList = mw.html.create(&amp;#039;ul&amp;#039;)&lt;br /&gt;
	local materialSortValue = nil&lt;br /&gt;
	for _, mat in ipairs(recipe.materials) do&lt;br /&gt;
		local quantity = string.gsub(mat.quantity, &amp;#039;%-&amp;#039;, &amp;#039;–&amp;#039;)&lt;br /&gt;
		if(materialSortValue == nil) then&lt;br /&gt;
			materialSortValue = quantity&lt;br /&gt;
		end&lt;br /&gt;
		matList:tag(&amp;#039;li&amp;#039;):wikitext(string.format(&amp;#039;%s × [[%s]]&amp;#039;, commas._add(quantity), mat.name))&lt;br /&gt;
	end&lt;br /&gt;
	ret:tag(&amp;#039;td&amp;#039;):addClass(&amp;#039;plainlist&amp;#039;):attr(&amp;#039;data-sort-value&amp;#039;, materialSortValue):node(matList)&lt;br /&gt;
	&lt;br /&gt;
	return ret&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function createHeader()&lt;br /&gt;
	local header = mw.html.create(&amp;#039;table&amp;#039;):addClass(&amp;#039;wikitable sortable products-list align-center-1 align-left-2 align-center-3&amp;#039;):done()&lt;br /&gt;
		header:tag(&amp;#039;tr&amp;#039;):tag(&amp;#039;th&amp;#039;):attr(&amp;#039;colspan&amp;#039;, &amp;#039;2&amp;#039;):wikitext(&amp;#039;Product&amp;#039;):done()&lt;br /&gt;
			:tag(&amp;#039;th&amp;#039;):wikitext(&amp;#039;Members&amp;#039;):done()&lt;br /&gt;
			:tag(&amp;#039;th&amp;#039;):wikitext(&amp;#039;Tool&amp;#039;):done()&lt;br /&gt;
			:tag(&amp;#039;th&amp;#039;):attr(&amp;#039;data-sort-type&amp;#039;, &amp;#039;number&amp;#039;):wikitext(&amp;#039;Skills&amp;#039;):done()&lt;br /&gt;
			:tag(&amp;#039;th&amp;#039;):attr(&amp;#039;data-sort-type&amp;#039;, &amp;#039;number&amp;#039;):wikitext(&amp;#039;XP&amp;#039;):done()&lt;br /&gt;
			:tag(&amp;#039;th&amp;#039;):wikitext(&amp;#039;Materials&amp;#039;):done()&lt;br /&gt;
	return header&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- If both variables contain the same element as part of a list (or single string)&lt;br /&gt;
function bothContain(argOne, argTwo)&lt;br /&gt;
	if(argOne == nil) or (argOne == &amp;#039;&amp;#039;) or (argTwo == nil) or (argTwo == &amp;#039;&amp;#039;) then&lt;br /&gt;
		return false&lt;br /&gt;
	elseif((type(argOne) == &amp;#039;string&amp;#039;) and (string.find(argOne, &amp;#039;,&amp;#039;) == nil)) and ((type(argTwo) == &amp;#039;string&amp;#039;) and (string.find(argTwo, &amp;#039;,&amp;#039;) == nil)) then&lt;br /&gt;
		return trim(argOne) == trim(argTwo)&lt;br /&gt;
	else&lt;br /&gt;
		if(type(argOne) == &amp;#039;string&amp;#039;) then&lt;br /&gt;
			argOne = split(argOne, &amp;quot;%s*,%s*&amp;quot;)&lt;br /&gt;
		end&lt;br /&gt;
		if(type(argTwo) == &amp;#039;string&amp;#039;) then&lt;br /&gt;
			argTwo = split(argTwo, &amp;quot;%s*,%s*&amp;quot;)&lt;br /&gt;
		end&lt;br /&gt;
		for i, v in ipairs(argOne) do&lt;br /&gt;
			for j, w in ipairs(argTwo) do&lt;br /&gt;
				if(trim(w) == trim(v)) then&lt;br /&gt;
					return true&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		return false&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.loadData(tools, limit, offset)&lt;br /&gt;
	local query = {&lt;br /&gt;
		&amp;#039;[[Uses tool::&amp;#039;.. table.concat(tools, &amp;#039;||&amp;#039;) ..&amp;#039;]]&amp;#039;,&lt;br /&gt;
		&amp;#039;[[Production JSON::+]]&amp;#039;,&lt;br /&gt;
		&amp;#039;?=#-&amp;#039;,&lt;br /&gt;
		&amp;#039;?Production JSON = json&amp;#039;,&lt;br /&gt;
		limit = limit or 500,&lt;br /&gt;
		offset = offset or 0,&lt;br /&gt;
	}&lt;br /&gt;
	local t1 = os.clock()&lt;br /&gt;
	local smwData = mw.smw.ask(query)&lt;br /&gt;
	local t2 = os.clock()&lt;br /&gt;
&lt;br /&gt;
	if(smwData == nil) then&lt;br /&gt;
		return nil&lt;br /&gt;
	end&lt;br /&gt;
	mw.log(string.format(&amp;#039;SMW: entries %d, time elapsed: %.3f ms.&amp;#039;, #smwData, (t2 - t1) * 1000))&lt;br /&gt;
&lt;br /&gt;
	data = {}&lt;br /&gt;
	for i, v in ipairs(smwData) do&lt;br /&gt;
		if type(v[&amp;#039;json&amp;#039;]) == &amp;#039;string&amp;#039; then&lt;br /&gt;
			table.insert(data, jsonDecode(v[&amp;#039;json&amp;#039;]))&lt;br /&gt;
		elseif type(v[&amp;#039;json&amp;#039;]) == &amp;#039;table&amp;#039; then&lt;br /&gt;
			for _, w in ipairs(v[&amp;#039;json&amp;#039;]) do&lt;br /&gt;
				table.insert(data, jsonDecode(w))&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- Remove recipes that do not use at least one of the input tools&lt;br /&gt;
	-- Iterate in reverse so pops do not interrupt iteration&lt;br /&gt;
	for i = #data, 1, -1 do&lt;br /&gt;
		if(not bothContain(tools, data[i].tools)) then&lt;br /&gt;
			table.remove(data, i)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	-- Sort table values by order of tool input&lt;br /&gt;
	if((#tools == 1)) then -- or (#data == 1)&lt;br /&gt;
		return data&lt;br /&gt;
	else&lt;br /&gt;
		local ret = {}&lt;br /&gt;
		-- This tracks the current position of where inserts should occur&lt;br /&gt;
		local toolCountOffset = {}&lt;br /&gt;
		for i = 1, #tools, 1 do&lt;br /&gt;
			table.insert(toolCountOffset, 0)&lt;br /&gt;
		end&lt;br /&gt;
		for i, recipe in ipairs(data) do&lt;br /&gt;
			local pos = 0&lt;br /&gt;
			for j, tool in ipairs(tools) do&lt;br /&gt;
				pos = pos + toolCountOffset[j]&lt;br /&gt;
				if(bothContain(recipe.tools, tool)) then&lt;br /&gt;
					table.insert(ret, pos + 1, recipe)&lt;br /&gt;
					toolCountOffset[j] = toolCountOffset[j] + 1&lt;br /&gt;
					break&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		return ret&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p._main(args)&lt;br /&gt;
	local tool = args ~= nil and args[1] or mw.title.getCurrentTitle().text&lt;br /&gt;
&lt;br /&gt;
	local tools = {}&lt;br /&gt;
	if(string.find(tool, &amp;#039;,&amp;#039;) == nil) then&lt;br /&gt;
		table.insert(tools, trim(tool))&lt;br /&gt;
	else&lt;br /&gt;
		for _, toolV in ipairs(split(tool, &amp;quot;,&amp;quot;)) do&lt;br /&gt;
			table.insert(tools, trim(toolV))&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	data = p.loadData(tools, args.limit, args.offset)&lt;br /&gt;
	&lt;br /&gt;
	if(data == nil) then&lt;br /&gt;
		return &amp;#039;Failed to find products using that tool - ensure it is spelled correctly. (ERR: no results from SMW)[[Category:Empty drop lists]]&amp;#039;&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	local ret = createHeader()&lt;br /&gt;
	for _, recipe in ipairs(data) do&lt;br /&gt;
		ret:node(buildRow(recipe, tools))&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	return tostring(ret)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[ DEBUG&lt;br /&gt;
= p._main({&amp;#039;Hammer&amp;#039;})&lt;br /&gt;
= p._main({&amp;#039;Hammer, Pickaxe&amp;#039;})&lt;br /&gt;
--]]&lt;br /&gt;
&lt;br /&gt;
function p.main(frame)&lt;br /&gt;
	--mw.logObject(frame)&lt;br /&gt;
	local args = frame:getParent().args&lt;br /&gt;
	return p._main(args)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
return p&lt;/div&gt;</summary>
		<author><name>Alex</name></author>
	</entry>
</feed>