模块:MaterialReaction

来自Noita Wiki
跳到导航 跳到搜索
Template-info.png 模块文档

一般来讲,本模块只应用于模板中,是用于加载材料反应的模块,如果你是想简单的加载材料反应模板,请查看{{MaterialReactions}}


local p = {}
local IDtoTable = {}--材料ID转数据表
for _,v in pairs(mw.loadData("Module:DataQuery/Materials")["Materials"])do --初始化id对应表
	IDtoTable[v.herd] = v
end

--- 移除前后空格,换行
local function strip(s)
    if s == nil then
        return ''
    end
    return s:gsub("^%s+", ""):gsub("%s+$", ""):gsub("%c","")
end
---split
---根据指定的分隔符分隔, 返回table, 内容会删除前后空格
---@param s string
---@param delim string
local function split(s, delim)
    if string.find(s, delim) == nil then
        return {
            strip(s)
        }
    end
    local result = {}
    for ct in string.gmatch(s, '([^' .. delim .. ']+)') do
        ct = strip(ct)
        result[#result + 1] = ct
    end
    return result
end

local function TagGetName(str)--删除tag的前后空格和[]以及非tag部分
	str = strip(str)
	local pos1 = 1
	local count = 0
	while(string.byte(str,pos1,pos1) ~= 91)do--91为[
		pos1 = pos1 + 1
	end
	local pos2 = pos1+1
	while(string.byte(str,pos2,pos2) ~= 93)do--93为]
		pos2 = pos2 + 1
	end
	return string.sub(str,pos1+1,pos2-1)
end

local function TagGetNameAndLastText(str)--第一个返回值为[tag],第二个为后续内容
	str = strip(str)
	local pos1 = 1
	local count = 0
	while(string.byte(str,pos1,pos1) ~= 91)do--91为[
		pos1 = pos1 + 1
	end
	local pos2 = pos1+1
	while(string.byte(str,pos2,pos2) ~= 93)do--93为]
		pos2 = pos2 + 1
	end
	local str1 = string.sub(str,pos1,pos2)
	local str2 = string.sub(str,pos2+1)
	return str1,str2
end

function p.group(frame)--按组加载函数
	local args = frame
    if frame == mw.getCurrentFrame() then
        args = require('Module:ProcessArgs').merge(true)
    else
        frame = mw.getCurrentFrame()
    end

    local query = {}
    for k, v in pairs(args) do--k为字符串
        if string.sub(k, 0, 2) == 'q?' then--如果开头两个字符为q?
            query[string.sub(k, 3)] = v--那么将截取之后的字符串作为一个key值,赋值为v(参数)
        end
    end
	local resultCache = {}
    if query.group ~= nil then
    	local raw_data = mw.loadData("Module:DataQuery/Materials").Materials_Link[strip(query.group):lower()]
    	for _,v in pairs(raw_data)do
    		table.insert(resultCache,frame:expandTemplate{title = "MaterialReactions/load", args = {id = v.herd}})
    	end
    	return table.concat(resultCache)
    else
    	return {}
    end
end

function p.allMatTable(frame)--生成所有材料的反应表格,非常好玩()
	local args = frame
    if frame == mw.getCurrentFrame() then
        args = require('Module:ProcessArgs').merge(true)
    else
        frame = mw.getCurrentFrame()
    end

	local resultCache = {}
    local raw_data = mw.loadData("Module:DataQuery/Materials")
    for _,v in pairs(raw_data)do
   		table.insert(resultCache,frame:expandTemplate{title = "MaterialReactions/load", args = {id = v.herd}})
   	end
   	return table.concat(resultCache)
end

function p.main(frame)--已完成
	local args = frame
    if frame == mw.getCurrentFrame() then
        args = require('Module:ProcessArgs').merge(true)
    else
        frame = mw.getCurrentFrame()
    end

    local query = {}
    for k, v in pairs(args) do--k为字符串
        if string.sub(k, 0, 2) == 'q?' then--如果开头两个字符为q?
            query[string.sub(k, 3)] = v--那么将截取之后的字符串作为一个key值,赋值为v(参数)
        end
    end

    local result = p.queryData(query)
    if result[1] == nil then
        return frame:preprocess(args.default or '')
    end

    local tbl = {}
    for _, row in ipairs(result) do
        table.insert(tbl, frame:expandTemplate { title = args.template, args = row })
    end
    local intro = frame:preprocess(args.intro or '')
    local outro = frame:preprocess(args.outro or '')
    return intro .. table.concat(tbl, args.delimiter or '') .. outro
end

local function EqTag(tagList,tag)--判断tag是否相等
	for _,v in pairs(tagList)do --注意,这里传进来的已经加过[]这两个了
		if v == tag then
			return true
		end
	end
	return false
end

local function FormatName(str, id, tagList, frame)--str为输入的参数,其中可能是tag,也有可能是材料id
	local inputArgs = {nil, nil}--输入到模板的参数
	if string.byte(str,1,1) == 91 then --91为[ 此处判断是否为tag
		--是tag
		local str1,str2 = TagGetNameAndLastText(str)
		local isTagMaterial = EqTag(tagList,str1)--判断是不是这个材料参与的
		if isTagMaterial and str2 == "" then--如果是,且没有后缀
			inputArgs[1] = "[["..IDtoTable[id].link.."##|"..IDtoTable[id].name.."]]"
			inputArgs[2] = IDtoTable[id].herd.."<br>"..str1
		elseif isTagMaterial and str2 ~= "" and IDtoTable[IDtoTable[id].herd..str2] ~= nil then --如果是,且后缀拼接的材料存在
			local tempName = IDtoTable[id].herd..str2
			inputArgs[1] = "[["..IDtoTable[tempName].link.."##|"..IDtoTable[tempName].name.."]]"
			inputArgs[2] = IDtoTable[tempName].herd.."<br>"..str
		else
			return "[[:Category:带有"..TagGetName(str).."标签的材料|"..str1.."]]"..str2 --注意,这个是特殊情况,不用展开模板
		end
	else
		--不是tag
		inputArgs[1] = "[["..IDtoTable[str].link.."##|"..IDtoTable[str].name.."]]"
		inputArgs[2] = IDtoTable[str].herd
	end
	return frame:expandTemplate{title = "MaterialReactions/hover", args = inputArgs}
end

local function FormatTag(str, frame)--str为输入的参数,其中可能是tag,也有可能是材料id
	if string.byte(str,1,1) == 91 then --91为[ 此处判断是否为tag
		--是tag
		local str1,str2 = TagGetNameAndLastText(str)
		return "[[:Category:带有"..TagGetName(str).."标签的材料|"..str1.."]]"..str2
	end
	--不是tag
	local inputArgs = {nil, nil}--输入到模板的参数
	inputArgs[1] = "[["..IDtoTable[str].link.."##|"..IDtoTable[str].name.."]]"
	inputArgs[2] = IDtoTable[str].herd
	return frame:expandTemplate{title = "MaterialReactions/hover", args = inputArgs}
end

function p.queryData(query)--query为参数表
	local frame = mw.getCurrentFrame()
	local raw_data = mw.loadData("Module:MaterialReaction/PreData")--注意,这个表是只读的,要深拷贝
	local result = {}
	if query.id ~= nil then
		local id = strip(query.id)
		query.id = nil
		local tagsList = split(IDtoTable[id].tags,",")
		local tempData = {}
		if IDtoTable[id].onfire == "1" then--始终燃烧材料始终带有fire标签
			table.insert(tagsList, "fire");
		end
		if IDtoTable[id].liquidSand == "0" and IDtoTable[id].cellType == "liquid" and id ~= "mimic_liquid" then--液体材料特判
    		table.insert(tagsList,"any_liquid")
    	end
		for i=1,#tagsList do --转换字符串为指定格式
			tagsList[i] = "["..tagsList[i].."]"
			if raw_data[tagsList[i]] ~= nil then
				table.insert(tempData, raw_data[tagsList[i]])
			end
		end
		if raw_data[id] ~= nil then
			table.insert(tempData, raw_data[id])
		end

		for h=1,#tempData do
			local thisData = tempData[h]
			for i,_ in pairs(thisData[1]) do --四个数组等长的,所以只需要知道一个数组的长度即可遍历
				local inputCache = {nil, nil, nil}--缓存区
				local outputCache = {nil, nil, nil}
				for j,_ in pairs(thisData[1][i]) do--遍历输入材料并解析
					inputCache[j] = FormatName(thisData[1][i][j],id,tagsList,frame)
				end
				for j,_ in pairs(thisData[2][i]) do
					outputCache[j] = FormatName(thisData[2][i][j],id,tagsList,frame)
				end
				table.insert(result,{output = table.concat(outputCache," + "),input = table.concat(inputCache," + "),rate=thisData[3][i],fast=thisData[4][i]})--直接合理初始化表
			end
		end
		
	elseif query.tag ~= nil then
		local tag = strip(query.tag)
		query.tag = nil
		tag = "["..tag.."]"
		local thisData = raw_data[tag]
		if thisData ~= nil then
			for i,_ in pairs(thisData[1]) do --四个数组等长的,所以只需要知道一个数组的长度即可遍历
				local inputCache = {nil, nil, nil}--缓存区
				local outputCache = {nil, nil, nil}
				for j,_ in pairs(thisData[1][i]) do--遍历输入材料并解析
					inputCache[j] = FormatTag(thisData[1][i][j],frame)
				end
				for j,_ in pairs(thisData[2][i]) do
					outputCache[j] = FormatTag(thisData[2][i][j],frame)
				end
				table.insert(result,{output = table.concat(outputCache," + "),input = table.concat(inputCache," + "),rate=thisData[3][i],fast=thisData[4][i]})--直接合理初始化表
			end
		end
	end
	return result
end


function p.all(frame)--已完成
	local args = frame
    if frame == mw.getCurrentFrame() then
        args = require('Module:ProcessArgs').merge(true)
    else
        frame = mw.getCurrentFrame()
    end

    local result = {}
    local raw_data = require("Module:MaterialReaction/data")

	for _, v1 in pairs(raw_data.children) do       --遍历元素
		--获得材料输入和输出
		local tempInputT = { nil, nil, nil } --nil用于占位,提供一个合适的数组大小,避免hash操作带来的性能损失
		local tempOutputT = { nil, nil, nil } --nil用于占位,提供一个合适的数组大小,避免hash操作带来的性能损失

		local i = 1                            --用于遍历元素的属性
		local cmpStr = "input_cell" .. tostring(i)
		while (v1.attr[cmpStr] ~= nil) do      --解析输入材料
			tempInputT[i] = FormatTag(v1.attr[cmpStr],frame)
			i = i + 1
			cmpStr = "input_cell" .. tostring(i)
		end
		i = 1
		local cmpStr = "output_cell" .. tostring(i)
		while (v1.attr[cmpStr] ~= nil) do --解析输出材料
			tempOutputT[i] = FormatTag(v1.attr[cmpStr],frame)
			i = i + 1
			cmpStr = "output_cell" .. tostring(i)
		end
		local Reactionfast = "否"
		if v1.attr.fast_reaction ~= nil then                 --解析反应是否快速
	    	if v1.attr.fast_reaction == "1" then
           		Reactionfast = "是"
			end
		end
		table.insert(result,{output = table.concat(tempOutputT," + "),input = table.concat(tempInputT," + "),rate=v1.attr.probability,fast=Reactionfast})
	end
    if result[1] == nil then
        return frame:preprocess(args.default or '')
    end

    local tbl = {}
    for _, row in ipairs(result) do
        tbl[#tbl + 1] = frame:expandTemplate { title = args.template, args = row }
    end
    local intro = frame:preprocess(args.intro or '')
    local outro = frame:preprocess(args.outro or '')
    return intro .. table.concat(tbl, args.delimiter or '') .. outro
end

return p