Diferencia entre revisiones de «Módulo:Crafting usage»
Línea 1: | Línea 1: | ||
− | |||
local p = {} | local p = {} | ||
local titleText = mw.title.getCurrentTitle().text | local titleText = mw.title.getCurrentTitle().text |
Revisión actual del 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