| Latest revision |
Your text |
| Line 1: |
Line 1: |
| local p = {} | | local p = {} |
|
| |
| local lib = require('Module:Feature') | | local lib = require('Module:Feature') |
| local Parse = require('Module:Parser').getTemplateArgs | | local Parse = require('Module:Parser').getTemplateArgs |
| local Rlib = require('Module:Recipe').param | | local Rlib = require('Module:Recipe').param |
| local Item = require('Module:Item')._main | | local Item = require('Module:Item')._main |
|
| |
| --------------------------------------------------------------------------------
| |
| -- Helpers
| |
| --------------------------------------------------------------------------------
| |
|
| |
| local function isNotEmpty(v)
| |
| return lib.isNotEmpty(v)
| |
| end
| |
|
| |
| local function normalizeText(s)
| |
| return mw.ustring.lower(mw.text.trim(tostring(s or '')))
| |
| end
| |
|
| |
| local function getKitchenwareArg()
| |
| return Rlib.sKitchArg or 'kitchenware'
| |
| end
| |
|
| |
| local function getSortDelimiter(sort)
| |
| return lib.ternary(
| |
| sort:find(Rlib.sSortDelim2),
| |
| Rlib.sSortDelim2,
| |
| Rlib.sSortDelim
| |
| )
| |
| end
| |
|
| |
| local function isCookingRecipe(recipe)
| |
| return normalizeText(recipe[Rlib.sTypeArg]) == 'cooking'
| |
| end
| |
|
| |
| local function getMaxCookingItemIndex(recipe)
| |
| local maxIndex = 0
| |
|
| |
| for key, _ in pairs(recipe) do
| |
| local index = tostring(key):match('^item_(%d+)')
| |
|
| |
| if index then
| |
| index = tonumber(index)
| |
|
| |
| if index and index > maxIndex then
| |
| maxIndex = index
| |
| end
| |
| end
| |
| end
| |
|
| |
| return maxIndex
| |
| end
| |
|
| |
| --------------------------------------------------------------------------------
| |
| -- Usage detection
| |
| --------------------------------------------------------------------------------
| |
|
| |
| local function standardRecipeUsesItem(recipe, item)
| |
| if not isNotEmpty(recipe['sort']) then
| |
| return false
| |
| end
| |
|
| |
| if not isNotEmpty(recipe[item]) then
| |
| return false
| |
| end
| |
|
| |
| for name in lib.gsplit(recipe['sort'], getSortDelimiter(recipe['sort'])) do
| |
| if isNotEmpty(name) and name == item then
| |
| return true
| |
| end
| |
| end
| |
|
| |
| return false
| |
| end
| |
|
| |
| local function cookingRecipeUsesItem(recipe, item)
| |
| local maxIndex = getMaxCookingItemIndex(recipe)
| |
|
| |
| for index = 1, maxIndex do
| |
| local prefix = 'item_' .. index
| |
|
| |
| -- Specific item:
| |
| -- |item_1 = Rice
| |
| if isNotEmpty(recipe[prefix]) and recipe[prefix] == item then
| |
| return true
| |
| end
| |
|
| |
| -- Single type:
| |
| -- |item_1_type = Fish
| |
| if isNotEmpty(recipe[prefix .. '_type']) and recipe[prefix .. '_type'] == item then
| |
| return true
| |
| end
| |
|
| |
| -- Multiple types:
| |
| -- |item_1_type_1 = Freshwater Fish
| |
| -- |item_1_type_2 = Saltwater Fish
| |
| local typeIndex = 1
| |
|
| |
| while isNotEmpty(recipe[prefix .. '_type_' .. typeIndex]) do
| |
| if recipe[prefix .. '_type_' .. typeIndex] == item then
| |
| return true
| |
| end
| |
|
| |
| typeIndex = typeIndex + 1
| |
| end
| |
|
| |
| -- Multiple accepted specific items:
| |
| -- |item_1_option_1 = Rice
| |
| -- |item_1_option_2 = Wheat
| |
| local optionIndex = 1
| |
|
| |
| while isNotEmpty(recipe[prefix .. '_option_' .. optionIndex]) do
| |
| if recipe[prefix .. '_option_' .. optionIndex] == item then
| |
| return true
| |
| end
| |
|
| |
| optionIndex = optionIndex + 1
| |
| end
| |
| end
| |
|
| |
| -- Kitchenware:
| |
| -- |kitchenware = Cooking Pot
| |
| local kitchenwareArg = getKitchenwareArg()
| |
|
| |
| if isNotEmpty(recipe[kitchenwareArg]) and recipe[kitchenwareArg] == item then
| |
| return true
| |
| end
| |
|
| |
| -- Multiple kitchenware:
| |
| -- |kitchenware_1 =
| |
| -- |kitchenware_2 =
| |
| local kitchenwareIndex = 1
| |
|
| |
| while isNotEmpty(recipe[kitchenwareArg .. '_' .. kitchenwareIndex]) do
| |
| if recipe[kitchenwareArg .. '_' .. kitchenwareIndex] == item then
| |
| return true
| |
| end
| |
|
| |
| kitchenwareIndex = kitchenwareIndex + 1
| |
| end
| |
|
| |
| return false
| |
| end
| |
|
| |
| local function recipeUsesItem(recipe, item)
| |
| if isCookingRecipe(recipe) then
| |
| return cookingRecipeUsesItem(recipe, item)
| |
| end
| |
|
| |
| return standardRecipeUsesItem(recipe, item)
| |
| end
| |
|
| |
| --------------------------------------------------------------------------------
| |
| -- Recipe display helpers
| |
| --------------------------------------------------------------------------------
| |
|
| |
| local function renderItem(name, amount, quality)
| |
| local out = tostring(Item({
| |
| name,
| |
| size = 20,
| |
| x = amount
| |
| }))
| |
|
| |
| if isNotEmpty(quality) then
| |
| out = out .. ' <small>(' .. quality .. ')</small>'
| |
| end
| |
|
| |
| return out
| |
| end
| |
|
| |
| local function renderIconLink(name, amount, quality)
| |
| local out = ''
| |
|
| |
| if isNotEmpty(amount) then
| |
| out = tostring(amount) .. '× '
| |
| end
| |
|
| |
| out = out .. '[[File:' .. name .. ' Icon.png|20x20px|link=' .. name .. ']] [[' .. name .. ']]'
| |
|
| |
| if isNotEmpty(quality) then
| |
| out = out .. ' <small>(' .. quality .. ')</small>'
| |
| end
| |
|
| |
| return out
| |
| end
| |
|
| |
| local function renderStandardIngredients(recipe)
| |
| local ingredients = {}
| |
|
| |
| if not isNotEmpty(recipe['sort']) then
| |
| return ingredients
| |
| end
| |
|
| |
| for name in lib.gsplit(recipe['sort'], getSortDelimiter(recipe['sort'])) do
| |
| if isNotEmpty(name) and isNotEmpty(recipe[name]) then
| |
| table.insert(ingredients, Item({
| |
| name,
| |
| size = 20,
| |
| x = recipe[name]
| |
| }))
| |
| end
| |
| end
| |
|
| |
| return ingredients
| |
| end
| |
|
| |
| local function renderCookingIngredient(recipe, index)
| |
| local prefix = 'item_' .. index
| |
| local amount = recipe[prefix .. '_amount'] or '1'
| |
| local quality = recipe[prefix .. '_quality']
| |
|
| |
| -- Specific item:
| |
| -- |item_1 = Rice
| |
| if isNotEmpty(recipe[prefix]) then
| |
| return renderItem(recipe[prefix], amount, quality)
| |
| end
| |
|
| |
| -- Specific item options:
| |
| -- |item_1_option_1 = Rice
| |
| -- |item_1_option_2 = Wheat
| |
| local options = {}
| |
| local optionIndex = 1
| |
|
| |
| while isNotEmpty(recipe[prefix .. '_option_' .. optionIndex]) do
| |
| table.insert(options, renderItem(
| |
| recipe[prefix .. '_option_' .. optionIndex],
| |
| amount,
| |
| quality
| |
| ))
| |
|
| |
| optionIndex = optionIndex + 1
| |
| end
| |
|
| |
| if #options > 0 then
| |
| return table.concat(options, ' / ')
| |
| end
| |
|
| |
| -- Type requirements:
| |
| -- |item_1_type = Fish
| |
| -- |item_1_type_1 = Freshwater Fish
| |
| -- |item_1_type_2 = Saltwater Fish
| |
| local types = {}
| |
|
| |
| if isNotEmpty(recipe[prefix .. '_type']) then
| |
| table.insert(types, renderIconLink(
| |
| recipe[prefix .. '_type'],
| |
| amount,
| |
| quality
| |
| ))
| |
| end
| |
|
| |
| local typeIndex = 1
| |
|
| |
| while isNotEmpty(recipe[prefix .. '_type_' .. typeIndex]) do
| |
| table.insert(types, renderIconLink(
| |
| recipe[prefix .. '_type_' .. typeIndex],
| |
| amount,
| |
| quality
| |
| ))
| |
|
| |
| typeIndex = typeIndex + 1
| |
| end
| |
|
| |
| if #types > 0 then
| |
| return table.concat(types, ' / ')
| |
| end
| |
|
| |
| return nil
| |
| end
| |
|
| |
| local function renderCookingIngredients(recipe)
| |
| local ingredients = {}
| |
| local maxIndex = getMaxCookingItemIndex(recipe)
| |
|
| |
| for index = 1, maxIndex do
| |
| local rendered = renderCookingIngredient(recipe, index)
| |
|
| |
| if isNotEmpty(rendered) then
| |
| table.insert(ingredients, rendered)
| |
| end
| |
| end
| |
|
| |
| return ingredients
| |
| end
| |
|
| |
| local function renderCookingKitchenware(recipe)
| |
| local kitchenwareArg = getKitchenwareArg()
| |
| local kitchenware = {}
| |
|
| |
| if isNotEmpty(recipe[kitchenwareArg]) then
| |
| table.insert(kitchenware, renderIconLink(recipe[kitchenwareArg]))
| |
| end
| |
|
| |
| local index = 1
| |
|
| |
| while isNotEmpty(recipe[kitchenwareArg .. '_' .. index]) do
| |
| table.insert(kitchenware, renderIconLink(recipe[kitchenwareArg .. '_' .. index]))
| |
| index = index + 1
| |
| end
| |
|
| |
| return kitchenware
| |
| end
| |
|
| |
| local function renderRecipeIngredients(recipe)
| |
| if isCookingRecipe(recipe) then
| |
| return renderCookingIngredients(recipe)
| |
| end
| |
|
| |
| return renderStandardIngredients(recipe)
| |
| end
| |
|
| |
| local function hasCookingRecipes(valids)
| |
| for _, recipes in pairs(valids) do
| |
| for _, recipe in pairs(recipes) do
| |
| if isCookingRecipe(recipe) then
| |
| return true
| |
| end
| |
| end
| |
| end
| |
|
| |
| return false
| |
| end
| |
|
| |
| --------------------------------------------------------------------------------
| |
| -- Main
| |
| --------------------------------------------------------------------------------
| |
|
| |
|
| function p.main(frame) | | function p.main(frame) |
| Line 331: |
Line 10: |
| wrappers = {'Template:Item Usage'} | | wrappers = {'Template:Item Usage'} |
| }) | | }) |
|
| |
| local item = args[1] or mw.title.getCurrentTitle().rootText | | local item = args[1] or mw.title.getCurrentTitle().rootText |
| local count = 0 | | local count = 0 |
| local craftType = args['type'] | | local craftType = args['type'] |
| local out = mw.html.create() | | local out = mw.html.create() |
| | | if lib.isNotEmpty(frame.args.pages) and frame.args.pages:find('%$%$%$') then |
| if isNotEmpty(frame.args.pages) and frame.args.pages:find('%$%$%$') then | |
| local valids = {} | | local valids = {} |
|
| |
| for page in lib.gsplit(frame.args.pages, '$$$') do | | for page in lib.gsplit(frame.args.pages, '$$$') do |
| local data = Parse(page, { only = 'Recipe' }) | | local data = Parse(page, { only='Recipe' } ) |
| | | if type(data[1]) ~= 'table' then data = {data} end |
| if type(data[1]) ~= 'table' then | |
| data = { data }
| |
| end
| |
| | |
| for _, call in ipairs(data) do | | for _, call in ipairs(data) do |
| if recipeUsesItem(call, item) then | | if lib.isNotEmpty(call['sort']) and lib.isNotEmpty(call[item]) then |
| valids[page] = valids[page] or {}
| | for name in lib.gsplit(call['sort'], lib.ternary(call['sort']:find(Rlib.sSortDelim2), Rlib.sSortDelim2, Rlib.sSortDelim)) do |
| table.insert(valids[page], call)
| | if (lib.isNotEmpty(name) and name == item) then |
| count = count + 1
| | valids[page] = valids[page] or {} |
| | table.insert(valids[page], call) |
| | count = count + 1 |
| | end |
| | end |
| end | | end |
| end | | end |
| end | | end |
| | | |
| if craftType == 'Furnishing Set' then | | if craftType == 'Furnishing Set' then |
| out:wikitext( | | out:wikitext('There ', lib.ternary(count > 1,'are', 'is'), ' <b>', tostring(count), '</b> [[Furnishing Set]]', lib.ternary(count > 1, 's', ''), ' that use', lib.ternary(count > 1, '', 's'), ' [[', item , ']] as a component:\n') |
| 'There ',
| |
| lib.ternary(count > 1, 'are', 'is'),
| |
| ' <b>',
| |
| tostring(count),
| |
| '</b> [[Furnishing Set]]',
| |
| lib.ternary(count > 1, 's', ''),
| |
| ' that use',
| |
| lib.ternary(count > 1, '', 's'),
| |
| ' [[',
| |
| item,
| |
| ']] as a component:\n'
| |
| )
| |
| else | | else |
| out:wikitext( | | out:wikitext('There ', lib.ternary(count > 1,'are', 'is'), ' <b>', tostring(count), '</b> use', lib.ternary(count > 1, 's', ''), ' for [[', item , ']]:\n') |
| 'There ',
| |
| lib.ternary(count > 1, 'are', 'is'),
| |
| ' <b>',
| |
| tostring(count),
| |
| '</b> use',
| |
| lib.ternary(count > 1, 's', ''),
| |
| ' for [[',
| |
| item,
| |
| ']]:\n'
| |
| )
| |
| end | | end |
| | | |
| out:node(p._main(valids, craftType)) | | out:node(p._main(valids, craftType)) |
|
| |
| return out | | return out |
| else | | else |
| Line 393: |
Line 46: |
| out:wikitext('No recipes use [[', item, ']] as an ingredient.') | | out:wikitext('No recipes use [[', item, ']] as an ingredient.') |
| end | | end |
|
| |
| return out | | return out |
| end | | end |
| Line 399: |
Line 51: |
|
| |
|
| function p._main(valids, craftType) | | function p._main(valids, craftType) |
| local _table = mw.html.create('table'):addClass('wikitable article-table sortable') | | local _table = mw.html.create('table'):addClass('fandom-table article-table sortable') |
| local showKitchenware = hasCookingRecipes(valids) | | |
| | | -- header row |
| -- Header row | |
| local tr = _table:tag('tr') | | local tr = _table:tag('tr') |
| tr:tag('th'):wikitext('Item') | | tr:tag('th'):wikitext('Item') |
| tr:tag('th'):wikitext('Craft Type') | | tr:tag('th'):wikitext('Craft Type') |
|
| |
| if showKitchenware then
| |
| tr:tag('th'):wikitext('Kitchenware')
| |
| end
| |
|
| |
| tr:tag('th'):wikitext(craftType == 'Furnishing Set' and 'Components' or 'Recipe') | | tr:tag('th'):wikitext(craftType == 'Furnishing Set' and 'Components' or 'Recipe') |
| | | -- mw.logObject(valids) |
| | -- rest of table |
| for page, recipes in lib.spairs(valids) do | | for page, recipes in lib.spairs(valids) do |
| local tr = _table:tag('tr') | | local tr = _table:tag('tr') |
| | | |
| for i, recipe in pairs(recipes) do | | for i, recipe in pairs(recipes) do |
| if i == 1 then | | if i == 1 then |
| local cell = tr:tag('td'):attr('rowspan', #valids[page]) | | local cell = tr:tag('td'):attr('rowspan', #valids[page]) |
|
| |
| if recipe[Rlib.sTypeArg]:find('Set') then | | if recipe[Rlib.sTypeArg]:find('Set') then |
| cell | | cell |
| :tag('div')
| | :tag('div') |
| :css{ | | :css{['text-align'] = 'center', ['width'] = '165px'} |
| ['text-align'] = 'center',
| | :wikitext('[[File:Furnishing Set ', page, ' Display.png|160x80px|alt=', page, '|link=', page, ']]<br>[[', page, ']]') |
| ['width'] = '165px'
| |
| }
| |
| :wikitext( | |
| '[[File:Furnishing Set ',
| |
| page,
| |
| ' Display.png|160x80px|alt=',
| |
| page,
| |
| '|link=',
| |
| page,
| |
| ']]<br>[[',
| |
| page,
| |
| ']]'
| |
| )
| |
| else | | else |
| cell:wikitext(Item({ | | cell:wikitext(Item({ page, x = recipe[Rlib.sYieldArg] })) |
| page,
| |
| x = recipe[Rlib.sYieldArg]
| |
| }))
| |
| end | | end |
| else | | else |
| tr = _table:tag('tr') | | tr = _table:tag('tr') |
| end | | end |
| | | tr:tag('td'):css{['text-align'] = 'center'}:wikitext('[[', recipe[Rlib.sTypeArg], ']]') |
| tr:tag('td') | | local ingredients = {} |
| :css{['text-align'] = 'center'}
| | for name in lib.gsplit(recipe['sort'], lib.ternary(recipe['sort']:find(Rlib.sSortDelim2), Rlib.sSortDelim2, Rlib.sSortDelim)) do |
| :wikitext('[[', recipe[Rlib.sTypeArg], ']]')
| | if (lib.isNotEmpty(name) and lib.isNotEmpty(recipe[name])) then |
| | | table.insert(ingredients, Item({ name, size = 20, x = recipe[name] })) |
| if showKitchenware then | |
| if isCookingRecipe(recipe) then
| |
| local kitchenware = renderCookingKitchenware(recipe)
| |
| tr:tag('td'):wikitext(table.concat(kitchenware, '<br>'))
| |
| else | |
| tr:tag('td'):wikitext('—') | |
| end | | end |
| end | | end |
|
| |
| local ingredients = renderRecipeIngredients(recipe)
| |
|
| |
| tr:tag('td'):wikitext(table.concat(ingredients, '<br>')) | | tr:tag('td'):wikitext(table.concat(ingredients, '<br>')) |
| end | | end |
| end | | end |
| | | -- mw.logObject(_table) --debug |
| return _table | | return _table |
| end | | end |
|
| |
|
| return p | | return p |