Module:Sandbox/User:Towelcat/Recipe
Jump to navigation
Jump to search
Module documentation
This documentation is transcluded from Template:Module sandbox/doc. [edit] [history] [purge]
Module:Sandbox/User:Towelcat/Recipe requires .
This module is a sandbox for Towelcat. It can be used to test changes to existing modules, prototype new modules, or just experiment with Lua features.
Invocations of this sandbox should be kept in userspace; if the module is intended for use in other namespaces, it should be moved out of the sandbox into a normal module and template.
This default documentation can be overridden by creating the /doc subpage of this module, as normal.
--<nowiki>
local p = {}
-- convert some used globals to locals to improve performance
local math = math
local string = string
local table = table
local mw = mw
local expr = mw.ext.ParserFunctions.expr
local clean_image = require('Module:Clean image').clean
local coins = require('Module:Coins')._amount
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:SCP')._main
local editbutton = require('Module:Edit button')
local onmain = require('Module:Mainonly').on_main
-- Tools that need special handling
local toolsList = {
['Axe'] = '[[File:Bronze axe.png|link=Axe]]',
}
local facilitiesIcons = {
['Anvil'] = '[[File:Anvil icon.png|link=Anvil]]',
['Apothecary'] = '[[File:Apothecary icon.png|link=Apothecary]]',
['Banner easel'] = '[[File:Banner easel icon.png|link=Banner easel]]',
['Barbarian anvil'] = '[[File:Anvil icon.png|link=Anvil]]',
['Blast furnace'] = '[[File:Furnace icon.png|link=Blast furnace]]',
['Brewery'] = '[[File:Brewery icon.png|link=Brewery]]',
['Clay oven'] = '[[File:Cooking range icon.png|link=Clay oven]]',
['Cooking range'] = '[[File:Cooking range icon.png|link=Cooking range]]',
['Crafting table 1'] = '[[File:Crafting table 1 icon.png|link=Crafting table 1]]',
['Crafting table 2'] = '[[File:Crafting table 2 icon.png|link=Crafting table 2]]',
['Crafting table 3'] = '[[File:Crafting table 3 icon.png|link=Crafting table 3]]',
['Crafting table 4'] = '[[File:Crafting table 4 icon.png|link=Crafting table 4]]',
['Dairy churn'] = '[[File:Dairy churn icon.png|link=Dairy churn]]',
['Demon lectern'] = '[[File:Demon lectern icon.png|link=Demon lectern]]',
['Eagle lectern'] = '[[File:Eagle lectern icon.png|link=Eagle lectern]]',
['Fancy Clothes Store'] = '[[File:Clothes shop icon.png|link=Fancy Clothes Store]]',
['Farming patch'] = '[[File:Farming patch icon.png|link=Farming/Patch_locations]]',
['Furnace'] = '[[File:Furnace icon.png|link=Furnace]]',
['Loom'] = '[[File:Loom icon.png|link=Loom]]',
['Mahogany demon lectern'] = '[[File:Mahogany demon lectern icon.png|link=Mahogany demon lectern]]',
['Mahogany eagle lectern'] = '[[File:Mahogany eagle lectern icon.png|link=Mahogany eagle lectern]]',
['Metal Press'] = '[[File:Furnace icon.png|link=Metal Press]]',
['Oak lectern'] = '[[File:Oak lectern icon.png|link=Oak lectern]]',
['Pluming stand'] = '[[File:Pluming stand icon.png|link=Pluming stand]]',
['Pottery wheel'] = '[[File:Pottery wheel icon.png|link=Pottery wheel]]',
['Sawmill'] = '[[File:Sawmill icon.png|link=Sawmill]]',
['Sandpit'] = '[[File:Sandpit icon.png|link=Sandpit]]',
['Shield easel'] = '[[File:Shield easel icon.png|link=Shield easel]]',
['Singing bowl'] = '[[File:Singing bowl icon.png|link=Singing bowl]]',
['Spinning wheel'] = '[[File:Spinning wheel icon.png|link=Spinning wheel]]',
['Tannery'] = '[[File:Tannery icon.png|link=Tannery]]',
['Taxidermist'] = '[[File:Taxidermist icon.png|link=Taxidermist]]',
['Teak demon lectern'] = '[[File:Teak demon lectern icon.png|link=Teak demon lectern]]',
['Teak eagle lectern'] = '[[File:Teak eagle lectern icon.png|link=Teak eagle lectern]]',
['Thakkrad Sigmundson'] = '[[File:Tannery icon.png|link=Thakkrad Sigmundson]]',
['Water'] = '[[File:Water source icon.png|link=Water]]',
['Whetstone'] = '[[File:Whetstone icon.png|link=Whetstone]]',
['Windmill'] = '[[File:Windmill icon.png|link=Windmill]]',
['Woodcutting stump'] = '[[File:Woodcutting stump icon.png|link=Woodcutting stump]]',
}
function p.main(frame)
local args = frame:getParent().args
local function to_number_expr(param)
if tonumber(commas._strip(param),10) then
return tonumber(commas._strip(param),10)
elseif pcall(function() expr(param) end) then
return tonumber(expr(param))
end
return 'error_not_number'
end
local function cost_to_number(cost_v, name)
if cost_v == nil then
if pcall(function() geprice(name) end) then
return geprice(name)
else
return 'error_GE_lookup'
end
elseif string.lower(cost_v) == 'no' then
return 'N/A'
else
return to_number_expr(cost_v)
end
end
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 = mat
local txt = params.default_to(args['mat'..i..'txt'], nil)
local qty = params.default_to(args['mat'..i..'quantity'], 1)
local img = params.default_to(args['mat'..i..'pic'], name..'.png')
local cost_v = args['mat'..i..'cost']
table.insert(ret_list, {
name = name,
txt = txt,
cost = cost_to_number(cost_v, name),
quantity = to_number_expr(qty),
image = clean_image({file=img, link=mat}),
} )
end
end
return ret_list
end
local function skill_list()
local ret_list = {}
for i=1,10,1 do
local skill = args['skill'..i]
if skill and params.has_content(skill) then
local name = skill
local lvl = params.default_to(args['skill'..i..'lvl'],'1')
local exp = params.default_to(args['skill'..i..'exp'],'0')
table.insert(ret_list, {
name = name,
level = lvl,
experience = exp,
} )
end
end
return ret_list
end
local name = args.outputname or mw.title.getCurrentTitle().text
local txt = args.outputtxt or nil
local image_name = args.outputpic or (name .. '.png')
local output = {
name = name,
txt = txt,
image = clean_image({file=image_name, link=name}),
quantity = to_number_expr(args.outputquantity or 1),
cost = cost_to_number(args.outputcost, name),
outputnote = args.outputitemnote or nil,
quantitynote = args.outputquantitynote or nil
}
local materials = mat_list()
local skills = skill_list()
local members = ''
if params.has_content(args.members) then
members = yesno(args.members, true)
if members then
members = 'Yes'
else
members = 'No'
end
end
local nosmw
if params.has_content(args.nosmw) then
nosmw = true
end
return p._main(frame, args, args.tools, skills, members, args.notes, materials, output, args.facilities, args.ticks, args.ticksnote, nosmw)
end
--
-- Main
--
function p._main(frame, args, tools, skills, members, notes, materials, output, facilities, ticks, ticksnote, nosmw)
local hasreftag = false
local function make_row(item_data)
local classOverride_cost, classOverride_qty
local textAlign = 'right'
local mat_ttl, mat_qty = 0
local output_cost = (tonumber(item_data.quantity) or 1) * (tonumber(item_data.cost) or 0)
if item_data.quantity == 'error_not_number' then
mat_qty = 'Error: invalid quantity parameter'
classOverride_qty = 'table-no'
else
mat_qty = commas._add(item_data.quantity)
end
if item_data.cost == 'error_not_number' then
mat_ttl = 'Error: invalid cost parameter'
classOverride_cost = 'table-no'
elseif item_data.cost == 'error_GE_lookup' then
mat_ttl = 'Error: could not find exchange price for item \'' .. item_data.name .. '\''
classOverride_cost = 'table-no'
elseif item_data.cost == 'N/A' then
mat_ttl = '<small>Untradeable</small>'
classOverride_cost = 'table-na'
textAlign = 'center'
else
mat_ttl = coins(output_cost)
end
local name = item_data.txt and string.format('[[%s|%s]]', item_data.name, item_data.txt) or string.format('[[%s]]', item_data.name)
local itemnote = item_data.outputnote and frame:extensionTag{ name = 'ref', content = item_data.outputnote, args = { group = 'r' } } or ''
local quantitynote = item_data.quantitynote and frame:extensionTag{ name = 'ref', content = item_data.quantitynote, args = { group = 'r' } } or ''
return mw.html.create('tr')
:tag('td'):wikitext(item_data.image):done()
:tag('td'):wikitext(name .. itemnote):done()
:tag('td'):addClass(classOverride_qty):wikitext(mat_qty .. quantitynote):done()
:tag('td'):addClass(classOverride_cost):css({ ['text-align'] = textAlign }):wikitext(mat_ttl):done(),
output_cost,
note ~= nil
end
local function toolImages(t)
local images = {}
if t == nil then
return 'None'
end
local spl = mw.text.split(t, ",")
for _, image_i in ipairs(spl) do
image_i = mw.text.trim(image_i)
if toolsList[image_i] then
table.insert(images, toolsList[trimmed])
else
table.insert(images, string.format("[[File:%s.png|link=%s]]", image_i, image_i))
end
end
return table.concat(images)
end
local function facilityLinks(f)
local links = {}
if f == nil then
return 'None'
end
local spl = mw.text.split(f, ",")
for _, link_i in ipairs(spl) do
if facilitiesIcons[link_i] ~= nil then
table.insert(links, string.format("%s [[%s]]", facilitiesIcons[link_i], link_i))
else
table.insert(links, string.format("[[%s]]", link_i))
end
end
return table.concat(links, "<br />")
end
local parent = mw.html.create('div')
:css({width = 'max-content' })
local requirements = mw.html.create('table')
:addClass('wikitable align-center-2 align-right-3')
:css({ width = '100%',
['margin'] = '0' })
requirements:tag('caption'):wikitext("Requirements"):done()
local tr = requirements:tag('tr')
if #skills ~= 0 then
tr:tag('th'):attr('colspan', 2):wikitext('Skill'):done()
tr:tag('th'):wikitext('Level'):done()
tr:tag('th'):wikitext('XP'):done()
end
local membersTemplate = editbutton('?')
if members == 'Yes' then
membersTemplate = "[[File:Member icon.png|center|link=Members]]"
elseif members == 'No' then
membersTemplate = "[[File:Free-to-play icon.png|center|link=Free-to-play]]"
end
if #skills ~= 0 then
for i, v in ipairs(skills) do
requirements:tag('tr')
:tag('td'):attr('colspan', 2):wikitext(skillpic(v.name) .. ' [[' .. v.name .. ']]'):done()
:tag('td'):wikitext(v.level):done()
:tag('td'):wikitext(v.experience):done()
end
end
if notes ~= nil then
requirements:tag('tr')
:tag('td'):attr('colspan', 4):wikitext(notes):done()
end
local tr = requirements:tag('tr')
tr:tag('th'):wikitext('Members'):done()
tr:tag('td'):wikitext(membersTemplate):done()
tr:tag('th'):attr('title', 'Ticks per action'):wikitext('[[RuneScape clock#Length of a tick|Ticks]]'):done()
if (ticks or '') == '' then
tr:tag('td'):wikitext('?'):done()
elseif string.lower(ticks) == 'na' then
local classOverride = 'table-na'
tr:tag('td'):addClass(classOverride):css({ ['text-align'] = center }):wikitext('N/A'):done()
elseif string.lower(ticks) == 'varies' then
local note = ''
if ticksnote ~= nil then
note = frame:extensionTag{ name='ref', content = ticksnote, args = { group='r' } }
hasreftag = true
end
tr:tag('td'):wikitext('Varies' .. note):done()
else
local secs = tonumber(ticks, 10) * 0.6
local note = ''
if ticksnote ~= nil then
note = frame:extensionTag{ name='ref', content = ticksnote, args = { group='r' } }
hasreftag = true
end
tr:tag('td'):attr('title', ticks .. ' ticks (' .. secs .. 's) per action'):wikitext(ticks .. ' (' .. secs .. 's) ' .. note):done()
end
if tools ~= nil or facilities ~= nil then
local toolImgs = toolImages(tools)
local facilityLnks = facilityLinks(facilities)
requirements:tag('tr')
:tag('th'):wikitext('Tools'):done()
:tag('td'):css({ ['text-align'] = 'center' }):wikitext(toolImgs):done()
:tag('th'):wikitext('Facilities'):done()
:tag('td'):css({ ['text-align'] = 'center' }):wikitext(facilityLnks):done()
end
local materialsTable = mw.html.create('table')
:addClass('wikitable align-center-1 align-right-3 align-right-4')
:css({ width = '100%',
['margin-top'] = '-1px' })
materialsTable:tag('caption'):wikitext("Materials"):done()
materialsTable:tag('tr')
:tag('th'):attr('colspan', 2):wikitext('Item'):done()
:tag('th'):wikitext('Quantity'):done()
:tag('th'):wikitext('Cost'):done()
local total_cost = 0
for i, v in ipairs(materials) do
row, row_cost = make_row(v)
if row_cost ~= 0 then
total_cost = total_cost + (tonumber(v.quantity) or 1) * v.cost
end
materialsTable:node(row)
end
if #materials == 0 then
materialsTable:tag('tr')
:tag('td'):attr('colspan','5'):css({ ['font-style'] = 'italic', ['text-align'] = 'center' }):wikitext('Materials unlisted '..editbutton()):done()
else
materialsTable:tag('tr')
:tag('th'):attr('colspan', 3):css({['text-align'] = 'right'}):wikitext('Total Cost'):done()
:tag('td'):css({['text-align'] = 'right'}):wikitext(coins(total_cost))
end
output_row, output_cost, has_output_note = make_row(output)
hasreftag = hasreftag or has_output_note
materialsTable:node(output_row)
if output_cost > 0 then
local profit = output_cost - total_cost
local note
if (((6000 / (tonumber(ticks) or 5)) * profit) > 5000000) then
note = ((frame:extensionTag{
name = 'ref',
content = 'Due to Grand Exchange prices changing based on trade volume, this profit may not be fully accurate if the components are infrequently traded.',
args = { group = 'r' }
}) .. '[[Category:Recipes with questionable profit]]')
hasreftag = true
else
note = ''
end
materialsTable:tag('tr')
:tag('th'):attr('colspan', 3):css({['text-align'] = 'right'}):wikitext('Profit'):done()
:tag('td'):css({['text-align'] = 'right'}):wikitext(coins(output_cost - total_cost) .. note)
end
parent:node(requirements)
parent:node(materialsTable)
if not nosmw then
local jsonObject = {skills = skills, materials = {}, output = output}
local materialNames = {}
for _, v in ipairs(materials) do
table.insert(jsonObject.materials, {name = v.name, quantity = v.quantity})
table.insert(materialNames, v.name)
end
-- mw.smw.set({
-- ["Uses material"] = materialNames,
-- ['Production JSON'] = mw.text.jsonEncode(jsonObject)
-- })
end
local outro = ''
if hasreftag then
outro = '\n' .. frame:extensionTag{ name='references', args = { group='r' } }
end
return tostring(parent) .. categories(args) .. outro
end
function categories(args)
if not onmain() then
return ''
end
local cats = {}
if (args.ticks or '') == '' then
table.insert(cats, '[[Category:Recipes missing ticks]]')
end
if args.tools ~= nil then
table.insert(cats, '[[Category:Recipes that require a tool]]')
end
if args.facilities ~= nil then
table.insert(cats, '[[Category:Recipes that use a facility]]')
end
return table.concat(cats,'')
end
return p