Diferencia entre revisiones de «Módulo:Crafting usage»

MinedNugget (discusión | contribs.)
Sin resumen de edición
Sin resumen de edición
 
(No se muestra una edición intermedia del mismo usuario)
Línea 1: Línea 1:
local p = {}
local p = {}
function p.dpl( f )
local titleText = mw.title.getCurrentTitle().text
local args = f:getParent().args
local grid = require( 'Module:Grid' )
local ingredients = args[1] and mw.text.split( args[1], ',' ) or { mw.title.getCurrentTitle().text }
local matchTypes = args.match and args.match:find( ',' ) and mw.text.split( args.match, ',' ) or args.match


local argList = {
local i18n = {
'ignoreusage', 'upcoming', 'name', 'ingredients', 'arggroups',
emptyCategory = 'Empty crafting usage',
1, 2, 3, 4, 5, 6, 7, 8, 9,
moduleCrafting = [[Module:Crafting]],
'A1', 'B1', 'C1', 'A2', 'B2', 'C2', 'A3', 'B3', 'C3',
moduleSlot = [[Module:Inventory slot]],
'Output', 'description'
moduleAliases = [[Module:Inventory slot/Aliases]],
}
moduleText = [[Module:Text]],
local anonToShaped = { 'A1', 'B1', 'C1', 'A2', 'B2', 'C2', 'A3', 'B3', 'C3' }
templateCrafting = 'Crafting',
local shapedToAnon = { A1 = 1, B1 = 2, C1 = 3, A2 = 4, B2 = 5, C2 = 5, A3 = 6, B3 = 7, C3 = 8 }
}
p.i18n = i18n
 
local text = require(i18n.moduleText)
local slot = require(i18n.moduleSlot)
local aliases = require(i18n.moduleAliases)
local crafting = require(i18n.moduleCrafting)
 
local function filterFrames(craftingArgs, pinnedItems)
-- Create a lookup table to easily determine if a string is a member of pinned items.
local pinnedItemsLookup = {}
for _, entry in pairs(pinnedItems) do
pinnedItemsLookup[entry] = true
end
local data = f:callParserFunction( '#dpl', {
-- Find any frames in this string that need to be pinned and pin them.
category = args.category or 'Recetas que usan ' .. table.concat( ingredients, '|Recetas que usan ' ),
local outputPinnedFrameCount = {}
nottitleregexp = args.ignore,
local shouldPinOutput = false
include = '{Crafting}:' .. table.concat( argList, ':' ),
local function pinFrames(inputString, restrictToMatching, isOutput)
mode = 'userformat',
if not inputString then return nil end
secseparators = '====',
isOutput = isOutput or false
multisecseparators = '===='
} )
local pinFrames = {} -- Only frames that are pinned
local pinnedFrameCount = 0
-- Comment this next line out if you're not using aliases
local pinnedFramesIndex = {}
local aliases = mw.loadData( 'Module:Grid/Aliases' )
local allFrames = {} -- All input frames
local allFrameCount = 0
function matchPattern( ingredient, ingredientNum )
local frameCount = 0 -- Count how many expanded frames we are in our iteration. Used for restricting output frames to match input frames
local matchType = matchTypes
if type( matchType ) == 'table' then
matchType = matchTypes[ingredientNum]
end
local pattern
local escaped = ingredient:gsub( '([%(%)])', '%%%1' )
if matchType == 'start' then
pattern = '[;:%]]%s*' .. escaped
elseif matchType == 'end' then
pattern = escaped .. '%s*[,;%[]'
elseif matchType == 'any' then
pattern = escaped
else
pattern = '[;:%]]%s*' .. escaped .. '%s*[,;%[]'
end
return pattern
for frameStr in string.gmatch(inputString, "[^;]+") do
end
local shouldPin = false
local out = {}
frameStr = mw.text.trim(frameStr)
local showDesciption
local originalFrameString = frameStr
local templates = {}
local frameObj = slot.makeFrame(frameStr, '')
for template in mw.text.gsplit( data, '====' ) do
local name = (frameObj.name:gsub("[{}]", "")) -- If this name is a subframe, remove the braces for alias testing.
-- If ignoreusage is empty
local subframe = (frameObj.name:find("[{}]") ~= nil) -- If the current frame is a subframe, don't advance the frame count for aliases
if template:find( '^%s*|' ) then
local expandedAlias = aliases[name]
local tArgs = {}
local isAlias = (expandedAlias and expandedAlias[1]) ~= nil
local i = 0
local isDesiredItem = (pinnedItemsLookup[name] ~= nil) -- If this item is present in our list of items to pin
-- Extract the arguments from the DPL query
for tArg in mw.text.gsplit( template, '\n|' ) do
-- Even if we have an exactly matching alias input, we have to step through each frame to log it as pinnable.
i = i + 1
if isAlias == true and isDesiredItem then
if tArg ~= '' then
shouldPin = true -- Set this frame as adding to the list of pinned frames
local key = argList[i]
if not subframe then
tArgs[key] = tArg
for _,_ in pairs(expandedAlias) do
frameCount = frameCount + 1
pinnedFramesIndex[frameCount] = true
end
else
frameCount = frameCount + 1
pinnedFramesIndex[frameCount] = true
end
end
elseif isAlias == false or subframe == true then
frameCount = frameCount + 1
end
end
local craftingArgs = {
if isAlias -- If this is an alias
tArgs[1] or tArgs.A1 or '', tArgs[2] or tArgs.B1 or '', tArgs[3] or tArgs.C1 or '',
and not isDesiredItem -- and we don't want to keep the alias as is
tArgs[4] or tArgs.A2 or '', tArgs[5] or tArgs.B2 or '', tArgs[6] or tArgs.C2 or '',
and (not isOutput or (isOutput and restrictToMatching)) then -- and we are either not output, or we are output that needs to be restricted.
tArgs[7] or tArgs.A3 or '', tArgs[8] or tArgs.B3 or '', tArgs[9] or tArgs.C3 or '',
local replacementString = {}
Output = tArgs.Output
for _,candidate in pairs(expandedAlias) do -- Find all pinned items that are part of this alias
}
if not subframe then -- Subframes only actually count as one frame
frameCount = frameCount + 1
local expandedFrames = {}
local hasIngredient
local argsWithIngredient = {}
local argGroups = {}
for i, v in pairs( craftingArgs ) do
if v ~= '' then
if aliases then
expandedFrames[i] = {}
local expandedFrame = {}
for frame in mw.text.gsplit( v, '%s*;%s*' ) do
local parts = grid.getParts( frame )
local alias = aliases[parts.name]
if alias then
local expandedAlias = grid.expandAlias( parts, alias ):gsub( '%s*([%[%]:,;])%s*', '%1' )
expandedFrames[i][frame] = expandedAlias:gsub( '([%(%)])', '%%%1' )
table.insert( expandedFrame, expandedAlias )
else
table.insert( expandedFrame, frame )
end
end
v = table.concat( expandedFrame, ';' )
craftingArgs[i] = v
end
end
if i ~= 'Output' then
 
local delimitedFrames = ';' .. v .. ';'
candidate = candidate.name or candidate -- Sometimes alias returns a table of tables
for ingredientNum, ingredient in pairs( ingredients ) do
if pinnedItemsLookup[candidate] or (restrictToMatching and outputPinnedFrameCount[frameCount]) then
if delimitedFrames:find( matchPattern( ingredient, ingredientNum ) ) then
local candidateOut = candidate
if not v:find( ';' ) then
if frameObj.num then
hasIngredient = 'static'
candidateOut = candidateOut..','..frameObj.num
elseif not hasIngredient then
hasIngredient = 'animated'
end
argsWithIngredient[i] = true
end
end
end
table.insert(replacementString, candidateOut)
pinnedFramesIndex[frameCount] = true -- When we find a good entry, store the number for use by Output
end
end
end
if not tArgs.arggroups and hasIngredient ~= 'static' then
if #replacementString > 0 then -- If this alias doesn't have any pinned items in it, leave it alone.
local _, frameCount = v:gsub( ';', '' )
if name:find("^" .. slot.i18n.prefixes.any .. " ") then
if frameCount > 0 then
-- Simple in place randomization
frameCount = frameCount + 1
for i = #replacementString, 2, -1 do
local group = argGroups[frameCount]
local j = math.random(i)
if not group then
replacementString[i], replacementString[j] = replacementString[j], replacementString[i]
group = { args = {} }
argGroups[frameCount] = group
end
group.count = frameCount
group.args[i] = true
end
end
else -- If we modify anything that isn't an "Any" alias, force pin the output.
shouldPinOutput = true
end
end
replacementString = table.concat(replacementString, ';')
-- The gsub is to put a % in front of every non alphanumeric character in name, this escapes the name so special characters don't act as a pattern match.
local findString = '('..name:gsub("(%W)", "%%%1")..',?%d*)' -- Also capture the quantity, since the replacement string has the quantity attached.
frameStr = frameStr:gsub(findString, replacementString, 1) -- Replace the alias name in the frame with the expanded and filtered string
shouldPin = true -- If we match with an expanded alias then we have to pin it
end
end
end
end
if hasIngredient then
-- Save modified frame to proper location
if tArgs.description then
if isDesiredItem or shouldPin or (restrictToMatching and outputPinnedFrameCount[frameCount]) then
showDescription = true
table.insert(pinFrames, frameStr)
pinnedFrameCount = pinnedFrameCount + frameCount
-- Don't pin an alias, unless its an exact match
if not isOutput and (not isAlias and isDesiredItem) then
pinnedFramesIndex[frameCount] = true -- When we find a good entry, store the number for use by Output
end
end
end
if hasIngredient == 'animated' then
table.insert(allFrames, frameStr)
if tArgs.arggroups then
allFrameCount = allFrameCount + frameCount
for argGroup in mw.text.gsplit( tArgs.arggroups, '%s*;%s*' ) do
end
local group = {}
if pinnedFrameCount > 0 then
local _, frameCount
if pinnedFrameCount < allFrameCount then
for arg in mw.text.gsplit( argGroup, '%s*,%s*' ) do
shouldPinOutput = true
if not tArgs[1] then
end
arg = shapedToAnon[arg]
for k,v in pairs(pinnedFramesIndex) do
end
outputPinnedFrameCount[k] = v
if not frameCount then
end
_, frameCount = craftingArgs[arg]:gsub( ';', '' )
return table.concat(pinFrames, ';')
end
else
group[arg] = true
return table.concat(allFrames, ';')
end
end
table.insert( argGroups, { count = frameCount + 1, args = group } )
end
end
-- for A1, A2, A3, B1, B2, etc
for _, arg in ipairs(crafting.cArgVals) do
craftingArgs[arg] = pinFrames(craftingArgs[arg])
end
craftingArgs.Output = pinFrames(craftingArgs.Output, shouldPinOutput, true)
return craftingArgs
end
 
--[[The main body, which retrieves the data, and returns the relevant
crafting templates, sorted alphabetically
--]]
function p.dpl(f)
local args = f
if f == mw.getCurrentFrame() then
args = f:getParent().args
else
f = mw.getCurrentFrame()
end
local startingIngredients = args[1] and text.split(args[1], '%s*,%s*') or {titleText}
local seen = {}
local ingredients = {}
-- Loop through all defined ingredients, and expand any aliases.
for _,entry in pairs(startingIngredients) do
if not seen[entry] then
table.insert(ingredients, entry)
seen[entry] = true
local expandedAlias = aliases[entry]
 
if expandedAlias then
for _,a in pairs(expandedAlias) do
if not seen[a] then
table.insert(ingredients, (a.name or a))
seen[a] = true
end
end
end
for _, groupData in pairs( argGroups ) do
end
local frameCount = groupData.count
end
local group = groupData.args
end
local requiredFrames = {}
local requiredFramesCount = 0
local showDescription
for arg in pairs( group ) do
local templates = {}
if argsWithIngredient[arg] then
local frames = craftingArgs[arg]
local queryStrings = {}
local frameNum = 0
-- SMW can query up to 15 conditions at once, so group ingredients into 15
for frame in mw.text.gsplit( frames, '%s*;%s*' ) do
local count = 1
frameNum = frameNum + 1
while count <= #ingredients do
if not requiredFrames[frameNum] then
queryStrings[math.floor(count/15)+1] = table.concat(ingredients, '||', count, math.min(#ingredients, count + 14))
local delimitedFrame = ';' .. frame .. ';'
count = count + 15
for ingredientNum, ingredient in pairs( ingredients ) do
end
if delimitedFrame:find( matchPattern( ingredient, ingredientNum ) ) then
requiredFrames[frameNum] = true
local seen = {}
requiredFramesCount = requiredFramesCount + 1
for _,str in ipairs(queryStrings) do
end
local query = {
end
'[[Crafting ingredient::'..str..']]',
end
'?Crafting JSON',
end
'?-Has subobject#-=Source page',
end
limit = 500
end
}
local smwdata = mw.smw.ask(query)
-- Not all frames will be used
if requiredFramesCount > 0 and requiredFramesCount < frameCount then
if smwdata then
for arg in pairs( group ) do
for _,v in ipairs(smwdata) do
local frames = craftingArgs[arg]
if v['Source page'] ~= titleText then -- Do not display results that came from the same page we are operating on, as they will be outdated.
local newFrames = {}
if type(v['Crafting JSON']) ~= "table" then --If a subobject name is not unique enough it will return as a table.
local frameNum = 0
if seen[v['Crafting JSON']] == nil then
for frame in mw.text.gsplit( frames, '%s*;%s*' ) do
seen[v['Crafting JSON']] = 1
frameNum = frameNum + 1
local tArgs = mw.text.jsonDecode(v['Crafting JSON'])
if requiredFrames[frameNum] then
tArgs['ignoreusage'] = '1' -- Always set ignore usage for crafting invocations that are usage.
table.insert( newFrames, frame )
if tArgs.description and tArgs.description ~= '' then
end
showDescription = '1'
end
newFrames = table.concat( newFrames, ';' )
-- If the whole expanded alias survived, collapse it again
if expandedFrames[arg] then
for frame, expandedAlias in pairs( expandedFrames[arg] ) do
--newFrames = 'blah' .. expandedAlias
newFrames = newFrames:gsub( expandedAlias, frame )
end
end
local tArg = arg
if arg ~= 'Output' and not tArgs[1] then
tArg = anonToShaped[arg]
end
tArgs[tArg] = newFrames
end
end
local newArgs = filterFrames(tArgs, startingIngredients)
-- Let Module:Crafting handle the name and ingredients columns
table.insert(templates,{args = newArgs, sortKey = newArgs.Output or newArgs.name})
tArgs.name = nil
tArgs.ingredients = nil
end
end
else
mw.log("ERROR: query returned table.")
mw.logObject(v['Crafting JSON'])
end
end
end
end
tArgs.nocat = '1'
table.insert( templates, tArgs )
end
end
end
end
end
end
if #templates == 0 then
return '[[Category:Como ingrediente vacío]]'
local templateCount = #templates
if templateCount == 0 then
if mw.title.getCurrentTitle().nsText == '' then
return f:expandTemplate{title='Translation category', args={i18n.emptyCategory, project='0'}}
end
return ''
end
end
templates[1].head = '1'
table.sort(templates, function(a, b)
templates[1].showname = '1'
if not a then return b end
if showDescription and args.showdesciption ~= '0' or args.showdesciption == '1' then
if not b then return a end
templates[1].showdescription = '1'
return a.sortKey < b.sortKey
end
end)
local initialArgs = templates[1].args
initialArgs.head = '1'
initialArgs.showname = '1'
initialArgs.showdescription = showDescription
if not args.continue then
if not args.continue then
templates[#templates].foot = '1'
templates[templateCount].args.foot = '1'
end
end
local crafting = require( 'Module:Crafting' )
local out = {}
local out = {}
for i, v in ipairs( templates ) do
for i, template in ipairs(templates) do
table.insert( out, crafting.table( v ) )
out[i] = crafting.table(template.args)
end
end
return table.concat(out, '\n')
return table.concat( out, '\n' )
end
end
return p
return p

Revisión actual - 15:49 15 dic 2024

local p = {} local titleText = mw.title.getCurrentTitle().text

local i18n = { emptyCategory = 'Empty crafting usage', moduleCrafting = Module:Crafting, moduleSlot = Module:Inventory slot, moduleAliases = Module:Inventory slot/Aliases, moduleText = Module:Text, templateCrafting = 'Crafting', } p.i18n = i18n

local text = require(i18n.moduleText) local slot = require(i18n.moduleSlot) local aliases = require(i18n.moduleAliases) local crafting = require(i18n.moduleCrafting)

local function filterFrames(craftingArgs, pinnedItems) -- Create a lookup table to easily determine if a string is a member of pinned items. local pinnedItemsLookup = {} for _, entry in pairs(pinnedItems) do pinnedItemsLookup[entry] = true end

-- Find any frames in this string that need to be pinned and pin them. local outputPinnedFrameCount = {} local shouldPinOutput = false local function pinFrames(inputString, restrictToMatching, isOutput) if not inputString then return nil end isOutput = isOutput or false

local pinFrames = {} -- Only frames that are pinned local pinnedFrameCount = 0 local pinnedFramesIndex = {} local allFrames = {} -- All input frames local allFrameCount = 0 local frameCount = 0 -- Count how many expanded frames we are in our iteration. Used for restricting output frames to match input frames

for frameStr in string.gmatch(inputString, "[^;]+") do local shouldPin = false frameStr = mw.text.trim(frameStr) local originalFrameString = frameStr local frameObj = slot.makeFrame(frameStr, ) local name = (frameObj.name:gsub("[{}]", "")) -- If this name is a subframe, remove the braces for alias testing. local subframe = (frameObj.name:find("[{}]") ~= nil) -- If the current frame is a subframe, don't advance the frame count for aliases local expandedAlias = aliases[name] local isAlias = (expandedAlias and expandedAlias[1]) ~= nil local isDesiredItem = (pinnedItemsLookup[name] ~= nil) -- If this item is present in our list of items to pin

-- Even if we have an exactly matching alias input, we have to step through each frame to log it as pinnable. if isAlias == true and isDesiredItem then shouldPin = true -- Set this frame as adding to the list of pinned frames if not subframe then for _,_ in pairs(expandedAlias) do frameCount = frameCount + 1 pinnedFramesIndex[frameCount] = true end else frameCount = frameCount + 1 pinnedFramesIndex[frameCount] = true end elseif isAlias == false or subframe == true then frameCount = frameCount + 1 end

if isAlias -- If this is an alias and not isDesiredItem -- and we don't want to keep the alias as is and (not isOutput or (isOutput and restrictToMatching)) then -- and we are either not output, or we are output that needs to be restricted. local replacementString = {} for _,candidate in pairs(expandedAlias) do -- Find all pinned items that are part of this alias if not subframe then -- Subframes only actually count as one frame frameCount = frameCount + 1 end

candidate = candidate.name or candidate -- Sometimes alias returns a table of tables if pinnedItemsLookup[candidate] or (restrictToMatching and outputPinnedFrameCount[frameCount]) then local candidateOut = candidate if frameObj.num then candidateOut = candidateOut..','..frameObj.num end table.insert(replacementString, candidateOut) pinnedFramesIndex[frameCount] = true -- When we find a good entry, store the number for use by Output end end if #replacementString > 0 then -- If this alias doesn't have any pinned items in it, leave it alone. if name:find("^" .. slot.i18n.prefixes.any .. " ") then -- Simple in place randomization for i = #replacementString, 2, -1 do local j = math.random(i) replacementString[i], replacementString[j] = replacementString[j], replacementString[i] end else -- If we modify anything that isn't an "Any" alias, force pin the output. shouldPinOutput = true end replacementString = table.concat(replacementString, ';') -- The gsub is to put a % in front of every non alphanumeric character in name, this escapes the name so special characters don't act as a pattern match. local findString = '('..name:gsub("(%W)", "%%%1")..',?%d*)' -- Also capture the quantity, since the replacement string has the quantity attached. frameStr = frameStr:gsub(findString, replacementString, 1) -- Replace the alias name in the frame with the expanded and filtered string shouldPin = true -- If we match with an expanded alias then we have to pin it end end

-- Save modified frame to proper location if isDesiredItem or shouldPin or (restrictToMatching and outputPinnedFrameCount[frameCount]) then table.insert(pinFrames, frameStr) pinnedFrameCount = pinnedFrameCount + frameCount -- Don't pin an alias, unless its an exact match if not isOutput and (not isAlias and isDesiredItem) then pinnedFramesIndex[frameCount] = true -- When we find a good entry, store the number for use by Output end end table.insert(allFrames, frameStr) allFrameCount = allFrameCount + frameCount end if pinnedFrameCount > 0 then if pinnedFrameCount < allFrameCount then shouldPinOutput = true end for k,v in pairs(pinnedFramesIndex) do outputPinnedFrameCount[k] = v end return table.concat(pinFrames, ';') else return table.concat(allFrames, ';') end end

-- for A1, A2, A3, B1, B2, etc for _, arg in ipairs(crafting.cArgVals) do craftingArgs[arg] = pinFrames(craftingArgs[arg]) end craftingArgs.Output = pinFrames(craftingArgs.Output, shouldPinOutput, true)

return craftingArgs end

--[[The main body, which retrieves the data, and returns the relevant crafting templates, sorted alphabetically --]] function p.dpl(f) local args = f if f == mw.getCurrentFrame() then args = f:getParent().args else f = mw.getCurrentFrame() end

local startingIngredients = args[1] and text.split(args[1], '%s*,%s*') or {titleText} local seen = {} local ingredients = {}

-- Loop through all defined ingredients, and expand any aliases. for _,entry in pairs(startingIngredients) do if not seen[entry] then table.insert(ingredients, entry) seen[entry] = true local expandedAlias = aliases[entry]

if expandedAlias then for _,a in pairs(expandedAlias) do if not seen[a] then table.insert(ingredients, (a.name or a)) seen[a] = true end end end end end

local showDescription local templates = {}

local queryStrings = {} -- SMW can query up to 15 conditions at once, so group ingredients into 15 local count = 1 while count <= #ingredients do queryStrings[math.floor(count/15)+1] = table.concat(ingredients, '||', count, math.min(#ingredients, count + 14)) count = count + 15 end

local seen = {} for _,str in ipairs(queryStrings) do local query = { 'Crafting ingredient::'..str..'', '?Crafting JSON', '?-Has subobject#-=Source page', limit = 500 } local smwdata = mw.smw.ask(query)

if smwdata then for _,v in ipairs(smwdata) do if v['Source page'] ~= titleText then -- Do not display results that came from the same page we are operating on, as they will be outdated. if type(v['Crafting JSON']) ~= "table" then --If a subobject name is not unique enough it will return as a table. if seen[v['Crafting JSON']] == nil then seen[v['Crafting JSON']] = 1 local tArgs = mw.text.jsonDecode(v['Crafting JSON']) tArgs['ignoreusage'] = '1' -- Always set ignore usage for crafting invocations that are usage. if tArgs.description and tArgs.description ~= then showDescription = '1' end local newArgs = filterFrames(tArgs, startingIngredients) table.insert(templates,{args = newArgs, sortKey = newArgs.Output or newArgs.name}) end else mw.log("ERROR: query returned table.") mw.logObject(v['Crafting JSON']) end end end end end

local templateCount = #templates if templateCount == 0 then if mw.title.getCurrentTitle().nsText == then return f:expandTemplate{title='Translation category', args={i18n.emptyCategory, project='0'}} end return end

table.sort(templates, function(a, b) if not a then return b end if not b then return a end return a.sortKey < b.sortKey end)

local initialArgs = templates[1].args initialArgs.head = '1' initialArgs.showname = '1' initialArgs.showdescription = showDescription if not args.continue then templates[templateCount].args.foot = '1' end

local out = {} for i, template in ipairs(templates) do out[i] = crafting.table(template.args) end return table.concat(out, '\n') end

return p