Module:Infobox recipe: Difference between revisions

From WIDEVERSE Wiki
Jump to navigation Jump to search
(mw.smw)
(No difference)

Revision as of 21:34, 1 November 2021

Documentation for this module may be created at Module:Infobox recipe/doc

--<nowiki>

--[=[<pre>
-- Implements [[Template:Databox recipe]]
--]=]

local p = {}

local yesno = require('Module:Yesno')
local params = require('Module:Paramtest')
local commas = require('Module:Addcommas')
local geprice = require('Module:Exchange')._price
local skillpic = require('Module:Skill_clickpic')._main
local mapicons = require('Module:Map_clickpic')
local editbutton = require('Module:Edit button')
local onmain = require('Module:Mainonly').on_main
local formatCalcvalue = require('Module:Calcvalue formatter').main
local compcost
local dungprice

-- Name mapping for special (multiple choice) items
local specmats = {
	['Sandstone'] = { ['Sandstone (1kg)'] = 10, ['Sandstone (2kg)'] = 5, ['Sandstone (5kg)'] = 2, ['Sandstone (10kg)'] = 1 },
	['Divine energy'] = { ['Pale energy'] = 2000, ['Flickering energy'] = 1000, ['Bright energy'] = 900, ['Glowing energy'] = 850, ['Sparkling energy'] = 800,
		['Gleaming energy'] = 700, ['Vibrant energy'] = 650, ['Lustrous energy'] = 600, ['Elder energy'] = 500, ['Brilliant energy'] = 450, ['Radiant energy'] = 400,
		['Luminous energy'] = 350, ['Incandescent energy'] = 225 },
}

--[[
Function to get the lowest price for multiple choice items
--]]
local function specprice(item)
	local low = 9999999999
	local ver = ''
	for i,v in pairs( specmats[item] ) do
		local price = geprice(i) * v
		if price <= low then
			low = price
			ver = i
		end
	end
	local txt = 'Based on the cost of '..specmats[item][ver]..' [['..ver..']] as the cheapest option.'
	return {low, txt}
end

--[[
Function to get the calcval value of an item
--]]
local function getCalcval(item)
	local calcval
	if string.find(item, ' %(%d%)$') then
		local subobj = string.gsub(item, ' %((%d)%)$', '#(%1)')
		local subsmw = mw.smw.ask({
			'[['..subobj..']]',
			'?Calculated value#-'
		})
		if subsmw and subsmw[1] then
			calcval = subsmw[1]['Calculated value']
		end
	end
	if not calcval then
		local res = mw.smw.ask({
			'[['..item..']]',
			'?Calculated value#-'
		})
		if res and res[1] then
			calcval = res[1]['Calculated value']
		end
	end
	if not calcval then
		error('No calculated value could be found for: '..item)
	end
	
	if tonumber(calcval) then
		return { tonumber(calcval), 'Calculated value given as a number on the [['..item..'|item page]].' }
	end
	
	local price = mw.getCurrentFrame():preprocess(calcval)
	if tonumber(price) then
		price = math.floor(price * 100 + 0.5) / 100
	else
		error('Error preprocessing calculated value: '..calcval)
	end
	
	local class = string.gsub(item, '%W', '')
	local note = 'Calculated value given on the [['..item..'|item page]] (generally based on GE prices of ingredients):  <span class="cv-formula-tog mw-customtoggle-'..class..'">[show/hide formula]</span>  <span class="mw-collapsible mw-collapsed" id="mw-customcollapsible-'..class..'"> <code>'..formatCalcvalue(calcval)..'</code></span>.'
	
	return { price, note }
end

function p.main(frame)
	local invoke_args = frame.args
	local args = frame:getParent().args
	--[[
	Function to handle all the materials listed
	Creates a table to pass to _main() consisting of
	* Item name, as a wikilink
	* Item image, as a wikilink, includes link to page
	* Quantity
	* Formatted price for display
	* Clean price for calculations
	* Note on the price source/calculation method
	If the parameter mat# is defined and not blank
	Every parameter (mat#img, mat#qty, mat#price, mat#pnote) will be looked for as well
	--]]
	local function mat_list()
		local ret_list = {}
		for i=1,10,1 do
			local mat = args['mat'..i]
			if mat and params.has_content(mat) then
				local name = params.default_to(args['mat'..i..'name'],mat)
				-- 2 separate prices
				-- 1 for display
				-- 1 for calculation
				local price,price_raw,price_note
				local qty = params.default_to(args['mat'..i..'qty'],'1')
				local img = params.default_to(args['mat'..i..'img'],
					mat..'.png')
					:gsub('File:','')
				local price_v = params.default_to(args['mat'..i..'price'],'/')
				local price_note = args['mat'..i..'pnote']
				local price_txt = price_v:lower()
				local old_price = false
				-- gemw = use exchange price
				if price_txt == 'gemw' then
					if specmats[mat] then
						local temp_cost = specprice(mat)
						price_raw = temp_cost[1]
						price = commas._add(price_raw)
						price_note = temp_cost[2]
					elseif string.lower(mat) == 'coins' then
						price_raw = 1
						price = commas._add(price_raw)
						local c_imgs = {10000, 1000, 250, 100, 25, 5, 4, 3, 2, 1}
						local num = tonumber(qty) or 1000
						for i = 1, #c_imgs do
							j = c_imgs[i]
							img = 'Coins '..j..'.png'
							if num >= j then
								break
							end
						end
					else
						price_raw = geprice(mat)
						price = commas._add(price_raw)
					end
				-- use (invention) material costs
				elseif price_txt == 'mat' or price_txt == 'comp' then
					if not compcost then
						compcost = require('Module:Component costs')._main
					end
					local temp_cost = compcost(mat)
					if temp_cost then
						price_raw = math.floor( temp_cost.price + 0.5 )
						price = commas._add(price_raw)
						price_note = temp_cost.note
					end
				-- use calcvalue from databox
				elseif price_txt == 'calcvalue' then
					local temp_cost = getCalcval(mat)
					price_raw = temp_cost[1]
					price = commas._add(price_raw)
					price_note = temp_cost[2]
				-- use valu from smuggler
				elseif price_txt == 'dung' or price_txt == 'dungeoneering' then
					if not dungprice then
						dungprice = require('Module:Smuggler price')._price
					end
					price_raw = tonumber( dungprice(mat) )
					price = commas._add(price_raw)
				-- parseable as number = use that
				elseif tonumber(commas._strip(price_v),10) then
					price_raw = tonumber(commas._strip(price_v),10)
					price = commas._add(price_raw)
					price_note = 'Fixed price given'
					old_price = true
				-- Some untradeables have a distinct market price
				-- because of their materials
				-- The template {{GETotal}} will help here
				-- Look for template call
				elseif price_v:find('{{.*}}') then
					price_raw = frame:preprocess(price_v)
					price = commas._add(price_raw)
					price_note = 'Price calculated from: <code><nowiki>'..price_v..'</nowiki></code>'
					old_price = true
				-- everything else
				-- use N/A for display and 0 for calculations
				else
					price_raw = 0
					price = 'N/A'
				end

				table.insert(ret_list, {
					name = '[['..mat..'|'..name..']]',
					name_raw = mat,
					price = price,
					price_raw = price_raw,
					price_note = price_note,
					quantity = qty,
					image = '[[File:'..img..'|link='..mat..']]',
					image_raw = img,
					old_price = old_price
				} )
			end
		end
		return ret_list
	end
	--[[
	Function to get a list of additional requirements, should there be any
	Will take non-blank parameters and simply paste them as is into a table
	Which will then be passed into the _main() function
	--]]
	local function get_other_reqs()
		local req_list = {}
		for i=1,5,1 do
			local req = args['misc'..i]
			if req and req:find('%S') then
				table.insert(req_list,req)
			end
		end
		return req_list
	end
	-- Fetching and formatting parameters starting here
	local item_name,item_image,
		ticks,ticks2,ticksnote,
		skill,level,experience,
		method,improved,instructions,totalvar = params.defaults{
				{args.name,mw.title.getCurrentTitle().text},
				{args.image,nil},
				{args.ticks,editbutton('?')},
				{args.ticks2,nil},
				{args.ticksnote,nil},
				{args.skill,nil},
				{args.level,editbutton('?')},
				{args.skillXP,nil},
				{args.method,nil},
				{args.improved,0},
				{args.instructions,nil},
				{args.totalvar,nil}
			}
	local item_link = mw.title.getCurrentTitle().text

	local skill2,level2,experience2,
		skill3,level3,experience3,
		facility,quest = params.defaults{
				{args.secSkill,nil},
				{args.secLevel,nil},
				{args.secXP,nil},
				{args.terSkill,nil},
				{args.terLevel,nil},
				{args.terXP,nil},
				{args.facility,nil},
				{args.quest,nil}
			}
	
	-- Add [[File: and |link=...]] to image, if it's defined
	if item_image then
		item_image = '[[File:'..item_image:gsub('File:','')..'|link='..item_link..']]'
	-- anti-redlink
	elseif mw.title.getCurrentTitle().text == 'Databox recipe/preload'
			or mw.title.getCurrentTitle().text == 'PreloadPage/Orphanage' then
		item_image = ''
	else
		item_image = '[[File:'..item_name..'.png|link='..item_name..']]'
	end
	-- Allow amount to be removed if it's 1
	local item_amount = tonumber(args.amount,10) or 1
	
	-- Check that improved is a number
	if tonumber(improved,10) then
		improved = tonumber(improved,10)
	else
		improved = 0
	end

	-- Tables to pass; call above functions
	local materials = mat_list()
	local misc_reqs = get_other_reqs()

	-- Look for gemw in the parameter, otherwise nil
	local item_ge_v = string.lower(args.geValue or '')
	local item_gep
	if item_ge_v == 'gemw' then
		item_gep = geprice(item_name)
	elseif item_ge_v == 'no' then
		item_gep = 'no'
	else
		item_gep = nil
	end

	-- Only accept "yes" or "no"
	-- Anything else defaults to no
	-- Should this default to unknown instead?
	local members = yesno(args.members) and '[[File:P2P icon.png|21px|link=]] Members only' or '[[File:F2P icon.png|21px|link=]] Free-to-play'

	local mainfunc = '_main'
	if invoke_args.onlysmw == 'yes' then
		mainfunc = '_smw'
	end
	-- Pass parameters to _main
	return p[mainfunc]( frame,
		item_name,
		item_link,
		item_image,
		item_amount,
		ticks,
		ticks2,
		ticksnote,
		improved,
		method,
		materials,
		facility,
		misc_reqs,
		skill,
		level,
		experience,
		skill2,
		level2,
		experience2,
		skill3,
		level3,
		experience3,
		item_gep,
		members,
		quest,
		yesno(args.nosmw) or false,
		instructions,
		totalvar
	)
end

--
-- Main
--
function p._main(frame,
		item_name,item_link,
		item_image,item_amount,
		ticks,ticks2,ticksnote,
		improved,method,
		materials,facility,misc_reqs,
		skill,level,experience,
		skill2,level2,experience2,
		skill3,level3,experience3,item_gep,
		members,quest,nosmw,instructions,totalvar)
	
	local hasreftag = false

	local ret = mw.html.create('table')
			:addClass('wikitable infobox-recipe')
			:css({ width = '50%',
				['max-width'] = '450px' })
	-- Caption header
	local caption = item_image..' '..item_name
	if item_amount > 1 then
		caption = caption..' ×'..item_amount
	end
	if improved > 0 then
		caption = caption..string.format(' <i><span title="Improved recipe %s">(+%s)</span></i>', improved, improved)
	elseif method then
		caption = caption..string.format('<br /><i>(%s)</i>', method)
	end
	ret:tag('caption'):wikitext(caption):done()

	---- Creation of row 1
	-- Columns 1 and 5
	local row1 = ret:tag('tr')
			:css('text-align','center')

	local row1a = row1:tag('th')
		:css('width','20%')

	if skill then
		if skill:lower() == 'no' then
			row1a:wikitext('-')
		else
			row1a:wikitext(skillpic(skill))
		end
	else
		row1a:wikitext('\'\'? skill\'\' '..editbutton())
	end

	local row1e = row1:tag('th')
		:css('width','20%')

	if skill2 and not (skill2:lower() == 'no') then
		row1e:wikitext(skillpic(skill2))
	else
		row1e:wikitext('-')
	end
	-- skill3 experience cell if there is room with tick cell. Default is 2-wide tick cell.
	if skill3 and not (skill3:lower() == 'no') and not ticks2 then
		row1:tag('th'):wikitext(skillpic(skill3)):done()
		row1:tag('th')
			:attr('title','Ticks per action')
			:css('width','40%')
			:wikitext('[[File:Hourglass.png|link=Game tick]]')
		:done()
	else
		row1:tag('th')
			:attr('title','Ticks per action')
			:css('width','40%')
			:attr('colspan','2')
			:wikitext('[[File:Hourglass.png|link=Game tick]]')
		:done()
	end
	
	row1:tag('th')
			:attr('title','Grand Exchange median price')
			:css('width','20%')
			:wikitext('[[File:Make-X GE icon.png|link=]]')
		:done()

	---- Creation of row 2
	local row2 = ret:tag('tr')
		:css('text-align','center')
	local row2a = row2:tag('td')
	local row2b = row2:tag('td')
	-- skill3 experience if included
	if skill3 and not (skill3:lower() == 'no') and not ticks2 then
		if experience3 then
			row2:tag('td'):wikitext(commas._add(experience3)..'&nbsp;XP'):done()	
		else
			row2:tag('td'):wikitext('-'):done()
		end
	end
	local row2c = row2:tag('td')
			:attr('colspan','2')
	-- flex tick cell if exp3 included
	if skill3 and not (skill3:lower() == 'no') and not ticks2 then
		row2c:attr('colspan','1')
	end
	local row2d = row2:tag('td')

	if skill and skill:lower() == 'no' then
		row2a:wikitext('-')
	elseif experience then
		row2a:wikitext(commas._add(experience)..' XP')
	else
		row2a:wikitext('\'\'? XP\'\' '..editbutton())
	end
	if experience2 then
		row2b:wikitext(commas._add(experience2)..' XP')
	else
		row2b:wikitext('-')
	end
	
	if tonumber(ticks,10) then
		local secs = tonumber(ticks,10) * 0.6
		local note = ''
		if ticksnote and string.find(ticksnote, '%S') then
			if ticksnote == '1' then
				ticksnote = 'When creating a single item'
			end
			note = frame:extensionTag{ name='ref', content = ticksnote, args = {group="r"} }
			hasreftag = true
		end
		if tonumber(ticks2,10) then
			local secs2 = tonumber(ticks2,10) * 0.6
			row2c:tag('span')
				:attr('title',ticks..' ticks ('..secs..' seconds) per action')
				:wikitext(ticks..' ('..secs..'s) ')
			:done()
			:wikitext(' / ')
			:tag('span')
				:attr('title',ticks2..' ticks ('..secs2..' seconds) per action, ')
				:wikitext('<i> '..ticks2..' ('..secs2..'s)</i> ')
			:done()
			:wikitext(note)
		else
			row2c:attr('title',ticks..' ticks ('..secs..' seconds) per action')
				:wikitext(ticks..' ('..secs..'s) '..note)
		end
	elseif string.lower(ticks) == 'varies' then
		local note = ''
		if ticksnote and string.find(ticksnote, '%S') then
			note = frame:extensionTag{ name='ref', content = ticksnote, args = {group="r"} }
			hasreftag = true
		end
		row2c:attr('title', 'Varies')
			:wikitext('Varies ' .. note)
	else
		row2c:wikitext(ticks)
	end
	
	if item_gep then
		if item_gep == 'no' then
			row2d:attr('title','Cannot be sold on the Grand Exchange')
				:wikitext('-')
		elseif item_amount > 1 then
			row2d:attr('title',commas._add(item_gep)..' coins each')
				:wikitext(commas._add(item_gep * item_amount))
		else
			row2d:wikitext(commas._add(item_gep))
		end
	else
		row2d:wikitext('\'\'?\'\' '..editbutton())
	end

	-- Add "Requirements" header
	ret:tag('tr')
			:tag('th')
				:attr('colspan','5')
				:wikitext('Requirements')
			:done()
		:done()
	-- Skill requirement 1
	if skill and not (skill:lower() == 'no') then
		ret:tag('tr')
			:tag('td')
				:attr('colspan','4')
				:wikitext(skillpic(skill)..' '..
					params.ucflc(skill)..' level')
			:done()
			:tag('td')
				:css('text-align','center')
				:wikitext(level)
			:done()
		:done()
	end
	-- Skill requirement 2
	if skill2 and level2 then
		ret:tag('tr')
			:tag('td')
				:attr('colspan','4')
				:wikitext(skillpic(skill2)..' '..
					params.ucflc(skill2)..' level')
			:done()
			:tag('td')
				:css('text-align','center')
				:wikitext(level2)
			:done()
		:done()
	end
	-- Skill requirement 3
	if skill3 and level3 then
		ret:tag('tr')
			:tag('td')
				:attr('colspan','4')
				:wikitext(skillpic(skill3)..' '..
					params.ucflc(skill3)..' level')
			:done()
			:tag('td')
				:css('text-align','center')
				:wikitext(level3)
			:done()
		:done()
	end

	-- Quest requirement
	if quest then
		ret:tag('tr')
			:tag('td')
				:attr('colspan','5')
				:wikitext(skillpic('quest')..' '..quest)
			:done()
		:done()
	end
	
	-- Facility requirement
	function facility_link(facility_arg)
		if type(facility_arg) == 'string' and mapicons.filelink(facility_arg:lower())[1] then
			local link = mapicons.filelink(facility_arg:lower())[2]
			local txt = mapicons.filelink(facility_arg:lower())[3]
			local art = mapicons.filelink(facility_arg:lower())[4]
			local vowels = {a=true, e=true, i=true, o=true, u=true}
			local article
			if art then
				article = art
			elseif vowels[string.sub(link:lower(), 1, 1)] then
				article = 'an'
			else
				article = 'a'
			end
			return article.." [["..link.."|"..(txt or link:lower()).."]]"
		else
			return facility_arg
		end
	end
	
	if facility then
		ret:tag('tr')
			:tag('td')
				:attr('colspan','5')
				:wikitext(mapicons._main(facility)..' Must be performed at '..facility_link(facility))
			:done()
		:done()
	end

	-- Miscellaneous requirements
	for i, v in ipairs(misc_reqs) do
		ret:tag('tr')
			:tag('td')
				:attr('colspan','5')
				:wikitext(v)
			:done()
		:done()
	end

	-- Members requirement
	ret:tag('tr')
			:tag('td')
				:attr('colspan','5')
				:wikitext(members)
			:done()
		:done()

	-- Materials header
	ret:tag('tr')
		:tag('th')
			:attr('colspan','5')
			:wikitext('Materials')
		:done()
	:done()
	:tag('tr')
		:tag('th')
			:attr('colspan','2')
			:wikitext('Item')
		:done()
		:tag('th')
			:wikitext('Quantity')
		:done()
		:tag('th')
			:wikitext('Price')
		:done()
		:tag('th')
			:wikitext('Total')
		:done()
	:done()

	-- Materials
	local total_price = 0
	local valued_items = 0
	local old_price = false
	-- Iterates through the tables in the table of materials
	for i, v in ipairs(materials) do
		-- Fetch all the variables
		local mat_name = v.name
		local mat_price = v.price
		local mat_raw = v.price_raw
		local mat_ttl
		local mat_note = ''
		local mat_qty = v.quantity
		local mat_img = v.image
		-- maintenance cat for old/manual prices
		if v.old_price then
			old_price = true
		end
		-- If no price is given for item, delete total
		-- Otherwise quantity * price each
		if mat_raw == 0 then
			mat_ttl = '-'
		else
			mat_ttl = mat_qty * mat_raw
		end
		-- If item total is a number
		-- Add it to the overall total
		-- Indicate this by incrementing valued item count
		-- Done with total calculations, add commas to total for formatting
		if type(mat_ttl) == 'number' then
			total_price = total_price + mat_ttl
			mat_ttl = commas._add(mat_ttl)
			if mat_raw > 0 then
				valued_items = valued_items + 1
			end
		end
		-- If a price note is given use it
		if v.price_note then
			mat_note = frame:extensionTag{ name='ref', content = v.price_note, args = {group="r"} }
			hasreftag = true
		end
		ret:tag('tr')
			:tag('td')
				:css({ ['border-right'] = 'none',
					['text-align'] = 'center' })
				:wikitext(mat_img)
			:done()
			:tag('td')
				:css({ ['border-left'] = 'none',
					['border-right'] = 'none',
					['text-align'] = 'left' })
				:wikitext(mat_name)
			:done()
			:tag('td')
				:css({ ['border-left'] = 'none',
					['border-right'] = 'none',
					['text-align'] = 'right' })
				:wikitext(commas._add(mat_qty))
			:done()
			:tag('td')
				:css({ ['border-left'] = 'none',
					['text-align'] = 'right' })
				:wikitext(mat_price)
			:done()
			:tag('td')
				:addClass('ref-left')
				:css('text-align','right')
				:wikitext(mat_note..mat_ttl)
			:done()
		:done()
	end

	-- If no materials found
	-- Indicate nothing listed, add an edit button for the page
	if #materials == 0 then
		ret:tag('tr')
				:tag('td')
					:attr('colspan','5')
					:css({ ['font-style'] = 'italic',
						['text-align'] = 'center' })
					:wikitext('Materials unlisted '..editbutton())
				:done()
			:done()
	end

	-- Total
	-- Hide if less than 2 items have a value
	if valued_items > 1 then
		ret:tag('tr')
			:tag('th')
				:attr('colspan','4')
				:css('text-align','right')
				:wikitext('Total price')
			:done()
			:tag('td')
				:css('text-align','right')
				:wikitext(commas._add(total_price))
			:done()
		:done()
	end
	if type(totalvar) == 'string' and #totalvar > 0 then
		mw.ext.VariablesLua.vardefine(totalvar, total_price)
	end
	
	-- Profit
	if valued_items >= 1 then
		if item_gep and item_gep ~= 'no' then
			local profit = item_gep * item_amount - total_price
			local profclass = 'text-green'
			if profit < 0 then
				profclass = 'text-red'
			end
			ret:tag('tr')
				:tag('th')
					:attr('colspan','4')
					:css('text-align','right')
					:wikitext('Profit')
				:done()
				:tag('td')
					:css('text-align','right')
					:addClass(profclass)
					:wikitext(commas._add(profit))
				:done()
			:done()
		end
	end
	
	if instructions then
		ret:tag('tr')
			:tag('th')
				:attr('colspan','6')
				:css('text-align','center')
				:wikitext('Instructions')
			:done()
		:done()
		:tag('tr')
			:tag('td')
				:attr('colspan','6')
				:wikitext(instructions)
	end
	
	if not nosmw then
		addSMW(ret, item_name,item_link,
		item_image,item_amount,
		ticks,ticks2,ticksnote,
		improved,method,
		materials,facility,misc_reqs,
		skill,level,experience,
		skill2,level2,experience2,
		skill3,level3,experience3,item_gep,
		members,quest,nosmw,instructions,totalvar, old_price)
	end
	addCategories(ret, item_name,item_link,
		item_image,item_amount,
		ticks,ticks2,ticksnote,
		improved,method,
		materials,facility,misc_reqs,
		skill,level,experience,
		skill2,level2,experience2,
		skill3,level3,experience3,item_gep,
		members,quest,nosmw,instructions,totalvar, old_price)
	
		if type(ret) ~= 'string' then ret = tostring(ret) end
	if hasreftag then
		ret = ret .. '\n' .. frame:extensionTag{ name='references', args = {group="r"} }
	end
	
	return ret
end

function p._smw(frame,
		item_name,item_link,
		item_image,item_amount,
		ticks,ticks2,ticksnote,
		improved,method,
		materials,facility,misc_reqs,
		skill,level,experience,
		skill2,level2,experience2,
		skill3,level3,experience3,item_gep,
		members,quest,nosmw,instructions,totalvar)
	local ret = mw.html.create('')
	local old_price = false
	for i,v in ipairs(materials) do
		if v.old_price then
			old_price = true
			break
		end
	end
	
	if not nosmw then
		addSMW(ret, item_name,item_link,
		item_image,item_amount,
		ticks,ticks2,ticksnote,
		improved,method,
		materials,facility,misc_reqs,
		skill,level,experience,
		skill2,level2,experience2,
		skill3,level3,experience3,item_gep,
		members,quest,nosmw,instructions,totalvar, old_price)
	end
	addCategories(ret, item_name,item_link,
		item_image,item_amount,
		ticks,ticks2,ticksnote,
		improved,method,
		materials,facility,misc_reqs,
		skill,level,experience,
		skill2,level2,experience2,
		skill3,level3,experience3,item_gep,
		members,quest,nosmw,instructions,totalvar, old_price)
	return ret
end

function addSMW(ret, item_name,item_link,
		item_image,item_amount,
		ticks,ticks2,ticksnote,
		improved,method,
		materials,facility,misc_reqs,
		skill,level,experience,
		skill2,level2,experience2,
		skill3,level3,experience3,item_gep,
		members,quest,nosmw,instructions,totalvar, old_price)
	if onmain() then
		if not nosmw then
			local smw = {}
			table.insert(smw,'Required materials:')
			local jsonmats = {}
			local mats = {}
			for _, v in ipairs(materials) do
				table.insert(jsonmats,{ name = v.name_raw, quantity = v.quantity, image = v.image_raw })
				table.insert(mats, v.name_raw)
			end
			if #mats > 0 then
				smw['Made from item'] = mats
			end
			
			if tonumber(ticks,10) then
				smw['Production ticks'] = ticks
			end
			if tonumber(ticks2,10) then
				smw['Production ticks secondary'] = ticks2
			end
			if ticksnote and string.find(ticksnote, '%S') then
				smw['Production ticks note'] = ticksnote
			end
	
			local tojson = {
				product = item_name,
				link = item_link,
				image = item_image,
				ticks = ticks,
				improved = improved,
				method = method or '',
				facility = facility or '',
				mats = jsonmats,
				skill = skill or '?',
				level = tonumber(level) or '?',
				exp = tonumber(experience) or '?',
				skill2 = skill2 or '?',
				level2 = tonumber(level2) or '?',
				exp2 = tonumber(experience2) or '?',
				skill3 = skill3 or '?',
				level3 = tonumber(level3) or '?',
				exp3 = tonumber(experience3) or '?',
				quantity = item_amount
			}
			local json = mw.text.nowiki(mw.text.jsonEncode(tojson))
			smw['Production JSON'] = json
			local smw_res = mw.smw.set(smw)
			if not smw_res == true then
				mw.log(result.error)
			end
		end
	end
end

function addCategories(ret, item_name,item_link,
		item_image,item_amount,
		ticks,ticks2,ticksnote,
		improved,method,
		materials,facility,misc_reqs,
		skill,level,experience,
		skill2,level2,experience2,
		skill3,level3,experience3,item_gep,
		members,quest,nosmw,instructions,totalvar, old_price)
	
	if onmain() then	
		-- Add categories
		cats = {}
		if not skill then
			table.insert(cats,'Recipes missing skill')
		end
		if skill and not (skill:lower() == 'no') then
			if not experience then
				table.insert(cats,'Recipes missing xp')
			end
			if not tonumber(level,10) then
				table.insert(cats,'Recipes missing skill level')
			end
		end
		if not tonumber(ticks,10) and string.lower(ticks) ~= 'varies' then
			table.insert(cats,'Recipes missing ticks')
		end
		if not item_gep then
			table.insert(cats,'Recipes missing item values')
		end
		-- Old/manual prices
		if old_price then
			table.insert(cats,'Recipes using manual values')
		end
		
		for i, v in ipairs(cats) do
			if (v ~= '') then
				cats[i] = string.format('[[Category:%s]]',v)
			end
		end
		
		ret = tostring(ret) .. table.concat(cats)
	end
end

return p