Module:Crafting Recipes
From Valheim Wiki
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