Module:Crafting Recipes: Difference between revisions
From Valheim Wiki
No edit summary |
No edit summary |
||
| (32 intermediate revisions by the same user not shown) | |||
| Line 1: | Line 1: | ||
local item_link = require('Module:Item').go | local item_link = require('Module:Item').go | ||
local is_crafting_station = require('Module:Item').is_crafting_station | |||
local trim = mw.text.trim | local trim = mw.text.trim | ||
local cargo = mw.ext.cargo | local cargo = mw.ext.cargo | ||
| Line 5: | Line 6: | ||
local currentFrame -- global cache for current frame object. | local currentFrame -- global cache for current frame object. | ||
local inputArgs -- global args cache. | local inputArgs -- global args cache. | ||
local lang -- cache current lang. | local lang -- cache current lang. | ||
local resultanchor | local resultanchor | ||
local l10n = function(key) | local l10n = function(key) | ||
return key | |||
end | end | ||
| Line 23: | Line 24: | ||
function getArg(key) | function getArg(key) | ||
local v = trim(inputArgs[key] or '') | |||
if v == '' then | |||
return nil | |||
else | |||
return v | |||
end | |||
end | end | ||
local itemLink = (function() | local itemLink = (function() | ||
local cache = {} | |||
return function(name, args) | |||
local key = name .. "|" | |||
if args then | |||
for k, v in pairs(args) do | |||
key = key .. k .. '=' .. tostring(v) .. '|' | |||
end | |||
end | |||
if not cache[key] then | |||
local args = args and mw.clone(args) or {} | |||
args[1] = name | |||
if (not args[2]) or args[2] == '' then | |||
args[2] = currentFrame:expandTemplate { title = 'tr', args = { name, lang = lang } } | |||
end | |||
args['small'] = 'y' | |||
args['lang'] = lang or 'en' | |||
args['nolink'] = args['nolink'] and 'y' or nil | |||
local mode = args['mode'] or nil | |||
if mode == nil and name:lower() == 'by hand' then | |||
mode = 'noimage' | |||
end | |||
if mode ~= nil then | |||
args['mode'] = mode | |||
end | |||
cache[key] = item_link(currentFrame, args) | |||
end | |||
return cache[key] | |||
end | |||
end)() | end)() | ||
-- credit: http://richard.warburton.it | -- credit: http://richard.warburton.it | ||
-- this version is with trim. | -- this version is with trim. | ||
local explode = function(div,str) | local explode = function(div, str) | ||
if (div == '') then return false end | |||
local pos, arr = 0, {} | |||
-- for each divider found | |||
for st, sp in function() return string.find(str, div, pos, true) end do | |||
table.insert(arr, trim(string.sub(str, pos, st - 1))) -- Attach chars left of current divider | |||
pos = sp + 1 -- Jump past current divider | |||
end | |||
table.insert(arr, trim(string.sub(str, pos))) -- Attach chars right of last divider | |||
return arr | |||
end | end | ||
-- | -- return an array of itemname, split xxx/yyy to item1=xxx, item2=yyy. If it's something like "Lead/Iron Bar", it will normalize as item1 = Iron Bar, item2 = Lead Bar. | ||
local split = (function() | local split = (function() | ||
local metals = { | |||
['Copper/Tin'] = 1, | |||
['Tin/Copper'] = 2, | |||
} | |||
return function(name) | |||
local count = select(2, name:gsub("/", "/", 2)) | |||
if count == 0 then | |||
-- only 1 item | |||
return { trim(name) } | |||
elseif count == 1 then | |||
-- 2 items | |||
local item1a, item1b, item2a, item2b = name:match("^%s*(%S+)%s*(.-)/%s*(%S+)%s*(.-)$") | |||
local x = metals[item1a .. '/' .. item2a] | |||
if tostring(item1b) == '' and x then | |||
item1b = item2b | |||
end | |||
if x == 2 then | |||
return { trim(item2a .. ' ' .. item2b), trim(item1a .. ' ' .. item1b) } | |||
else | |||
return { trim(item1a .. ' ' .. item1b), trim(item2a .. ' ' .. item2b) } | |||
end | |||
else | |||
-- 3 or more items | |||
return explode('/', name) | |||
end | |||
end | |||
end)() | end)() | ||
-- return 1 or 2 value(s), when input is name[note], return item, note. | -- return 1 or 2 value(s), when input is name[note], return item, note. | ||
local itemname = function(str) | local itemname = function(str) | ||
local item, note = str:match("^(.-)(%b[])$") | |||
if item then | |||
return item, note | |||
else | |||
return str | |||
end | |||
end | end | ||
-- normalize ingredient name input, Lead Bar=>¦Lead Bar¦, Iron/Lead Bar => ¦Iron Bar¦Lead Bar¦, Lead/Iron Bar => ¦Iron Bar¦Lead Bar¦ .... | -- normalize ingredient name input, Lead Bar=>¦Lead Bar¦, Iron/Lead Bar => ¦Iron Bar¦Lead Bar¦, Lead/Iron Bar => ¦Iron Bar¦Lead Bar¦ .... | ||
local normalize = function(name) | local normalize = function(name) | ||
local result = '¦' | |||
for k, v in ipairs(split(name)) do | |||
result = result .. itemname(v) .. '¦' | |||
end | |||
return result | |||
end | end | ||
local escape = function(str) | local escape = function(str) | ||
return str:gsub("'", "\\'"):gsub("'", "\\'") | |||
end | end | ||
local enclose = function(str) | local enclose = function(str) | ||
return "'" .. escape(str) .. "'" | |||
end | end | ||
local getItemGroupName = function(item) | local getItemGroupName = function(item) | ||
if item == 'Wood' or item == 'Wood2' or item == 'Wood3' then | |||
return 'Any Wood' | |||
elseif item == 'Copper Bar' or item == 'Tin Bar' then | |||
return 'Any Bar' | |||
end | |||
end | end | ||
local normalizeStation = function(station) | local normalizeStation = function(station) | ||
return station | |||
end | end | ||
local normalizeVersion = function(_version) | local normalizeVersion = function(_version) | ||
return _version | |||
end | end | ||
local criStr = function(args) | local criStr = function(args) | ||
local constraints = {} | |||
-- station = ? and station != ? | |||
local _station = trim(args['station'] or '') | |||
local _stationnot = trim(args['stationnot'] or '') | |||
local str = '' | |||
if _station ~= '' then | |||
for _, v in ipairs(explode('/', _station)) do | |||
if str ~= '' then | |||
str = str .. ' OR ' | |||
end | |||
str = str .. "station = " .. enclose(normalizeStation(v)) | |||
end | |||
end | |||
if _stationnot ~= '' then | |||
if str ~= '' then | |||
str = '(' .. str .. ')' | |||
end | |||
for _, v in ipairs(explode('/', _stationnot)) do | |||
if str ~= '' then | |||
str = str .. ' AND ' | |||
end | |||
str = str .. 'station <> ' .. enclose(normalizeStation(v)) | |||
end | |||
end | |||
constraints['station'] = str | |||
local _result = trim(args['result'] or '') | |||
local _resultnot = trim(args['resultnot'] or '') | |||
local str = '' | |||
if _result ~= '' then | |||
for _, v in ipairs(explode('/', _result)) do | |||
if str ~= '' then | |||
str = str .. ' OR ' | |||
end | |||
if mw.ustring.sub(v, 1, 5) == 'LIKE ' then | |||
str = str .. "result LIKE " .. enclose(trim(mw.ustring.sub(v, 6))) | |||
else | |||
str = str .. 'result=' .. enclose(v) | |||
end | |||
end | |||
end | |||
if _resultnot ~= '' then | |||
if str ~= '' then | |||
str = '(' .. str .. ')' | |||
end | |||
for _, v in ipairs(explode('/', _resultnot)) do | |||
if str ~= '' then | |||
str = str .. ' AND ' | |||
end | |||
if mw.ustring.sub(v, 1, 5) == 'LIKE ' then | |||
str = str .. "result NOT LIKE " .. enclose(trim(mw.ustring.sub(v, 6))) | |||
else | |||
str = str .. 'result <> ' .. enclose(v) | |||
end | |||
end | |||
end | |||
if str ~= '' then | |||
constraints['result'] = str | |||
end | |||
-- ingredient = ? | |||
local _ingredient = trim(args['ingredient'] or '') | |||
if _ingredient ~= '' then | |||
local str = '' | |||
for _, v in ipairs(explode('/', _ingredient)) do | |||
if str ~= '' then | |||
str = str .. ' OR ' | |||
end | |||
if mw.ustring.sub(v, 1, 1) == '#' then | |||
str = str .. "ingredients HOLDS LIKE '%¦" .. escape(mw.ustring.sub(v, 2)) .. "¦%'" | |||
elseif mw.ustring.sub(v, 1, 5) == 'LIKE ' then | |||
str = str .. "ingredients HOLDS LIKE '%¦" .. escape(trim(mw.ustring.sub(v, 6))) .. "¦%'" | |||
else | |||
str = str .. "ingredients HOLDS LIKE '%¦" .. escape(v) .. "¦%'" | |||
-- any xxx | |||
local group = getItemGroupName(v) | |||
if group then | |||
str = str .. " OR ingredients HOLDS LIKE '%¦" .. escape(group) .. "¦%'" | |||
end | |||
end | |||
end | |||
constraints['ingredient'] = str | |||
end | |||
--versions | |||
local _version = normalizeVersion(args['version'] or args['versions'] or '') | |||
if _version ~= '' then | |||
constraints['version'] = 'version = ' .. enclose(_version) | |||
end | |||
local where = '' | |||
if constraints['station'] then | |||
where = constraints['station'] | |||
end | |||
if constraints['result'] then | |||
if where ~= '' then | |||
where = where .. ' AND ' | |||
end | |||
where = where .. '(' .. constraints['result'] .. ')' | |||
end | |||
if constraints['ingredient'] then | |||
if where ~= '' then | |||
where = where .. ' AND ' | |||
end | |||
where = where .. '(' .. constraints['ingredient'] .. ')' | |||
end | |||
if constraints['version'] then | |||
if where ~= '' then | |||
where = where .. ' AND ' | |||
end | |||
where = where .. '(' .. constraints['version'] .. ')' | |||
end | |||
return where | |||
end | end | ||
local resultCell = function(row, showResultId, needLink, noVersion, template) | local resultCell = function(row, showResultId, needLink, noVersion, template) | ||
local result, resultid, resultimage, resulttext, amount, version = row['result'], row['resultid'], row | |||
['resultimage'], row['resulttext'], row['amount'], row['version'] | |||
local str = '' | |||
local args = { anchor = resultanchor, nolink = not needLink, class = 'multi-line' } | |||
if showResultId then | |||
args['id'] = resultid | |||
end | |||
if resultimage then | |||
args['image'] = resultimage | |||
end | |||
if resulttext then | |||
args[2] = resulttext | |||
end | |||
if version ~= '' then | |||
args['icons'] = 'n' | |||
end | |||
str = str .. itemLink(result, args) | |||
if amount ~= '1' then | |||
str = str .. ' <span class="note-text">(' .. amount .. ')</span>' | |||
end | |||
if not noVersion and version ~= nil and version ~= '' then | |||
-- {{version icons}} is a slow template, so cache its result: | |||
local vstr = cache.get(lang .. ':recipes:versionicons:' .. version) -- cache for current lang | |||
if not vstr then | |||
vstr = ' (' .. currentFrame:expandTemplate { title = 'version icons', args = { version } } .. ')' | |||
cache.set(lang .. ':recipes:versionicons:' .. version, vstr, 3600 * 24) -- cache 24hr. | |||
end | |||
str = str .. vstr | |||
end | |||
if template then | |||
local template_str = currentFrame:expandTemplate { title = template, args = { | |||
link = needLink, showid = showResultId, noversion = noVersion, | |||
resultid = resultid, resultimage = resultimage, resulttext = resulttext, | |||
result = result, amount = amount, versions = version, | |||
} } | |||
str = template_str:gsub('@@@@', str) | |||
end | |||
return str | |||
end | end | ||
local ingredientsCell = function(args) | local ingredientsCell = function(args) | ||
local str = '<ul>' | |||
for _, v in ipairs(explode('^', args)) do | |||
str = str .. '<li>' | |||
local item, amount = v:match('^(.-)¦(.-)$') | |||
local s | |||
for _, itemname in ipairs(split(item)) do | |||
if s then | |||
s = s .. l10n('ingredients_sep') .. itemLink(itemname) | |||
else | |||
s = itemLink(itemname) | |||
end | |||
end | |||
str = str .. s | |||
if amount ~= '1' then | |||
str = str .. ' <span class="note-text">(' .. amount .. ')</span>' | |||
end | |||
str = str .. '</li>' | |||
end | |||
str = str .. '</ul>' | |||
return str | |||
end | end | ||
local stationCell = function(station, options) | local stationLevelLink = function(station, level) | ||
return '<div class="station-level-container" title="' .. l10n('Required station level') .. '">' | |||
.. '[[File:Crafting Station Level Star.png|link=' .. station .. ']]' | |||
.. '<span>' .. level .. '</span>' | |||
.. '</div>' | |||
end | |||
local stationCell = function(station, level, options) | |||
options = options or { wrap = 'y', suffixLinkWithItemTag = false } | |||
if station == 'By Hand' then | |||
return l10n('By Hand') | |||
elseif true == is_crafting_station(station) then | |||
-- station == 'Workbench' or station == 'Forge' or station == 'Cauldron' or station == 'Fermenter' then | |||
local linkItem = itemLink(station, options) | |||
if level ~= '' then | |||
linkItem = linkItem .. '<br>' .. stationLevelLink(station, level) | |||
end | |||
return linkItem | |||
-- return itemLink(station, options) | |||
elseif station == "Station One and Station Two" then | |||
return itemLink("Station One", options) .. l10n('And') .. itemLink('Station Two', { mode = 'text' }) | |||
else | |||
return station | |||
end | |||
end | end | ||
-- for extract. | -- for extract. | ||
local compactStation = function(station) | local compactStation = function(station) | ||
if station == 'By Hand' then | |||
return '' | |||
else | |||
return l10n('compact_before') .. station .. l10n('compact_after') | |||
end | |||
end | end | ||
local getFlags = function(args) | local getFlags = function(args) | ||
local needCate = 1 | |||
local needLink = true | |||
local _cate = trim(args['cate'] or '') | |||
if _cate == 'force' or _cate == 'all' then | |||
needCate = 2 | |||
elseif _cate == 'n' or _cate == 'no' then | |||
needCate = nil | |||
end | |||
local _link = trim(args['link'] or '') | |||
if _link == 'y' or _link == 'yes' or _link == 'force' then | |||
needLink = true | |||
elseif _link == 'n' or _link == 'no' then | |||
needLink = false | |||
end | |||
return needCate, needLink | |||
end | end | ||
| Line 433: | Line 392: | ||
local tableStart = function(title, withStation) | local tableStart = function(title, withStation) | ||
local header_ | |||
local str = '<div class="crafts ' .. (getArg('class') or '') | |||
local _id = (getArg('id') or '') | |||
if _id ~= '' then | |||
str = str .. '" id="' .. _id | |||
end | |||
local _css = (getArg('css') or getArg('style') or '') | |||
if _css ~= '' then | |||
str = str .. '" style="' .. _css | |||
end | |||
str = str .. '"><div class="wrap"><table ' | |||
if (getArg('sortable') or 'y'):sub(1, 1) ~= 'n' then | |||
str = str .. 'class="sortable" ' | |||
end | |||
str = str .. 'cellpadding="0" cellspacing="0">' | |||
if title ~= '' then | |||
str = str .. '<caption>' .. title .. '</caption>' | |||
end | |||
local _i, _field | |||
str = str .. '<tr>' | |||
_i = 1 | |||
_field = 'col-A-1' | |||
while getArg(_field) do | |||
if not extCols_A then | |||
extCols_A = {} | |||
end | |||
table.insert(extCols_A, _field) | |||
str = str .. '<th>' .. getArg(_field) .. '</th>' | |||
_i = _i + 1 | |||
_field = 'col-A-' .. _i | |||
end | |||
str = str .. '<th class="result">' .. (getArg('header-result') or l10n('Result')) .. '</th>' | |||
_i = 1 | |||
_field = 'col-B-1' | |||
while getArg(_field) do | |||
if not extCols_B then | |||
extCols_B = {} | |||
end | |||
table.insert(extCols_B, _field) | |||
str = str .. '<th>' .. getArg(_field) .. '</th>' | |||
_i = _i + 1 | |||
_field = 'col-B-' .. _i | |||
end | |||
str = str .. '<th class="ingredients">' .. (getArg('header-ingredients') or l10n('Ingredients')) .. '</th>' | |||
_i = 1 | |||
_field = 'col-C-1' | |||
while getArg(_field) do | |||
if not extCols_C then | |||
extCols_C = {} | |||
end | |||
table.insert(extCols_C, _field) | |||
str = str .. '<th>' .. getArg(_field) .. '</th>' | |||
_i = _i + 1 | |||
_field = 'col-C-' .. _i | |||
end | |||
if withStation then | |||
_i = 1 | |||
_field = 'station-col-before-1' | |||
while getArg(_field) do | |||
if not extCols_stationBefore then | |||
extCols_stationBefore = {} | |||
end | |||
table.insert(extCols_stationBefore, _field) | |||
str = str .. '<th class="station">' .. getArg(_field) .. '</th>' | |||
_i = _i + 1 | |||
_field = 'station-col-before-' .. _i | |||
end | |||
str = str .. '<th class="station">' .. (getArg('header-station') or l10n('Crafting Station')) .. '</th>' | |||
_i = 1 | |||
_field = 'station-col-after-1' | |||
while getArg(_field) do | |||
if not extCols_stationAfter then | |||
extCols_stationAfter = {} | |||
end | |||
table.insert(extCols_stationAfter, _field) | |||
str = str .. '<th class="station">' .. getArg(_field) .. '</th>' | |||
_i = _i + 1 | |||
_field = 'station-col-after-' .. _i | |||
end | |||
end | |||
_i = 1 | |||
_field = 'col-D-1' | |||
while getArg(_field) do | |||
if not extCols_D then | |||
extCols_D = {} | |||
end | |||
table.insert(extCols_D, _field) | |||
str = str .. '<th>' .. getArg(_field) .. '</th>' | |||
_i = _i + 1 | |||
_field = 'col-D-' .. _i | |||
end | |||
str = str .. '</tr>' | |||
return str | |||
end | end | ||
local tableEnd = function(rows_count, expectedrows) | local tableEnd = function(rows_count, expectedrows) | ||
local str = '</table><div style="display: none">total: ' .. rows_count .. ' row(s)</div></div></div>' | |||
if expectedrows and rows_count ~= expectedrows then | |||
str = str .. '[[Category:' .. l10n('cate_unexpected_rows_count') .. ']]' | |||
end | |||
if not expectedrows and rows_count == 0 then | |||
str = str .. '[[Category:' .. l10n('cate_no_row') .. ']]' | |||
end | |||
return str | |||
end | end | ||
local tableRow = function(str, row, current_station, station_count, rows_count, showResultId, withStation, needCate, needLink, needGroup, current_result, result_count, current_result_ext, result_ext_count, template, stationGroup) | local tableRow = function(str, row, current_station, station_count, rows_count, showResultId, withStation, needCate, | ||
needLink, needGroup, current_result, result_count, current_result_ext, result_ext_count, | |||
template, stationGroup) | |||
local str_w = '' -- before result col | |||
local str_x = '' -- between result and ingredients cols | |||
local str_y = '' -- between ingredients and station cols | |||
local str_z = '' -- after station | |||
local str_resultCell = '' | |||
local result_index = getArg('result-index-#' .. rows_count) or getArg('result-index-' .. row['result']) | |||
str = str .. '<tr data-rowid="' .. tostring(rows_count) .. '">' | |||
if needGroup then | |||
local result = row['result'] .. '|' .. (row['resultid'] or '') .. '|' .. row['amount'] | |||
-- grouping result col | |||
if current_result == result then -- is same group ?? | |||
result_count = result_count + 1 | |||
else | |||
--new group: | |||
-- rowspan value for prev group, if needed. | |||
if result_count then | |||
str = str:gsub("yyyrowspanyyy", tostring(result_count)) | |||
end | |||
-- begin this group | |||
current_result = result | |||
result_count = 1 | |||
str_resultCell = '<td class="result" rowspan="yyyrowspanyyy">' .. | |||
resultCell(row, showResultId, needLink, false, template) .. '</td>' | |||
end | |||
-- grouping ext cols | |||
if result_index and (current_result_ext == result_index) then -- is same group ?? | |||
result_ext_count = result_ext_count + 1 | |||
else | |||
--new group: | |||
-- rowspan value for prev group, if needed. | |||
if result_ext_count then | |||
str = str:gsub("zzzrowspanzzz", tostring(result_ext_count)) | |||
end | |||
-- begin this group | |||
current_result_ext = result_index | |||
result_ext_count = 1 | |||
if extCols_A then | |||
for _, v in ipairs(extCols_A) do | |||
if result_index then | |||
str_w = str_w .. | |||
'<td class="' .. | |||
v .. '" rowspan="zzzrowspanzzz">' .. (getArg(result_index .. '-row-' .. v) or '') .. '</td>' | |||
else | |||
str_w = str_w .. '<td class="' .. v .. '" rowspan="zzzrowspanzzz"></td>' | |||
end | |||
end | |||
end | |||
if extCols_B then | |||
for _, v in ipairs(extCols_B) do | |||
if result_index then | |||
str_x = str_x .. | |||
'<td class="' .. | |||
v .. '" rowspan="zzzrowspanzzz">' .. (getArg(result_index .. '-row-' .. v) or '') .. '</td>' | |||
else | |||
str_x = str_x .. '<td class="' .. v .. '" rowspan="zzzrowspanzzz"></td>' | |||
end | |||
end | |||
end | |||
-- extCols_C = { col-C-1 } | |||
-- for _, v in ipairs(extCols_C) = col-C-1 | |||
-- result_index = 'result-index-'..row['result'] = getArg('result-index-Grilled neck tail') = a | |||
-- value = result_index .. '-row-'' .. col-C-1) = getArg('a-row-col-C-1') = 20s | |||
if extCols_C then | |||
for _, v in ipairs(extCols_C) do | |||
if result_index then | |||
str_y = str_y .. | |||
'<td class="' .. | |||
v .. '" rowspan="zzzrowspanzzz">' .. (getArg(result_index .. '-row-' .. v) or '') .. '</td>' | |||
else | |||
str_y = str_y .. '<td class="' .. v .. '" rowspan="zzzrowspanzzz"></td>' | |||
end | |||
end | |||
end | |||
if extCols_D then | |||
for _, v in ipairs(extCols_D) do | |||
if result_index then | |||
str_z = str_z .. | |||
'<td class="' .. | |||
v .. '" rowspan="zzzrowspanzzz">' .. (getArg(result_index .. '-row-' .. v) or '') .. '</td>' | |||
else | |||
str_z = str_z .. '<td class="' .. v .. '" rowspan="zzzrowspanzzz"></td>' | |||
end | |||
end | |||
end | |||
end | |||
else | |||
if extCols_A then | |||
for _, v in ipairs(extCols_A) do | |||
if result_index then | |||
str_w = str_w .. '<td class="' .. v .. | |||
'">' .. (getArg(result_index .. '-row-' .. v) or '') .. '</td>' | |||
else | |||
str_w = str_w .. '<td class="' .. v .. '"></td>' | |||
end | |||
end | |||
end | |||
if extCols_B then | |||
for _, v in ipairs(extCols_B) do | |||
if result_index then | |||
str_x = str_x .. '<td class="' .. v .. | |||
'">' .. (getArg(result_index .. '-row-' .. v) or '') .. '</td>' | |||
else | |||
str_x = str_x .. '<td class="' .. v .. '"></td>' | |||
end | |||
end | |||
end | |||
if extCols_C then | |||
for _, v in ipairs(extCols_C) do | |||
if result_index then | |||
str_y = str_y .. '<td class="' .. v .. | |||
'">' .. (getArg(result_index .. '-row-' .. v) or '') .. '</td>' | |||
else | |||
str_y = str_y .. '<td class="' .. v .. '"></td>' | |||
end | |||
end | |||
end | |||
if extCols_D then | |||
for _, v in ipairs(extCols_D) do | |||
if result_index then | |||
str_z = str_z .. '<td class="' .. v .. | |||
'">' .. (getArg(result_index .. '-row-' .. v) or '') .. '</td>' | |||
else | |||
str_z = str_z .. '<td class="' .. v .. '"></td>' | |||
end | |||
end | |||
end | |||
str_resultCell = '<td class="result">' .. resultCell(row, showResultId, needLink, false, template) .. '</td>' | |||
end | |||
str = str .. | |||
str_w .. | |||
str_resultCell .. str_x .. '<td class="ingredients">' .. ingredientsCell(row['args']) .. '</td>' .. str_y | |||
if withStation then | |||
local stationName = row['station'] or '' | |||
local stationLevel = row['stationlevel'] or '' | |||
local station = stationName .. stationLevel -- @TODO: Mave | |||
if stationGroup then | |||
if current_station == station then -- is same group ?? | |||
station_count = station_count + 1 | |||
else | |||
--new group: | |||
-- rowspan value for prev group, if needed. | |||
if station_count then | |||
str = str:gsub("xxxrowspanxxx", tostring(station_count)) | |||
end | |||
-- begin this group | |||
current_station = station | |||
station_count = 1 | |||
local station_index = getArg('station-index-' .. station) | |||
-- station before: | |||
if extCols_stationBefore then | |||
for _, v in ipairs(extCols_stationBefore) do | |||
if station_index then | |||
str = str .. | |||
'<td class="station ' .. | |||
v .. | |||
'" rowspan="xxxrowspanxxx">' .. (getArg(station_index .. '-row-' .. v) or '') .. '</td>' | |||
else | |||
str = str .. '<td class="station ' .. v .. '" rowspan="xxxrowspanxxx"></td>' | |||
end | |||
end | |||
end | |||
str = str .. | |||
'<td class="station" data-station="' .. | |||
stationName .. | |||
'" data-stationlevel="' .. | |||
stationLevel .. '" rowspan="xxxrowspanxxx">' .. stationCell(stationName, stationLevel) .. '</td>' | |||
-- station after: | |||
if extCols_stationAfter then | |||
for _, v in ipairs(extCols_stationAfter) do | |||
if station_index then | |||
str = str .. | |||
'<td class="station ' .. | |||
v .. | |||
'" rowspan="xxxrowspanxxx">' .. (getArg(station_index .. '-row-' .. v) or '') .. '</td>' | |||
else | |||
str = str .. '<td class="station ' .. v .. '" rowspan="xxxrowspanxxx"></td>' | |||
end | |||
end | |||
end | |||
end | |||
else | |||
if current_station == station then -- is same group ?? | |||
station_count = station_count + 1 | |||
else | |||
current_station = station | |||
station_count = 1 | |||
end | |||
local station_index = getArg('station-index-' .. station) | |||
-- station before: | |||
if extCols_stationBefore then | |||
for _, v in ipairs(extCols_stationBefore) do | |||
if station_index then | |||
str = str .. | |||
'<td class="station ' .. | |||
v .. '">' .. (getArg(station_index .. '-row-' .. v) or '') .. '</td>' | |||
else | |||
str = str .. '<td class="station ' .. v .. '"></td>' | |||
end | |||
end | |||
end | |||
str = str .. '<td class="station">' .. stationCell(stationName, stationLevel) .. '</td>' | |||
-- station after: | |||
if extCols_stationAfter then | |||
for _, v in ipairs(extCols_stationAfter) do | |||
if station_index then | |||
str = str .. | |||
'<td class="station ' .. | |||
v .. '">' .. (getArg(station_index .. '-row-' .. v) or '') .. '</td>' | |||
else | |||
str = str .. '<td class="station ' .. v .. '"></td>' | |||
end | |||
end | |||
end | |||
end | |||
end | |||
str = str .. str_z .. '</tr>' | |||
return str, current_station, station_count, current_result, result_count, current_result_ext, result_ext_count | |||
end | end | ||
local extRows = function(withStation, isTop) | local extRows = function(withStation, isTop) | ||
local prefix | |||
if isTop then | |||
prefix = 'topextrow-' | |||
else | |||
prefix = 'extrow-' | |||
end | |||
local returnstr = '' | |||
local valid = true | |||
local p | |||
local str | |||
local _i = 1 | |||
local temp | |||
while valid do | |||
local i = tostring(_i) .. '-' | |||
p = prefix .. i | |||
valid = false | |||
str = '<tr data-' .. prefix .. 'id="' .. tostring(_i) .. '">' | |||
if extCols_A then | |||
for _, v in ipairs(extCols_A) do | |||
temp = getArg(p .. v) | |||
if temp then | |||
valid = true | |||
str = str .. '<td class="' .. v .. '">' .. temp .. '</td>' | |||
else | |||
str = str .. '<td class="' .. v .. '"></td>' | |||
end | |||
end | |||
end | |||
temp = getArg(p .. 'col-result') | |||
if temp then | |||
valid = true | |||
str = str .. '<td class="result">' .. temp .. '</td>' | |||
else | |||
str = str .. '<td class="result"></td>' | |||
end | |||
if extCols_B then | |||
for _, v in ipairs(extCols_B) do | |||
temp = getArg(p .. v) | |||
if temp then | |||
valid = true | |||
str = str .. '<td class="' .. v .. '">' .. temp .. '</td>' | |||
else | |||
str = str .. '<td class="' .. v .. '"></td>' | |||
end | |||
end | |||
end | |||
temp = getArg(p .. 'col-ingredients') | |||
if temp then | |||
valid = true | |||
str = str .. '<td class="ingredients">' .. temp .. '</td>' | |||
else | |||
str = str .. '<td class="ingredients"></td>' | |||
end | |||
if extCols_C then | |||
for _, v in ipairs(extCols_C) do | |||
temp = getArg(p .. v) | |||
if temp then | |||
valid = true | |||
str = str .. '<td class="' .. v .. '">' .. temp .. '</td>' | |||
else | |||
str = str .. '<td class="' .. v .. '"></td>' | |||
end | |||
end | |||
end | |||
if withStation then | |||
-- station before: | |||
if extCols_stationBefore then | |||
for _, v in ipairs(extCols_stationBefore) do | |||
temp = getArg(p .. v) | |||
if temp then | |||
valid = true | |||
str = str .. '<td class="station ' .. v .. '">' .. temp .. '</td>' | |||
else | |||
str = str .. '<td class="station ' .. v .. '"></td>' | |||
end | |||
end | |||
end | |||
temp = getArg(p .. 'col-station') | |||
if temp then | |||
valid = true | |||
str = str .. '<td class="station">' .. temp .. '</td>' | |||
else | |||
str = str .. '<td class="station"></td>' | |||
end | |||
-- station after: | |||
if extCols_stationAfter then | |||
for _, v in ipairs(extCols_stationAfter) do | |||
temp = getArg(p .. v) | |||
if temp then | |||
valid = true | |||
str = str .. '<td class="station ' .. v .. '">' .. temp .. '</td>' | |||
else | |||
str = str .. '<td class="station ' .. v .. '"></td>' | |||
end | |||
end | |||
end | |||
end | |||
if extCols_D then | |||
for _, v in ipairs(extCols_D) do | |||
temp = getArg(p .. v) | |||
if temp then | |||
valid = true | |||
str = str .. '<td class="' .. v .. '">' .. temp .. '</td>' | |||
else | |||
str = str .. '<td class="' .. v .. '"></td>' | |||
end | |||
end | |||
end | |||
str = str .. '</tr>' | |||
if valid then | |||
_i = _i + 1 | |||
returnstr = returnstr .. str | |||
end | |||
end | |||
return returnstr | |||
end | end | ||
local tableBody = function(result, showResultId, withStation, needGroup, needCate, needLink, rootpagename, title, expectedrows, template, stationGroup) | local tableBody = function(noResultsText, result, showResultId, withStation, needGroup, needCate, needLink, rootpagename, | ||
title, expectedrows, template, stationGroup) | |||
if next(result) == nil then | |||
return "''" .. (noResultsText or 'No results') .. "''" | |||
end | |||
local str = tableStart(title, withStation) | |||
-- top ext rows: | |||
str = str .. extRows(withStation, true) | |||
-- main rows: | |||
local current_station | |||
local station_count | |||
local rows_count = 0 | |||
local current_result | |||
local result_count | |||
local current_result_ext | |||
local result_ext_count | |||
for _, row in ipairs(result) do | |||
rows_count = rows_count + 1 | |||
-- table row: | |||
str, current_station, station_count, current_result, result_count, current_result_ext, result_ext_count = | |||
tableRow(str, row, current_station, station_count, rows_count, showResultId, withStation, needCate, needLink, | |||
needGroup, current_result, result_count, current_result_ext, result_ext_count, template, stationGroup) | |||
-- cate: | |||
if needCate then | |||
if needCate == 2 or rootpagename == currentFrame:expandTemplate { title = 'tr', args = { row['result'], lang = lang } } then | |||
addCate(row['station']) | |||
end | |||
end | |||
end | |||
-- rowspan value for last station group and result group | |||
if withStation and station_count and stationGroup then | |||
str = str:gsub("xxxrowspanxxx", tostring(station_count)) | |||
end | |||
if needGroup then | |||
str = str:gsub("yyyrowspanyyy", tostring(result_count)) | |||
str = str:gsub("zzzrowspanzzz", tostring(result_ext_count)) | |||
end | |||
-- ext rows: | |||
str = str .. extRows(withStation) | |||
-- table end | |||
str = str .. tableEnd(rows_count, expectedrows) | |||
-- cate | |||
if needCate then | |||
str = str .. cateStr() | |||
end | |||
return str | |||
end | end | ||
----------------------------------------------------------------- | ----------------------------------------------------------------- | ||
| Line 900: | Line 908: | ||
-- for {{craftingrecipes/register}} | -- for {{craftingrecipes/register}} | ||
p.register = function(frame) | p.register = function(frame) | ||
local args = frame:getParent().args | |||
-- {{{ingredients}}} | |||
local ingredients = {} -- list of {index, itemname, amount} | |||
for k, v in pairs(args) do | |||
if (type(k) == 'number') then | |||
if k % 2 == 1 then -- 2n-1, nth item | |||
local index, item, amount = (k + 1) / 2, trim(v), trim(args[k + 1]) | |||
ingredients[index] = { item, amount } | |||
end | |||
end | |||
end | |||
local serialized = '' -- serialized ingredients list | |||
for _, v in ipairs(ingredients) do | |||
serialized = serialized .. '^' .. v[1] .. '¦' .. v[2] | |||
end | |||
serialized = mw.ustring.sub(serialized, 2) | |||
table.sort(ingredients, function(a, b) return a[1] < b[1] end) -- sort by ingredient item name | |||
local ingredients_string = '' | |||
local ingredients_string_full = '' | |||
for _, v in ipairs(ingredients) do | |||
local name, amount = unpack(v) | |||
local ingstr = normalize(name) | |||
ingredients_string = ingredients_string .. '^' .. ingstr | |||
ingredients_string_full = ingredients_string_full .. '^' .. ingstr .. amount | |||
end | |||
--{{{version}}}, normalize | |||
version = normalizeVersion(args['version'] or '') | |||
--store | |||
frame:callParserFunction('#cargo_store:_table=CraftingRecipes', { | |||
result = trim(args['result'] or ''), | |||
resultid = trim(args['resultid'] or ''), | |||
resultimage = trim(args['image'] or ''), | |||
resulttext = trim(args['text'] or ''), | |||
amount = trim(args['amount'] or ''), | |||
version = version, | |||
station = normalizeStation(trim(args['station'] or '')), | |||
stationlevel = trim(args['stationlevel'] or ''), | |||
ingredients = mw.ustring.sub(ingredients_string, 2), | |||
ings = mw.ustring.sub(ingredients_string_full, 2), | |||
args = serialized, | |||
}) | |||
end -- p.register | end -- p.register | ||
-- for {{craftingrecipes}} | -- for {{craftingrecipes}} | ||
p.query = function(frame) | p.query = function(frame) | ||
currentFrame = frame -- global frame cache | |||
local args = frame:getParent().args | |||
inputArgs = args | |||
lang = frame.args['lang'] or 'en' | |||
resultanchor = trim(args['resultanchor'] or '') | |||
addCate, cateStr = (function() | |||
local cate = l10n('station_cate') | |||
local cateCache = {} | |||
local addCate = function(station) | |||
cateCache[station] = true | |||
end | |||
local cateStr = function() | |||
local str = '' | |||
for station, _ in pairs(cateCache) do | |||
str = str .. | |||
'[[Category:' .. | |||
(cate[station] or frame:expandTemplate { title = 'tr', args = { station, lang = lang, link = 'y' } }) .. | |||
']]' | |||
end | |||
if str ~= '' then | |||
str = '[[Category:' .. l10n('cate_craftable') .. ']]' .. str | |||
end | |||
return str | |||
end | |||
return addCate, cateStr | |||
end)() | |||
local where = trim(args['where'] or '') | |||
if where == '' then | |||
where = criStr(args) | |||
end | |||
-- no constraint no result. | |||
if where == '' then | |||
return '<span style="color:red;font-weight:bold;">CraftingRecipes: No constraint</span>' | |||
end | |||
-- format: | |||
local needCate, needLink = getFlags(args) | |||
local needGroup = true | |||
if (getArg('grouping') or 'y'):sub(1, 1) == 'n' then | |||
needGroup = false | |||
end | |||
local showResultId = false | |||
if trim(args['showresultid'] or '') ~= '' then | |||
showResultId = true | |||
end | |||
local _title = trim(args['title'] or '') | |||
local _expectedrows = trim(args['expectedrows'] or '') | |||
if _expectedrows ~= '' then | |||
_expectedrows = tonumber(_expectedrows) | |||
else | |||
_expectedrows = nil | |||
end | |||
local rootpagename = mw.title.getCurrentTitle().rootText | |||
local noResultsText = 'No results' | |||
if args['result'] or '' ~= '' then | |||
noResultsText = 'This item cannot be crafted' | |||
end | |||
if args['ingredient'] or '' ~= '' then | |||
noResultsText = 'This item is not used in any crafting recipes' | |||
end | |||
if trim(args['nostation'] or '') ~= '' then | |||
-- no station | |||
-- query, still need contain station field for cate. | |||
local result = mw.ext.cargo.query('CraftingRecipes', | |||
'result, resultid, resultimage, resulttext, amount, version, station, stationlevel, args', { | |||
where = where, | |||
groupBy = "resultid, result, amount, version, ings", | |||
orderBy = "result, amount DESC, version", -- Don't order by station | |||
limit = 2000, | |||
}) | |||
return tableBody(noResultsText, result, showResultId, false, needGroup, needCate, needLink, rootpagename, _title, | |||
_expectedrows, getArg('resulttemplate'), false) | |||
else | |||
-- with station | |||
local stationGroup = true | |||
if (getArg('stationgrouping') or 'y'):sub(1, 1) == 'n' then | |||
stationGroup = false | |||
end | |||
-- query | |||
local result = mw.ext.cargo.query('CraftingRecipes', | |||
'result, resultid, resultimage, resulttext, amount, version, station, stationlevel, args', { | |||
where = where, | |||
groupBy = "resultid, result, amount, ings, version", | |||
orderBy = "station, stationlevel, result, amount DESC, version, ings", -- order by station first for station grouping. | |||
limit = 2000, | |||
}) | |||
return tableBody(noResultsText, result, showResultId, true, needGroup, needCate, needLink, rootpagename, _title, | |||
_expectedrows, getArg('resulttemplate'), stationGroup) | |||
end | |||
end -- p.query | end -- p.query | ||
-- for {{craftingrecipes/extract}} | -- for {{craftingrecipes/extract}} | ||
p.extract = function(frame) | p.extract = function(frame) | ||
currentFrame = frame -- global frame cache | |||
local args = frame:getParent().args | |||
inputArgs = args | |||
lang = frame.args['lang'] or 'en' | |||
--l10n_table = l10n_info[lang] or l10n_info['en'] | |||
local where = trim(args['where'] or '') | |||
if where == '' then | |||
where = criStr(args) | |||
end | |||
-- no constraint no result. | |||
if where == '' then | |||
return '<span style="color:red;font-weight:bold;">CraftingRecipes/extract: No constraint</span>' | |||
end | |||
-- query: | |||
local result = mw.ext.cargo.query('CraftingRecipes', | |||
'result, resultid, resultimage, resulttext, amount, version, station, stationlevel, args', { | |||
where = where, | |||
groupBy = "resultid, result, amount, version, ings", | |||
orderBy = "result, amount DESC, version", -- Don't order by station | |||
limit = 20, -- enough. | |||
}) | |||
-- output | |||
local mode = getArg('mode') | |||
local sep = getArg('sep') or getArg('seperator') | |||
if not mode or mode == 'compact' or mode == '' then | |||
--default mode = compact | |||
local sep = sep or l10n('default_sep_compact') | |||
local withResult = getArg('withresult') | |||
local withStation = not getArg('nostation') | |||
local withVersion = not getArg('noversion') | |||
local str = nil | |||
for _, row in ipairs(result) do | |||
if str then | |||
str = str .. sep | |||
else | |||
str = '' | |||
end | |||
str = str .. '<span class="recipe compact">' | |||
if withVersion then | |||
if row['version'] ~= '' then | |||
str = str .. currentFrame:expandTemplate { title = 'version icons', args = { row['version'] } } .. | |||
': ' | |||
end | |||
end | |||
local ingFlag = nil | |||
for _, v in ipairs(explode('^', row['args'])) do | |||
if ingFlag then | |||
str = str .. ' + ' | |||
else | |||
ingFlag = true | |||
end | |||
local item, amount = v:match('^(.-)¦(.-)$') | |||
if amount ~= '1' then | |||
str = str .. amount .. ' ' | |||
end | |||
local s | |||
for _, itemname in ipairs(split(item)) do | |||
if s then | |||
s = s .. " / " .. itemLink(itemname, { mode = 'image' }) | |||
else | |||
s = itemLink(itemname, { mode = 'image' }) | |||
end | |||
end | |||
str = str .. s | |||
end | |||
if withResult then | |||
str = str .. ' = ' | |||
if row['amount'] ~= '1' then | |||
str = str .. row['amount'] .. ' ' | |||
end | |||
local args = { mode = 'image' } | |||
if row['resultimage'] then | |||
args['image'] = row['resultimage'] | |||
end | |||
str = str .. itemLink(row['result'], args) | |||
end | |||
if withStation then | |||
str = str .. compactStation(row['station']) | |||
end | |||
str = str .. '</span>' | |||
end | |||
return str | |||
elseif mode == 'ingredients' then | |||
local sep = sep or l10n('default_sep_ingredients') | |||
local str = '' | |||
for _, row in ipairs(result) do | |||
if str ~= '' then | |||
str = str .. sep | |||
end | |||
str = str .. ingredientsCell(row['args']) | |||
end | |||
return '<div class="crafting-ingredients">' .. str .. '</div>' | |||
elseif mode == 'station' then | |||
-- only return first row. | |||
for _, row in ipairs(result) do | |||
return stationCell(row['station'], '', {}) | |||
end | |||
elseif mode == 'result' then | |||
-- only return first row. | |||
local needCate, needLink = getFlags(args) | |||
for _, row in ipairs(result) do | |||
return resultCell(row, getArg('showresultid'), needLink, true, getArg('resulttemplate')) | |||
end | |||
elseif mode == 'ingredients-buy' then | |||
-- only process first row. | |||
for _, row in ipairs(result) do | |||
local value = 0 | |||
for _, v in ipairs(explode('^', row['args'])) do | |||
local item, amount = v:match('^(.-)¦(.-)$') | |||
value = value + | |||
require('Module:Iteminfo').getItemStat( | |||
tonumber(currentFrame:expandTemplate { title = 'itemIdFromName', args = { item, lang = 'en' } }) or | |||
0, | |||
'value') * amount | |||
end | |||
return value | |||
end | |||
elseif mode == 'ingredients-sell' then | |||
-- only process first row. | |||
for _, row in ipairs(result) do | |||
local value = 0 | |||
for _, v in ipairs(explode('^', row['args'])) do | |||
local item, amount = v:match('^(.-)¦(.-)$') | |||
value = value + | |||
math.floor(require('Module:Iteminfo').getItemStat( | |||
tonumber(currentFrame:expandTemplate { title = 'itemIdFromName', args = { item, lang = 'en' } }) or | |||
0, | |||
'value') / 5) * amount | |||
end | |||
return value | |||
end | |||
else | |||
return '<span style="color:red;font-weight:bold;">CraftingRecipes/extract: Invalid mode</span>' | |||
end | |||
end -- p.extract | end -- p.extract | ||
-- count | -- count | ||
p.count = function(frame) | p.count = function(frame) | ||
local args = frame:getParent().args | |||
local where = trim(args['where'] or '') | |||
if where == '' then | |||
where = criStr(args) | |||
end | |||
-- no constraint no result. | |||
if where == '' then | |||
return | |||
end | |||
-- query: since we must use group by to eliminate duplicates, so we can not use COUNT() to get row count directly. | |||
local result = mw.ext.cargo.query('CraftingRecipes', | |||
'result, resultid, resultimage, resulttext, amount, version, station, stationlevel, args', { | |||
where = where, | |||
groupBy = "resultid, result, amount, ings, version", | |||
limit = 2000, | |||
}) | |||
-- count | |||
local count = 0 | |||
for _, row in ipairs(result) do | |||
count = count + 1 | |||
end | |||
return count | |||
end -- p.count | end -- p.count | ||
-- return "yes" or "" | -- return "yes" or "" | ||
p.exist = function(frame) | p.exist = function(frame) | ||
local args = frame:getParent().args | |||
local where = trim(args['where'] or '') | |||
if where == '' then | |||
where = criStr(args) | |||
end | |||
-- no constraint no result. | |||
if where == '' then | |||
return | |||
end | |||
-- query: | |||
local result = mw.ext.cargo.query('CraftingRecipes', 'result', { | |||
where = where, | |||
limit = 1, -- enough. | |||
}) | |||
-- output | |||
for _, row in ipairs(result) do | |||
return 'yes' | |||
end | |||
end -- p.exist | end -- p.exist | ||
return p | return p | ||
Latest revision as of 22:00, 8 February 2026
Documentation for this module may be created at Module:Crafting Recipes/doc
local item_link = require('Module:Item').go
local is_crafting_station = require('Module:Item').is_crafting_station
local trim = mw.text.trim
local cargo = mw.ext.cargo
local cache = require 'mw.ext.LuaCache'
local currentFrame -- global cache for current frame object.
local inputArgs -- global args cache.
local lang -- cache current lang.
local resultanchor
local l10n = function(key)
return key
end
local extCols_stationBefore = nil
local extCols_stationAfter = nil
local extCols_A = nil
local extCols_B = nil
local extCols_C = nil
local extCols_D = nil
function getArg(key)
local v = trim(inputArgs[key] or '')
if v == '' then
return nil
else
return v
end
end
local itemLink = (function()
local cache = {}
return function(name, args)
local key = name .. "|"
if args then
for k, v in pairs(args) do
key = key .. k .. '=' .. tostring(v) .. '|'
end
end
if not cache[key] then
local args = args and mw.clone(args) or {}
args[1] = name
if (not args[2]) or args[2] == '' then
args[2] = currentFrame:expandTemplate { title = 'tr', args = { name, lang = lang } }
end
args['small'] = 'y'
args['lang'] = lang or 'en'
args['nolink'] = args['nolink'] and 'y' or nil
local mode = args['mode'] or nil
if mode == nil and name:lower() == 'by hand' then
mode = 'noimage'
end
if mode ~= nil then
args['mode'] = mode
end
cache[key] = item_link(currentFrame, args)
end
return cache[key]
end
end)()
-- credit: http://richard.warburton.it
-- this version is with trim.
local explode = function(div, str)
if (div == '') then return false end
local pos, arr = 0, {}
-- for each divider found
for st, sp in function() return string.find(str, div, pos, true) end do
table.insert(arr, trim(string.sub(str, pos, st - 1))) -- Attach chars left of current divider
pos = sp + 1 -- Jump past current divider
end
table.insert(arr, trim(string.sub(str, pos))) -- Attach chars right of last divider
return arr
end
-- return an array of itemname, split xxx/yyy to item1=xxx, item2=yyy. If it's something like "Lead/Iron Bar", it will normalize as item1 = Iron Bar, item2 = Lead Bar.
local split = (function()
local metals = {
['Copper/Tin'] = 1,
['Tin/Copper'] = 2,
}
return function(name)
local count = select(2, name:gsub("/", "/", 2))
if count == 0 then
-- only 1 item
return { trim(name) }
elseif count == 1 then
-- 2 items
local item1a, item1b, item2a, item2b = name:match("^%s*(%S+)%s*(.-)/%s*(%S+)%s*(.-)$")
local x = metals[item1a .. '/' .. item2a]
if tostring(item1b) == '' and x then
item1b = item2b
end
if x == 2 then
return { trim(item2a .. ' ' .. item2b), trim(item1a .. ' ' .. item1b) }
else
return { trim(item1a .. ' ' .. item1b), trim(item2a .. ' ' .. item2b) }
end
else
-- 3 or more items
return explode('/', name)
end
end
end)()
-- return 1 or 2 value(s), when input is name[note], return item, note.
local itemname = function(str)
local item, note = str:match("^(.-)(%b[])$")
if item then
return item, note
else
return str
end
end
-- normalize ingredient name input, Lead Bar=>¦Lead Bar¦, Iron/Lead Bar => ¦Iron Bar¦Lead Bar¦, Lead/Iron Bar => ¦Iron Bar¦Lead Bar¦ ....
local normalize = function(name)
local result = '¦'
for k, v in ipairs(split(name)) do
result = result .. itemname(v) .. '¦'
end
return result
end
local escape = function(str)
return str:gsub("'", "\\'"):gsub("'", "\\'")
end
local enclose = function(str)
return "'" .. escape(str) .. "'"
end
local getItemGroupName = function(item)
if item == 'Wood' or item == 'Wood2' or item == 'Wood3' then
return 'Any Wood'
elseif item == 'Copper Bar' or item == 'Tin Bar' then
return 'Any Bar'
end
end
local normalizeStation = function(station)
return station
end
local normalizeVersion = function(_version)
return _version
end
local criStr = function(args)
local constraints = {}
-- station = ? and station != ?
local _station = trim(args['station'] or '')
local _stationnot = trim(args['stationnot'] or '')
local str = ''
if _station ~= '' then
for _, v in ipairs(explode('/', _station)) do
if str ~= '' then
str = str .. ' OR '
end
str = str .. "station = " .. enclose(normalizeStation(v))
end
end
if _stationnot ~= '' then
if str ~= '' then
str = '(' .. str .. ')'
end
for _, v in ipairs(explode('/', _stationnot)) do
if str ~= '' then
str = str .. ' AND '
end
str = str .. 'station <> ' .. enclose(normalizeStation(v))
end
end
constraints['station'] = str
local _result = trim(args['result'] or '')
local _resultnot = trim(args['resultnot'] or '')
local str = ''
if _result ~= '' then
for _, v in ipairs(explode('/', _result)) do
if str ~= '' then
str = str .. ' OR '
end
if mw.ustring.sub(v, 1, 5) == 'LIKE ' then
str = str .. "result LIKE " .. enclose(trim(mw.ustring.sub(v, 6)))
else
str = str .. 'result=' .. enclose(v)
end
end
end
if _resultnot ~= '' then
if str ~= '' then
str = '(' .. str .. ')'
end
for _, v in ipairs(explode('/', _resultnot)) do
if str ~= '' then
str = str .. ' AND '
end
if mw.ustring.sub(v, 1, 5) == 'LIKE ' then
str = str .. "result NOT LIKE " .. enclose(trim(mw.ustring.sub(v, 6)))
else
str = str .. 'result <> ' .. enclose(v)
end
end
end
if str ~= '' then
constraints['result'] = str
end
-- ingredient = ?
local _ingredient = trim(args['ingredient'] or '')
if _ingredient ~= '' then
local str = ''
for _, v in ipairs(explode('/', _ingredient)) do
if str ~= '' then
str = str .. ' OR '
end
if mw.ustring.sub(v, 1, 1) == '#' then
str = str .. "ingredients HOLDS LIKE '%¦" .. escape(mw.ustring.sub(v, 2)) .. "¦%'"
elseif mw.ustring.sub(v, 1, 5) == 'LIKE ' then
str = str .. "ingredients HOLDS LIKE '%¦" .. escape(trim(mw.ustring.sub(v, 6))) .. "¦%'"
else
str = str .. "ingredients HOLDS LIKE '%¦" .. escape(v) .. "¦%'"
-- any xxx
local group = getItemGroupName(v)
if group then
str = str .. " OR ingredients HOLDS LIKE '%¦" .. escape(group) .. "¦%'"
end
end
end
constraints['ingredient'] = str
end
--versions
local _version = normalizeVersion(args['version'] or args['versions'] or '')
if _version ~= '' then
constraints['version'] = 'version = ' .. enclose(_version)
end
local where = ''
if constraints['station'] then
where = constraints['station']
end
if constraints['result'] then
if where ~= '' then
where = where .. ' AND '
end
where = where .. '(' .. constraints['result'] .. ')'
end
if constraints['ingredient'] then
if where ~= '' then
where = where .. ' AND '
end
where = where .. '(' .. constraints['ingredient'] .. ')'
end
if constraints['version'] then
if where ~= '' then
where = where .. ' AND '
end
where = where .. '(' .. constraints['version'] .. ')'
end
return where
end
local resultCell = function(row, showResultId, needLink, noVersion, template)
local result, resultid, resultimage, resulttext, amount, version = row['result'], row['resultid'], row
['resultimage'], row['resulttext'], row['amount'], row['version']
local str = ''
local args = { anchor = resultanchor, nolink = not needLink, class = 'multi-line' }
if showResultId then
args['id'] = resultid
end
if resultimage then
args['image'] = resultimage
end
if resulttext then
args[2] = resulttext
end
if version ~= '' then
args['icons'] = 'n'
end
str = str .. itemLink(result, args)
if amount ~= '1' then
str = str .. ' <span class="note-text">(' .. amount .. ')</span>'
end
if not noVersion and version ~= nil and version ~= '' then
-- {{version icons}} is a slow template, so cache its result:
local vstr = cache.get(lang .. ':recipes:versionicons:' .. version) -- cache for current lang
if not vstr then
vstr = ' (' .. currentFrame:expandTemplate { title = 'version icons', args = { version } } .. ')'
cache.set(lang .. ':recipes:versionicons:' .. version, vstr, 3600 * 24) -- cache 24hr.
end
str = str .. vstr
end
if template then
local template_str = currentFrame:expandTemplate { title = template, args = {
link = needLink, showid = showResultId, noversion = noVersion,
resultid = resultid, resultimage = resultimage, resulttext = resulttext,
result = result, amount = amount, versions = version,
} }
str = template_str:gsub('@@@@', str)
end
return str
end
local ingredientsCell = function(args)
local str = '<ul>'
for _, v in ipairs(explode('^', args)) do
str = str .. '<li>'
local item, amount = v:match('^(.-)¦(.-)$')
local s
for _, itemname in ipairs(split(item)) do
if s then
s = s .. l10n('ingredients_sep') .. itemLink(itemname)
else
s = itemLink(itemname)
end
end
str = str .. s
if amount ~= '1' then
str = str .. ' <span class="note-text">(' .. amount .. ')</span>'
end
str = str .. '</li>'
end
str = str .. '</ul>'
return str
end
local stationLevelLink = function(station, level)
return '<div class="station-level-container" title="' .. l10n('Required station level') .. '">'
.. '[[File:Crafting Station Level Star.png|link=' .. station .. ']]'
.. '<span>' .. level .. '</span>'
.. '</div>'
end
local stationCell = function(station, level, options)
options = options or { wrap = 'y', suffixLinkWithItemTag = false }
if station == 'By Hand' then
return l10n('By Hand')
elseif true == is_crafting_station(station) then
-- station == 'Workbench' or station == 'Forge' or station == 'Cauldron' or station == 'Fermenter' then
local linkItem = itemLink(station, options)
if level ~= '' then
linkItem = linkItem .. '<br>' .. stationLevelLink(station, level)
end
return linkItem
-- return itemLink(station, options)
elseif station == "Station One and Station Two" then
return itemLink("Station One", options) .. l10n('And') .. itemLink('Station Two', { mode = 'text' })
else
return station
end
end
-- for extract.
local compactStation = function(station)
if station == 'By Hand' then
return ''
else
return l10n('compact_before') .. station .. l10n('compact_after')
end
end
local getFlags = function(args)
local needCate = 1
local needLink = true
local _cate = trim(args['cate'] or '')
if _cate == 'force' or _cate == 'all' then
needCate = 2
elseif _cate == 'n' or _cate == 'no' then
needCate = nil
end
local _link = trim(args['link'] or '')
if _link == 'y' or _link == 'yes' or _link == 'force' then
needLink = true
elseif _link == 'n' or _link == 'no' then
needLink = false
end
return needCate, needLink
end
local addCate, cateStr -- for table body. init in p.query
local tableStart = function(title, withStation)
local header_
local str = '<div class="crafts ' .. (getArg('class') or '')
local _id = (getArg('id') or '')
if _id ~= '' then
str = str .. '" id="' .. _id
end
local _css = (getArg('css') or getArg('style') or '')
if _css ~= '' then
str = str .. '" style="' .. _css
end
str = str .. '"><div class="wrap"><table '
if (getArg('sortable') or 'y'):sub(1, 1) ~= 'n' then
str = str .. 'class="sortable" '
end
str = str .. 'cellpadding="0" cellspacing="0">'
if title ~= '' then
str = str .. '<caption>' .. title .. '</caption>'
end
local _i, _field
str = str .. '<tr>'
_i = 1
_field = 'col-A-1'
while getArg(_field) do
if not extCols_A then
extCols_A = {}
end
table.insert(extCols_A, _field)
str = str .. '<th>' .. getArg(_field) .. '</th>'
_i = _i + 1
_field = 'col-A-' .. _i
end
str = str .. '<th class="result">' .. (getArg('header-result') or l10n('Result')) .. '</th>'
_i = 1
_field = 'col-B-1'
while getArg(_field) do
if not extCols_B then
extCols_B = {}
end
table.insert(extCols_B, _field)
str = str .. '<th>' .. getArg(_field) .. '</th>'
_i = _i + 1
_field = 'col-B-' .. _i
end
str = str .. '<th class="ingredients">' .. (getArg('header-ingredients') or l10n('Ingredients')) .. '</th>'
_i = 1
_field = 'col-C-1'
while getArg(_field) do
if not extCols_C then
extCols_C = {}
end
table.insert(extCols_C, _field)
str = str .. '<th>' .. getArg(_field) .. '</th>'
_i = _i + 1
_field = 'col-C-' .. _i
end
if withStation then
_i = 1
_field = 'station-col-before-1'
while getArg(_field) do
if not extCols_stationBefore then
extCols_stationBefore = {}
end
table.insert(extCols_stationBefore, _field)
str = str .. '<th class="station">' .. getArg(_field) .. '</th>'
_i = _i + 1
_field = 'station-col-before-' .. _i
end
str = str .. '<th class="station">' .. (getArg('header-station') or l10n('Crafting Station')) .. '</th>'
_i = 1
_field = 'station-col-after-1'
while getArg(_field) do
if not extCols_stationAfter then
extCols_stationAfter = {}
end
table.insert(extCols_stationAfter, _field)
str = str .. '<th class="station">' .. getArg(_field) .. '</th>'
_i = _i + 1
_field = 'station-col-after-' .. _i
end
end
_i = 1
_field = 'col-D-1'
while getArg(_field) do
if not extCols_D then
extCols_D = {}
end
table.insert(extCols_D, _field)
str = str .. '<th>' .. getArg(_field) .. '</th>'
_i = _i + 1
_field = 'col-D-' .. _i
end
str = str .. '</tr>'
return str
end
local tableEnd = function(rows_count, expectedrows)
local str = '</table><div style="display: none">total: ' .. rows_count .. ' row(s)</div></div></div>'
if expectedrows and rows_count ~= expectedrows then
str = str .. '[[Category:' .. l10n('cate_unexpected_rows_count') .. ']]'
end
if not expectedrows and rows_count == 0 then
str = str .. '[[Category:' .. l10n('cate_no_row') .. ']]'
end
return str
end
local tableRow = function(str, row, current_station, station_count, rows_count, showResultId, withStation, needCate,
needLink, needGroup, current_result, result_count, current_result_ext, result_ext_count,
template, stationGroup)
local str_w = '' -- before result col
local str_x = '' -- between result and ingredients cols
local str_y = '' -- between ingredients and station cols
local str_z = '' -- after station
local str_resultCell = ''
local result_index = getArg('result-index-#' .. rows_count) or getArg('result-index-' .. row['result'])
str = str .. '<tr data-rowid="' .. tostring(rows_count) .. '">'
if needGroup then
local result = row['result'] .. '|' .. (row['resultid'] or '') .. '|' .. row['amount']
-- grouping result col
if current_result == result then -- is same group ??
result_count = result_count + 1
else
--new group:
-- rowspan value for prev group, if needed.
if result_count then
str = str:gsub("yyyrowspanyyy", tostring(result_count))
end
-- begin this group
current_result = result
result_count = 1
str_resultCell = '<td class="result" rowspan="yyyrowspanyyy">' ..
resultCell(row, showResultId, needLink, false, template) .. '</td>'
end
-- grouping ext cols
if result_index and (current_result_ext == result_index) then -- is same group ??
result_ext_count = result_ext_count + 1
else
--new group:
-- rowspan value for prev group, if needed.
if result_ext_count then
str = str:gsub("zzzrowspanzzz", tostring(result_ext_count))
end
-- begin this group
current_result_ext = result_index
result_ext_count = 1
if extCols_A then
for _, v in ipairs(extCols_A) do
if result_index then
str_w = str_w ..
'<td class="' ..
v .. '" rowspan="zzzrowspanzzz">' .. (getArg(result_index .. '-row-' .. v) or '') .. '</td>'
else
str_w = str_w .. '<td class="' .. v .. '" rowspan="zzzrowspanzzz"></td>'
end
end
end
if extCols_B then
for _, v in ipairs(extCols_B) do
if result_index then
str_x = str_x ..
'<td class="' ..
v .. '" rowspan="zzzrowspanzzz">' .. (getArg(result_index .. '-row-' .. v) or '') .. '</td>'
else
str_x = str_x .. '<td class="' .. v .. '" rowspan="zzzrowspanzzz"></td>'
end
end
end
-- extCols_C = { col-C-1 }
-- for _, v in ipairs(extCols_C) = col-C-1
-- result_index = 'result-index-'..row['result'] = getArg('result-index-Grilled neck tail') = a
-- value = result_index .. '-row-'' .. col-C-1) = getArg('a-row-col-C-1') = 20s
if extCols_C then
for _, v in ipairs(extCols_C) do
if result_index then
str_y = str_y ..
'<td class="' ..
v .. '" rowspan="zzzrowspanzzz">' .. (getArg(result_index .. '-row-' .. v) or '') .. '</td>'
else
str_y = str_y .. '<td class="' .. v .. '" rowspan="zzzrowspanzzz"></td>'
end
end
end
if extCols_D then
for _, v in ipairs(extCols_D) do
if result_index then
str_z = str_z ..
'<td class="' ..
v .. '" rowspan="zzzrowspanzzz">' .. (getArg(result_index .. '-row-' .. v) or '') .. '</td>'
else
str_z = str_z .. '<td class="' .. v .. '" rowspan="zzzrowspanzzz"></td>'
end
end
end
end
else
if extCols_A then
for _, v in ipairs(extCols_A) do
if result_index then
str_w = str_w .. '<td class="' .. v ..
'">' .. (getArg(result_index .. '-row-' .. v) or '') .. '</td>'
else
str_w = str_w .. '<td class="' .. v .. '"></td>'
end
end
end
if extCols_B then
for _, v in ipairs(extCols_B) do
if result_index then
str_x = str_x .. '<td class="' .. v ..
'">' .. (getArg(result_index .. '-row-' .. v) or '') .. '</td>'
else
str_x = str_x .. '<td class="' .. v .. '"></td>'
end
end
end
if extCols_C then
for _, v in ipairs(extCols_C) do
if result_index then
str_y = str_y .. '<td class="' .. v ..
'">' .. (getArg(result_index .. '-row-' .. v) or '') .. '</td>'
else
str_y = str_y .. '<td class="' .. v .. '"></td>'
end
end
end
if extCols_D then
for _, v in ipairs(extCols_D) do
if result_index then
str_z = str_z .. '<td class="' .. v ..
'">' .. (getArg(result_index .. '-row-' .. v) or '') .. '</td>'
else
str_z = str_z .. '<td class="' .. v .. '"></td>'
end
end
end
str_resultCell = '<td class="result">' .. resultCell(row, showResultId, needLink, false, template) .. '</td>'
end
str = str ..
str_w ..
str_resultCell .. str_x .. '<td class="ingredients">' .. ingredientsCell(row['args']) .. '</td>' .. str_y
if withStation then
local stationName = row['station'] or ''
local stationLevel = row['stationlevel'] or ''
local station = stationName .. stationLevel -- @TODO: Mave
if stationGroup then
if current_station == station then -- is same group ??
station_count = station_count + 1
else
--new group:
-- rowspan value for prev group, if needed.
if station_count then
str = str:gsub("xxxrowspanxxx", tostring(station_count))
end
-- begin this group
current_station = station
station_count = 1
local station_index = getArg('station-index-' .. station)
-- station before:
if extCols_stationBefore then
for _, v in ipairs(extCols_stationBefore) do
if station_index then
str = str ..
'<td class="station ' ..
v ..
'" rowspan="xxxrowspanxxx">' .. (getArg(station_index .. '-row-' .. v) or '') .. '</td>'
else
str = str .. '<td class="station ' .. v .. '" rowspan="xxxrowspanxxx"></td>'
end
end
end
str = str ..
'<td class="station" data-station="' ..
stationName ..
'" data-stationlevel="' ..
stationLevel .. '" rowspan="xxxrowspanxxx">' .. stationCell(stationName, stationLevel) .. '</td>'
-- station after:
if extCols_stationAfter then
for _, v in ipairs(extCols_stationAfter) do
if station_index then
str = str ..
'<td class="station ' ..
v ..
'" rowspan="xxxrowspanxxx">' .. (getArg(station_index .. '-row-' .. v) or '') .. '</td>'
else
str = str .. '<td class="station ' .. v .. '" rowspan="xxxrowspanxxx"></td>'
end
end
end
end
else
if current_station == station then -- is same group ??
station_count = station_count + 1
else
current_station = station
station_count = 1
end
local station_index = getArg('station-index-' .. station)
-- station before:
if extCols_stationBefore then
for _, v in ipairs(extCols_stationBefore) do
if station_index then
str = str ..
'<td class="station ' ..
v .. '">' .. (getArg(station_index .. '-row-' .. v) or '') .. '</td>'
else
str = str .. '<td class="station ' .. v .. '"></td>'
end
end
end
str = str .. '<td class="station">' .. stationCell(stationName, stationLevel) .. '</td>'
-- station after:
if extCols_stationAfter then
for _, v in ipairs(extCols_stationAfter) do
if station_index then
str = str ..
'<td class="station ' ..
v .. '">' .. (getArg(station_index .. '-row-' .. v) or '') .. '</td>'
else
str = str .. '<td class="station ' .. v .. '"></td>'
end
end
end
end
end
str = str .. str_z .. '</tr>'
return str, current_station, station_count, current_result, result_count, current_result_ext, result_ext_count
end
local extRows = function(withStation, isTop)
local prefix
if isTop then
prefix = 'topextrow-'
else
prefix = 'extrow-'
end
local returnstr = ''
local valid = true
local p
local str
local _i = 1
local temp
while valid do
local i = tostring(_i) .. '-'
p = prefix .. i
valid = false
str = '<tr data-' .. prefix .. 'id="' .. tostring(_i) .. '">'
if extCols_A then
for _, v in ipairs(extCols_A) do
temp = getArg(p .. v)
if temp then
valid = true
str = str .. '<td class="' .. v .. '">' .. temp .. '</td>'
else
str = str .. '<td class="' .. v .. '"></td>'
end
end
end
temp = getArg(p .. 'col-result')
if temp then
valid = true
str = str .. '<td class="result">' .. temp .. '</td>'
else
str = str .. '<td class="result"></td>'
end
if extCols_B then
for _, v in ipairs(extCols_B) do
temp = getArg(p .. v)
if temp then
valid = true
str = str .. '<td class="' .. v .. '">' .. temp .. '</td>'
else
str = str .. '<td class="' .. v .. '"></td>'
end
end
end
temp = getArg(p .. 'col-ingredients')
if temp then
valid = true
str = str .. '<td class="ingredients">' .. temp .. '</td>'
else
str = str .. '<td class="ingredients"></td>'
end
if extCols_C then
for _, v in ipairs(extCols_C) do
temp = getArg(p .. v)
if temp then
valid = true
str = str .. '<td class="' .. v .. '">' .. temp .. '</td>'
else
str = str .. '<td class="' .. v .. '"></td>'
end
end
end
if withStation then
-- station before:
if extCols_stationBefore then
for _, v in ipairs(extCols_stationBefore) do
temp = getArg(p .. v)
if temp then
valid = true
str = str .. '<td class="station ' .. v .. '">' .. temp .. '</td>'
else
str = str .. '<td class="station ' .. v .. '"></td>'
end
end
end
temp = getArg(p .. 'col-station')
if temp then
valid = true
str = str .. '<td class="station">' .. temp .. '</td>'
else
str = str .. '<td class="station"></td>'
end
-- station after:
if extCols_stationAfter then
for _, v in ipairs(extCols_stationAfter) do
temp = getArg(p .. v)
if temp then
valid = true
str = str .. '<td class="station ' .. v .. '">' .. temp .. '</td>'
else
str = str .. '<td class="station ' .. v .. '"></td>'
end
end
end
end
if extCols_D then
for _, v in ipairs(extCols_D) do
temp = getArg(p .. v)
if temp then
valid = true
str = str .. '<td class="' .. v .. '">' .. temp .. '</td>'
else
str = str .. '<td class="' .. v .. '"></td>'
end
end
end
str = str .. '</tr>'
if valid then
_i = _i + 1
returnstr = returnstr .. str
end
end
return returnstr
end
local tableBody = function(noResultsText, result, showResultId, withStation, needGroup, needCate, needLink, rootpagename,
title, expectedrows, template, stationGroup)
if next(result) == nil then
return "''" .. (noResultsText or 'No results') .. "''"
end
local str = tableStart(title, withStation)
-- top ext rows:
str = str .. extRows(withStation, true)
-- main rows:
local current_station
local station_count
local rows_count = 0
local current_result
local result_count
local current_result_ext
local result_ext_count
for _, row in ipairs(result) do
rows_count = rows_count + 1
-- table row:
str, current_station, station_count, current_result, result_count, current_result_ext, result_ext_count =
tableRow(str, row, current_station, station_count, rows_count, showResultId, withStation, needCate, needLink,
needGroup, current_result, result_count, current_result_ext, result_ext_count, template, stationGroup)
-- cate:
if needCate then
if needCate == 2 or rootpagename == currentFrame:expandTemplate { title = 'tr', args = { row['result'], lang = lang } } then
addCate(row['station'])
end
end
end
-- rowspan value for last station group and result group
if withStation and station_count and stationGroup then
str = str:gsub("xxxrowspanxxx", tostring(station_count))
end
if needGroup then
str = str:gsub("yyyrowspanyyy", tostring(result_count))
str = str:gsub("zzzrowspanzzz", tostring(result_ext_count))
end
-- ext rows:
str = str .. extRows(withStation)
-- table end
str = str .. tableEnd(rows_count, expectedrows)
-- cate
if needCate then
str = str .. cateStr()
end
return str
end
-----------------------------------------------------------------
local p = {}
-- for {{craftingrecipes/register}}
p.register = function(frame)
local args = frame:getParent().args
-- {{{ingredients}}}
local ingredients = {} -- list of {index, itemname, amount}
for k, v in pairs(args) do
if (type(k) == 'number') then
if k % 2 == 1 then -- 2n-1, nth item
local index, item, amount = (k + 1) / 2, trim(v), trim(args[k + 1])
ingredients[index] = { item, amount }
end
end
end
local serialized = '' -- serialized ingredients list
for _, v in ipairs(ingredients) do
serialized = serialized .. '^' .. v[1] .. '¦' .. v[2]
end
serialized = mw.ustring.sub(serialized, 2)
table.sort(ingredients, function(a, b) return a[1] < b[1] end) -- sort by ingredient item name
local ingredients_string = ''
local ingredients_string_full = ''
for _, v in ipairs(ingredients) do
local name, amount = unpack(v)
local ingstr = normalize(name)
ingredients_string = ingredients_string .. '^' .. ingstr
ingredients_string_full = ingredients_string_full .. '^' .. ingstr .. amount
end
--{{{version}}}, normalize
version = normalizeVersion(args['version'] or '')
--store
frame:callParserFunction('#cargo_store:_table=CraftingRecipes', {
result = trim(args['result'] or ''),
resultid = trim(args['resultid'] or ''),
resultimage = trim(args['image'] or ''),
resulttext = trim(args['text'] or ''),
amount = trim(args['amount'] or ''),
version = version,
station = normalizeStation(trim(args['station'] or '')),
stationlevel = trim(args['stationlevel'] or ''),
ingredients = mw.ustring.sub(ingredients_string, 2),
ings = mw.ustring.sub(ingredients_string_full, 2),
args = serialized,
})
end -- p.register
-- for {{craftingrecipes}}
p.query = function(frame)
currentFrame = frame -- global frame cache
local args = frame:getParent().args
inputArgs = args
lang = frame.args['lang'] or 'en'
resultanchor = trim(args['resultanchor'] or '')
addCate, cateStr = (function()
local cate = l10n('station_cate')
local cateCache = {}
local addCate = function(station)
cateCache[station] = true
end
local cateStr = function()
local str = ''
for station, _ in pairs(cateCache) do
str = str ..
'[[Category:' ..
(cate[station] or frame:expandTemplate { title = 'tr', args = { station, lang = lang, link = 'y' } }) ..
']]'
end
if str ~= '' then
str = '[[Category:' .. l10n('cate_craftable') .. ']]' .. str
end
return str
end
return addCate, cateStr
end)()
local where = trim(args['where'] or '')
if where == '' then
where = criStr(args)
end
-- no constraint no result.
if where == '' then
return '<span style="color:red;font-weight:bold;">CraftingRecipes: No constraint</span>'
end
-- format:
local needCate, needLink = getFlags(args)
local needGroup = true
if (getArg('grouping') or 'y'):sub(1, 1) == 'n' then
needGroup = false
end
local showResultId = false
if trim(args['showresultid'] or '') ~= '' then
showResultId = true
end
local _title = trim(args['title'] or '')
local _expectedrows = trim(args['expectedrows'] or '')
if _expectedrows ~= '' then
_expectedrows = tonumber(_expectedrows)
else
_expectedrows = nil
end
local rootpagename = mw.title.getCurrentTitle().rootText
local noResultsText = 'No results'
if args['result'] or '' ~= '' then
noResultsText = 'This item cannot be crafted'
end
if args['ingredient'] or '' ~= '' then
noResultsText = 'This item is not used in any crafting recipes'
end
if trim(args['nostation'] or '') ~= '' then
-- no station
-- query, still need contain station field for cate.
local result = mw.ext.cargo.query('CraftingRecipes',
'result, resultid, resultimage, resulttext, amount, version, station, stationlevel, args', {
where = where,
groupBy = "resultid, result, amount, version, ings",
orderBy = "result, amount DESC, version", -- Don't order by station
limit = 2000,
})
return tableBody(noResultsText, result, showResultId, false, needGroup, needCate, needLink, rootpagename, _title,
_expectedrows, getArg('resulttemplate'), false)
else
-- with station
local stationGroup = true
if (getArg('stationgrouping') or 'y'):sub(1, 1) == 'n' then
stationGroup = false
end
-- query
local result = mw.ext.cargo.query('CraftingRecipes',
'result, resultid, resultimage, resulttext, amount, version, station, stationlevel, args', {
where = where,
groupBy = "resultid, result, amount, ings, version",
orderBy = "station, stationlevel, result, amount DESC, version, ings", -- order by station first for station grouping.
limit = 2000,
})
return tableBody(noResultsText, result, showResultId, true, needGroup, needCate, needLink, rootpagename, _title,
_expectedrows, getArg('resulttemplate'), stationGroup)
end
end -- p.query
-- for {{craftingrecipes/extract}}
p.extract = function(frame)
currentFrame = frame -- global frame cache
local args = frame:getParent().args
inputArgs = args
lang = frame.args['lang'] or 'en'
--l10n_table = l10n_info[lang] or l10n_info['en']
local where = trim(args['where'] or '')
if where == '' then
where = criStr(args)
end
-- no constraint no result.
if where == '' then
return '<span style="color:red;font-weight:bold;">CraftingRecipes/extract: No constraint</span>'
end
-- query:
local result = mw.ext.cargo.query('CraftingRecipes',
'result, resultid, resultimage, resulttext, amount, version, station, stationlevel, args', {
where = where,
groupBy = "resultid, result, amount, version, ings",
orderBy = "result, amount DESC, version", -- Don't order by station
limit = 20, -- enough.
})
-- output
local mode = getArg('mode')
local sep = getArg('sep') or getArg('seperator')
if not mode or mode == 'compact' or mode == '' then
--default mode = compact
local sep = sep or l10n('default_sep_compact')
local withResult = getArg('withresult')
local withStation = not getArg('nostation')
local withVersion = not getArg('noversion')
local str = nil
for _, row in ipairs(result) do
if str then
str = str .. sep
else
str = ''
end
str = str .. '<span class="recipe compact">'
if withVersion then
if row['version'] ~= '' then
str = str .. currentFrame:expandTemplate { title = 'version icons', args = { row['version'] } } ..
': '
end
end
local ingFlag = nil
for _, v in ipairs(explode('^', row['args'])) do
if ingFlag then
str = str .. ' + '
else
ingFlag = true
end
local item, amount = v:match('^(.-)¦(.-)$')
if amount ~= '1' then
str = str .. amount .. ' '
end
local s
for _, itemname in ipairs(split(item)) do
if s then
s = s .. " / " .. itemLink(itemname, { mode = 'image' })
else
s = itemLink(itemname, { mode = 'image' })
end
end
str = str .. s
end
if withResult then
str = str .. ' = '
if row['amount'] ~= '1' then
str = str .. row['amount'] .. ' '
end
local args = { mode = 'image' }
if row['resultimage'] then
args['image'] = row['resultimage']
end
str = str .. itemLink(row['result'], args)
end
if withStation then
str = str .. compactStation(row['station'])
end
str = str .. '</span>'
end
return str
elseif mode == 'ingredients' then
local sep = sep or l10n('default_sep_ingredients')
local str = ''
for _, row in ipairs(result) do
if str ~= '' then
str = str .. sep
end
str = str .. ingredientsCell(row['args'])
end
return '<div class="crafting-ingredients">' .. str .. '</div>'
elseif mode == 'station' then
-- only return first row.
for _, row in ipairs(result) do
return stationCell(row['station'], '', {})
end
elseif mode == 'result' then
-- only return first row.
local needCate, needLink = getFlags(args)
for _, row in ipairs(result) do
return resultCell(row, getArg('showresultid'), needLink, true, getArg('resulttemplate'))
end
elseif mode == 'ingredients-buy' then
-- only process first row.
for _, row in ipairs(result) do
local value = 0
for _, v in ipairs(explode('^', row['args'])) do
local item, amount = v:match('^(.-)¦(.-)$')
value = value +
require('Module:Iteminfo').getItemStat(
tonumber(currentFrame:expandTemplate { title = 'itemIdFromName', args = { item, lang = 'en' } }) or
0,
'value') * amount
end
return value
end
elseif mode == 'ingredients-sell' then
-- only process first row.
for _, row in ipairs(result) do
local value = 0
for _, v in ipairs(explode('^', row['args'])) do
local item, amount = v:match('^(.-)¦(.-)$')
value = value +
math.floor(require('Module:Iteminfo').getItemStat(
tonumber(currentFrame:expandTemplate { title = 'itemIdFromName', args = { item, lang = 'en' } }) or
0,
'value') / 5) * amount
end
return value
end
else
return '<span style="color:red;font-weight:bold;">CraftingRecipes/extract: Invalid mode</span>'
end
end -- p.extract
-- count
p.count = function(frame)
local args = frame:getParent().args
local where = trim(args['where'] or '')
if where == '' then
where = criStr(args)
end
-- no constraint no result.
if where == '' then
return
end
-- query: since we must use group by to eliminate duplicates, so we can not use COUNT() to get row count directly.
local result = mw.ext.cargo.query('CraftingRecipes',
'result, resultid, resultimage, resulttext, amount, version, station, stationlevel, args', {
where = where,
groupBy = "resultid, result, amount, ings, version",
limit = 2000,
})
-- count
local count = 0
for _, row in ipairs(result) do
count = count + 1
end
return count
end -- p.count
-- return "yes" or ""
p.exist = function(frame)
local args = frame:getParent().args
local where = trim(args['where'] or '')
if where == '' then
where = criStr(args)
end
-- no constraint no result.
if where == '' then
return
end
-- query:
local result = mw.ext.cargo.query('CraftingRecipes', 'result', {
where = where,
limit = 1, -- enough.
})
-- output
for _, row in ipairs(result) do
return 'yes'
end
end -- p.exist
return p