Module:Item Usage: Difference between revisions
fandom-table -> wikitable |
No edit summary |
||
| 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, in case you later use: | |||
-- |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 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 | |||
if #kitchenware == 0 then | |||
return nil | |||
end | |||
return '<b>Kitchenware:</b> ' .. table.concat(kitchenware, ' / ') | |||
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 | |||
local kitchenware = renderCookingKitchenware(recipe) | |||
if isNotEmpty(kitchenware) then | |||
table.insert(ingredients, kitchenware) | |||
end | |||
return ingredients | |||
end | |||
local function renderRecipeIngredients(recipe) | |||
if isCookingRecipe(recipe) then | |||
return renderCookingIngredients(recipe) | |||
end | |||
return renderStandardIngredients(recipe) | |||
end | |||
-------------------------------------------------------------------------------- | |||
-- Main | |||
-------------------------------------------------------------------------------- | |||
function p.main(frame) | function p.main(frame) | ||
| Line 10: | Line 329: | ||
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 | |||
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 | if recipeUsesItem(call, item) then | ||
valids[page] = valids[page] or {} | |||
table.insert(valids[page], call) | |||
count = count + 1 | |||
end | end | ||
end | end | ||
end | end | ||
if craftType == 'Furnishing Set' then | if craftType == 'Furnishing Set' then | ||
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') | 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' | |||
) | |||
else | else | ||
out:wikitext('There ', lib.ternary(count > 1,'are', 'is'), ' <b>', tostring(count), '</b> use', lib.ternary(count > 1, 's', ''), ' for [[', item , ']]:\n') | out:wikitext( | ||
'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 46: | Line 391: | ||
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 52: | Line 398: | ||
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('wikitable article-table sortable') | ||
-- | -- 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') | ||
tr:tag('th'):wikitext(craftType == 'Furnishing Set' and 'Components' or 'Recipe') | tr:tag('th'):wikitext(craftType == 'Furnishing Set' and 'Components' or 'Recipe') | ||
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') | |||
:css{['text-align'] = 'center', ['width'] = '165px'} | :css{ | ||
:wikitext('[[File:Furnishing Set ', page, ' Display.png|160x80px|alt=', page, '|link=', page, ']]<br>[[', page, ']]') | ['text-align'] = 'center', | ||
['width'] = '165px' | |||
} | |||
:wikitext( | |||
'[[File:Furnishing Set ', | |||
page, | |||
' Display.png|160x80px|alt=', | |||
page, | |||
'|link=', | |||
page, | |||
']]<br>[[', | |||
page, | |||
']]' | |||
) | |||
else | else | ||
cell:wikitext(Item({ page, x = recipe[Rlib.sYieldArg] })) | cell:wikitext(Item({ | ||
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], ']]') | |||
local ingredients = | tr:tag('td') | ||
:css{['text-align'] = 'center'} | |||
:wikitext('[[', recipe[Rlib.sTypeArg], ']]') | |||
local ingredients = renderRecipeIngredients(recipe) | |||
tr:tag('td'):wikitext(table.concat(ingredients, '<br>')) | tr:tag('td'):wikitext(table.concat(ingredients, '<br>')) | ||
end | end | ||
end | end | ||
return _table | return _table | ||
end | end | ||
return p | return p | ||