Diferencia entre revisiones de «Módulo:Crafting usage»
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 = {} | ||
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 | local allFrames = {} -- All input frames | ||
local allFrameCount = 0 | |||
function | local frameCount = 0 -- Count how many expanded frames we are in our iteration. Used for restricting output frames to match input frames | ||
if | |||
local | |||
local | |||
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 | local isAlias = (expandedAlias and expandedAlias[1]) ~= nil | ||
local | 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 | end | ||
elseif isAlias == false or subframe == true then | |||
frameCount = frameCount + 1 | |||
end | 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 | |||
if | |||
end | 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 | 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 #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 | local j = math.random(i) | ||
replacementString[i], replacementString[j] = replacementString[j], replacementString[i] | |||
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 | -- Save modified frame to proper location | ||
if | 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 | ||
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 | |||
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 | end | ||
local newArgs = filterFrames(tArgs, startingIngredients) | |||
table.insert(templates,{args = newArgs, sortKey = newArgs.Output or newArgs.name}) | |||
end | end | ||
else | |||
mw.log("ERROR: query returned table.") | |||
mw.logObject(v['Crafting JSON']) | |||
end | end | ||
end | end | ||
end | end | ||
end | end | ||
end | end | ||
return ' | 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 | table.sort(templates, function(a, b) | ||
templates[1]. | 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 | if not args.continue then | ||
templates[ | templates[templateCount].args.foot = '1' | ||
end | end | ||
local out = {} | local out = {} | ||
for i, | for i, template in ipairs(templates) do | ||
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