Module:Infobox recipe
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)..' 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