Module:Sandbox/LootChest

local getArgs = require('Module:Arguments').getArgs local config = require('Module:Sandbox/LootChest/config') local cov = config['json']['cov'] local sprite, alink if not(config['customize']['itemLink'] and config['customize']['struLink']) then sprite = require('Module:Sprite').link end if config['customize']['noUseAutoLink'] == true then alink = function(a) return a end else alink = require('Module:Autolink').invlink end

local p = {}

local function makeInvokeFunc(funcName) return function (frame) local args = getArgs(frame) return p[funcName](args) end end

function struLink(name) -- 输入结构的ID，返回最后结果.

local text if cov['structure']['text'][name] then text = cov['structure']['text'][name] else text = name end

local id = '' if cov['structure']['sprite-id'][name] then id = cov['structure']['sprite-id'][name] end

local dataType if cov['structure']['sprite-data-type'][name] then dataType = cov['structure']['sprite-data-type'][name] else dataType = cov['structure']['sprite-data-type']['default'] end

local link = 'none' if text:find('%|') then link = text:match('%[%[(.*)%|') text = text:match('%|(.*)%]%]') end

if config['debug']['showId'] then return (sprite({['data'] = dataType, ['id'] = id, ['link'] = link, ['text'] = text}) .. '('..name..')') else return sprite({['data'] = dataType, ['id'] = id, ['link'] = link, ['text'] = text}) end end

function ref(NsId, enName, functions) -- 输入物品的命名空间ID和itemLink最后的显示结果，对齐检索cov.json并添加注释.

local ref = "" local getRef = function(text, name) return mw.getCurrentFrame:callParserFunction('#tag:ref', {text, ['name'] = name}) end

if cov['note']['assign'][NsId] then ref = ref..getRef(cov['note']['assign'][NsId], NsId) end

local funcRefList = cov['note']['functions']

if functions and funcRefList then for _, func in ipairs(functions) do               if funcRefList[func['function']] then if funcRefList[func['function']][tonumber(func['value']) or func['value']] then ref = ref..getRef(funcRefList[func['function']][tonumber(func['value']) or func['value']],                       func['function'] .. ':'..funcRefList[func['function']][tonumber(func['value']) or func['value']]) end end end end

if ref == "" then return enName else return enName..ref end end

function itemLink(NsId, functions) -- 输入物品的命名空间ID，返回最终的显示结果.

local enName, id, link, text, dataType enName = NsId:gsub('_', ' ')

--- 如果在cov.json中存在转换规则，则进行转换，否则直接将命名空间ID作为英文名输入sprite local itemCov if cov['item']['cov'][NsId] then itemCov = cov['item']['cov'][NsId] if itemCov['name'] then enName = itemCov['name'] end if itemCov['id'] then id = itemCov['id'] end if itemCov['link'] then link = itemCov['link'] end if itemCov['text'] then text = itemCov['text'] end end

--- 如果存在标注，在输出的物品名中添加前缀 local Er, Sd, dataNum local funcCov if functions then for _, func in ipairs(functions) do           if cov['item']['cov'][NsId] and itemCov['functions'] and itemCov['functions'][func['function']] and itemCov['functions'][func['function']][tonumber(func['value']) or func['value']] then funcCov = itemCov['functions'][func['function']][tonumber(func['value']) or func['value']] if funcCov['name'] then enName = funcCov['name'] end if funcCov['id'] then id = funcCov['id'] end if funcCov['link'] then link = funcCov['link'] end if funcCov['text'] then text = funcCov['text'] end end if not(config['customize']['noUseAutoLink']) then text = text or alink(enName):gsub('.*%|', '') if func['function'] == 'enchant_randomly' or func['function'] == 'enchant_with_levels' then Er = true end if func['function'] == 'set_damage' then Sd = true end end if func['function'] == 'set_data' then dataNum = func['value'] end end end if not(config['customize']['noUseAutoLink']) then if Er then text = config['mark']['enchanted'] .. text end if Sd then text = config['mark']['set_damage'] .. text end end Er, Sd = nil, nil

if cov['item']['sprite-data-type'][NsId] then dataType = cov['item']['sprite-data-type'][NsId] else dataType = cov['item']['sprite-data-type']['default'] end

enName = sprite({['data'] = dataType, [1] = enName, ['id'] = id, ['link'] = link, ['text'] = text})

if config['debug']['showId'] then if dataNum then return ref(NsId, enName..' ('..NsId..':'..dataNum..') ', functions) else return ref(NsId, enName..' ('..NsId..') ', functions) end else return ref(NsId, enName, functions) end

end

function chanceCount(weightProportion, rolls) -- 概率计算函数

if type(rolls) == "table" then local fp = 1 - weightProportion--failureProbability local sum = 0 for i = rolls[1], rolls[2] do           sum = sum + math.pow(fp, i)        end return string.format("%.4f", 1 - (sum / (rolls[2] - rolls[1] + 1))) else return string.format("%.4f", 1 - math.pow((1 - weightProportion), rolls)) end end

function judge(condition, a, b)   if condition then return a else return b end end

function getData(lootTable) -- 从JSON中获取数据，返回一个查询的函数.

--通过函数闭包使JSON文件不被刷新. return function(name, stru, poolNum, itemNum) --利用表结构和匿名函数实现switch. local switch = { ["value"] = function if not(lootTable[stru]['pools'][poolNum]['entries'][itemNum]['type'] == "minecraft:item"               or lootTable[stru]['pools'][poolNum]['entries'][itemNum]['type'] == "item") or not(lootTable[stru]['pools'][poolNum]['entries'][itemNum]['functions']) or not(lootTable[stru]['pools'][poolNum]['entries'][itemNum]['functions'][1]['count']) then return 1 end

if type(lootTable[stru]['pools'][poolNum]['entries'][itemNum]['functions'][1]['count']) == 'table' then return tostring(lootTable[stru]['pools'][poolNum]['entries'][itemNum]['functions'][1]['count']['min']) .. '-'..tostring(lootTable[stru]['pools'][poolNum]['entries'][itemNum]['functions'][1]['count']['max']) else return lootTable[stru]['pools'][poolNum]['entries'][itemNum]['functions'][1]['count'] end

end, ["averageValue"] = function if not(lootTable[stru]['pools'][poolNum]['entries'][itemNum]['type'] == "minecraft:item"           or lootTable[stru]['pools'][poolNum]['entries'][itemNum]['type'] == "item") or not(lootTable[stru]['pools'][poolNum]['entries'][itemNum]['functions']) or not(lootTable[stru]['pools'][poolNum]['entries'][itemNum]['functions'][1]['count']) then return 1 end

if type(lootTable[stru]['pools'][poolNum]['entries'][itemNum]['functions'][1]['count']) == 'table' then return (lootTable[stru]['pools'][poolNum]['entries'][itemNum]['functions'][1]['count']['min'] + lootTable[stru]['pools'][poolNum]['entries'][itemNum]['functions'][1]['count']['max']) / 2 else return lootTable[stru]['pools'][poolNum]['entries'][itemNum]['functions'][1]['count'] end end, ["weight"] = function return lootTable[stru]['pools'][poolNum]['entries'][itemNum]['weight'] end, ["name"] = function if not(lootTable[stru]['pools'][poolNum]['entries'][itemNum]['type'] == "minecraft:item" or lootTable[stru]['pools'][poolNum]['entries'][itemNum]['type'] == "item") then return "nothing" end

return (lootTable[stru]['pools'][poolNum]['entries'][itemNum]['name']:gsub('minecraft:', '')) end, --计算用的堆叠数 ["rolls"] = function if type(lootTable[stru]['pools'][poolNum]['rolls']) == "table" then return { lootTable[stru]['pools'][poolNum]['rolls']['min'], lootTable[stru]['pools'][poolNum]['rolls']['max']} else return lootTable[stru]['pools'][poolNum]['rolls'] end end, --显示用的堆叠数 ["rollsOut"] = function if type(lootTable[stru]['pools'][poolNum]['rolls']) == "table" then return (lootTable[stru]['pools'][poolNum]['rolls']['min'] .. '-'..lootTable[stru]['pools'][poolNum]['rolls']['max']) .. 'x'       else return lootTable[stru]['pools'][poolNum]['rolls'] end end, ['functions'] = function local functions = lootTable[stru]['pools'][poolNum]['entries'][itemNum]['functions'] local result = {} local covSingle if functions == nil then return nil end for _, func in ipairs(functions) do           func['function'] = func['function']:gsub('minecraft:', '') covSingle = config['function'][func['function']] if covSingle then if covSingle[2] and type(func[covSingle[1]]) == 'table' then if covSingle[3] then table.insert(                           result,                            {['function'] = func['function'],                            ['value'] = tostring(func[covSingle[1]][covSingle[2]]) .. '-'..tostring(func[covSingle[1]][covSingle[3]])}) else table.insert(                               result,                                {['function'] = func['function'],                                ['value'] = tostring(func[covSingle[1]][covSingle[2]])}) end else table.insert(                               result,                                {['function'] = func['function'],                                ['value'] = tostring(func[covSingle[1]])}) end end end

return result end, ["entries"] = function return lootTable[stru]['pools'][poolNum]['entries'] end, ["pools"] = function return lootTable[stru]['pools'] end, ["table"] = function return lootTable end

}

return switch[name](stru, poolNum, itemNum) end end

function dataParsing(args, edition, genre) -- 获取数据table，同时用于all模式和item模式.

local data = getData(config['json'][edition]) --此处data被赋予一个函数，作为数据查找函数.

local at, struList, listNum = nil, {}, 1 local poorsValue, stru, itemNum, fakeItemNum, poolsList local poorsWeight, rolls -- 预声明循环内变量，分别为函数体内使用，第一层for使用，第二层for使用

if genre == "all" then loopPrimer = data('table') else loopPrimer = args end

local stru for q, w in pairs(loopPrimer) do       --结构循环 itemNum, fakeItemNum = 1, 1 --伪物品序号，服务于第二个物品循环，用于重新遍历第一个循环的物品，计算其概率等信息. poolsList, poorsValue = {}, {}

if genre == "all" then stru = q else stru = w end

if data('table')[stru] ~= nil then

for o in ipairs(data('pools', stru)) do               --奖池循环

poorsWeight = 0 rolls = data('rolls', stru, o)

if type(rolls) == 'table' then poorsValue[o] = rolls[1] .. '-'..rolls[2] else poorsValue[o] = rolls end

for n in ipairs(data('entries', stru, o)) do                   --物品循环 poolsList[itemNum] = {} poolsList[itemNum]['name'] = data('name', stru, o, n)                   poolsList[itemNum]['functions'] = data('functions', stru, o, n)                    poolsList[itemNum]['value'] = data('value', stru, o, n)                    poolsList[itemNum]['pools'] = o

if data('weight', stru, o, n) then poolsList[itemNum]['weight'] = data('weight', stru, o, n)                   else poolsList[itemNum]['weight'] = 1 end

poolsList[itemNum]['averageValue'] = data('averageValue', stru, o, n)                   poorsWeight = poorsWeight + poolsList[itemNum]['weight'] itemNum = itemNum + 1 end --到这里为止，poolsList包含了一个奖池的全部信息，然后在下一个循环进行几率等内容的计算，之后在最外层进行排序.

for n in ipairs(data('entries', stru, o)) do                   --物品循环 poolsList[fakeItemNum]['weightProportion'] = tonumber(poolsList[fakeItemNum]['weight']) / poorsWeight poolsList[fakeItemNum]['weightProportionOut'] = ''..tostring(poolsList[fakeItemNum]['weight']) .. '/'..tostring(poorsWeight) .. ''                   poolsList[fakeItemNum]['chance'] = chanceCount(poolsList[fakeItemNum]['weightProportion'], rolls) poolsList[fakeItemNum]['chanceOut'] = tonumber(poolsList[fakeItemNum]['chance'] * 100) .. '%'                   poolsList[fakeItemNum]['itemNum'] = string.format("%.2f", poolsList[fakeItemNum]['averageValue'] * poolsList[fakeItemNum]['chance']) poolsList[fakeItemNum]['boxNum'] = string.format("%.1f", 1 / poolsList[fakeItemNum]['chance']) fakeItemNum = fakeItemNum + 1 end

table.sort(poolsList, function(a, b) return a['chance'] > b['chance'] end)

end struList[listNum] = {} struList[listNum]['name'] = stru struList[listNum]['value'] = poolsList struList[listNum]['poolsValue'] = poorsValue struList[listNum]['poolNum'] = #data('pools', stru) struList[listNum]['itemNum'] = itemNum - 1 listNum = listNum + 1 else struList[listNum] = {} struList[listNum]['poolNum'] = 0 struList[listNum]['itemNum'] = 0 listNum = listNum + 1 end

end

table.sort(struList, function(a, b) return a['itemNum'] > b['itemNum'] end)

return struList end

function getTableAll(data) --获取all函数的结果文本. local wikiTable, poolNum, wikiTablePart = , , {} local box = mw.html.create("div"):cssText('display:flex;flex-wrap:wrap;overflow:auto') local modifyTag = false

for i, k in ipairs(data) do       if k['poolNum'] ~= 0 then poolNum = k['poolNum'] --表头部分 wikiTable = '{| class="wikitable sortable jquery-tablesorter" style="'..config['style']['allTableStyle'] .. '"\n!colspan="' .. (poolNum * 2 + 4)

if config['customize']['struLink'] then wikiTable = wikiTable..'"|'..config['struLink'](k['name']) .. '\n|-\n'           else                wikiTable = wikiTable..'"|'..struLink(k['name']) .. '\n|-\n' end --此处

wikiTable = wikiTable.. '! rowspan=2 | ' .. config['header']['item'] .. '\n' .. '! colspan='..poolNum..' | ' .. config['header']['stack'] .. '\n' .. '! colspan='..poolNum..' | ' .. config['header']['weight'] .. '\n' .. '! rowspan=2 | ' .. config['header']['probability'] .. '\n' .. '! rowspan=2 | ' .. config['header']['itemNumber'] .. '\n' .. '! rowspan=2 | ' .. config['header']['boxNumber'] .. '\n' .. '|- \n'

--表中部分 for h = 1, 2 do               for y = 1, poolNum do                    wikiTable = wikiTable..'! '..config['header']['weightNoteH']..k['poolsValue'][y]..config['header']['weightNoteF']..k['poolsValue'][y] .. '× \n' end end

wikiTable = wikiTable..'|- \n'

for o, p in ipairs(data[i]['value']) do               --值循环 if config['customize']['itemLink'] then wikiTablePart[o] = '|'..config['itemLink'](p['name'], p['functions'], config) else wikiTablePart[o] = '|'..itemLink(p['name'], p['functions']) end

for m = 1, poolNum do                   if p['pools'] == m                        then wikiTablePart[o] = wikiTablePart[o] .. '||'..p['value'] else wikiTablePart[o] = wikiTablePart[o] .. '||' .. ' '                   end end

for m = 1, poolNum do                   if p['pools'] == m                        then wikiTablePart[o] = wikiTablePart[o] .. '||'..p['weightProportionOut'] else wikiTablePart[o] = wikiTablePart[o] .. '||' .. ' '                   end end

wikiTablePart[o] = wikiTablePart[o] .. '||'..p['chanceOut'] .. '||'..p['itemNum'] .. '||'..p['boxNum'] .. '\n|-\n' wikiTable = wikiTable..wikiTablePart[o] end wikiTable = wikiTable..'|}' box:wikitext(' \n'..wikiTable..'\n ') if not(modifyTag) then modifyTag = true end end end if not(modifyTag) then return '' else return tostring(box) end

end

function getDataItemAll(edition) local data = dataParsing({}, edition, 'all') local itemList, resultList = {}, {} local boxNum for struNum, struInf in pairs(data) do

for itemNum, itemInf in ipairs(struInf['value']) do

if itemList[itemInf['name']] == nil then itemList[itemInf['name']] = {['list'] = {}, ['name'] = itemInf['name']} end

itemInf['stru'] = struInf['name']

table.insert(itemList[itemInf['name']]['list'], itemInf)

end

end

for _, Inf in pairs(itemList) do       Inf['long'] = #Inf['list'] table.insert(resultList, Inf) end

return resultList end

function getDataItem(args, edition, genre) if genre == 'all' then return getDataItemAll(edition) end local itemList = {} local boxNum local data = dataParsing({}, edition, 'all') for argNum, name in ipairs(args) do       boxNum = 1 itemList[argNum] = {} itemList[argNum]['list'] = {} itemList[argNum]['name'] = name for struNum, struInf in pairs(data) do

for itemNum, itemInf in ipairs(struInf['value']) do

if itemInf['name'] == name then

if not(args[argNum..'function']) then itemList[argNum]['list'][boxNum] = itemInf itemList[argNum]['list'][boxNum]['stru'] = struInf['name'] boxNum = boxNum + 1 else for _, func in ipairs(itemInf['functions']) do                               if func['function'] == args[argNum..'function'] and func['value'] == args[argNum..'value'] then itemList[argNum]['list'][boxNum] = itemInf itemList[argNum]['list'][boxNum]['stru'] = struInf['name'] boxNum = boxNum + 1 end end

end

end

end table.sort(itemList[argNum]['list'], function(a, b) return struLink(a['stru']) > struLink(b['stru']) end)

end itemList[argNum]['long'] = #itemList[argNum]['list']

end

return itemList

end

function getTableItem(data) local box = mw.html.create("div"):cssText('display:flex;flex-wrap:wrap;overflow:auto')

local wikiTable = '{| class="wikitable sortable jquery-tablesorter" style="'..config['style']['itemTableStyle'] .. '\n' ..   '! ' .. config['header']['item'] .. '\n' ..    '! ' .. config['header']['source'] .. '\n' ..    '! ' .. config['header']['quantity'] .. '\n' ..    '! ' .. config['header']['probability'] .. '\n' ..    '! ' .. config['header']['boxNumber'] .. '\n' ..    '! ' .. config['header']['form'] .. '\n' ..    '|-\n'    local modifyTag = false

for itemNum, itemInf in ipairs(data) do       if itemInf['long'] > 0 then wikiTable = wikiTable..'| rowspan='..itemInf['long'] .. '|'..itemLink(itemInf['name']) .. '\n'

for boxNum, boxInf in ipairs(itemInf['list']) do               wikiTable = wikiTable .. '|' ..struLink(boxInf['stru']) .. '\n' .. '|' ..boxInf['value'] .. '\n' .. '|' ..boxInf['chanceOut'] .. '\n' .. '|' ..boxInf['boxNum'] .. '\n' .. '|' ..judge(boxInf['functions'] and boxInf['functions'][1],               itemLink(boxInf['name'], boxInf['functions']), config['header']['noForm']) .. '\n' .. '|-\n' end if not(modifyTag) then modifyTag = true end end end

wikiTable = wikiTable..'|}'

box:wikitext('\n'..wikiTable..'\n')

if not(modifyTag) then return '' else return tostring(box) end end

function getDataAll(args, edition, genre) return dataParsing(args, edition, genre) end

function result(args, getData, getTable) local genre if args['type'] == 'all' or args[1] == 'all' then genre = 'all' else genre = 'arg' end local cout = '' local dataJava, dataBedrock, dataJavaDev, dataBedrockBeta local dataJavaTable, dataBedrockTable, dataJavaDevTable, dataBedrockBetaTable dataJava = getData(args, 'java', genre) dataBedrock = getData(args, 'bedrock', genre) dataJavaTable = tostring(getTable(dataJava)) dataBedrockTable = tostring(getTable(dataBedrock))

if dataJavaTable == dataBedrockTable then cout = cout .. config['label']['javaAndBedrock'] .. '\n'..dataJavaTable else cout = cout .. config['label']['java'] .. '\n'..dataJavaTable .. '\n' .. config['label']['bedrock'] .. '\n'..dataBedrockTable end

if config['debug']['onlyJava'] or args['only'] == 'java' or dataBedrockTable == '' then cout = config['label']['java'] .. '\n' .. dataJavaTable end if config['debug']['onlyBedrock'] or args['only'] == 'bedrock' or dataJavaTable == '' then cout = config['label']['bedrock'] .. '\n' .. dataBedrockTable end

if config['json']['javaDev'] and args['only'] ~= 'bedrock' and config['switch']['javaDev'] then dataJavaDev = getData(args, 'javaDev', genre) dataJavaTable = tostring(getTable(dataJavaDev)) if dataJavaTable ~= dataJavaDevTable and dataJavaTable ~= '' then cout = cout .. config['label']['javaDev'] .. '\n'..dataJavaTable end end if config['json']['bedrockBeta'] and args['only'] ~= 'java' and config['switch']['bedrockBeta'] then dataBedrockBeta = getData(args, 'bedrockBeta', genre) dataBedrockBetaTable = tostring(getTable(dataBedrockBeta)) if dataBedrockTable ~= dataBedrockBetaTable and dataBedrockBetaTable ~= '' then cout = cout .. config['label']['bedrockBeta'] .. '\n'..dataBedrockBetaTable end end

return cout end

p.all = makeInvokeFunc('_all')

function p._all(args) return result(args, getDataAll, getTableAll) end

p.item = makeInvokeFunc('_item')

function p._item(args) return result(args, getDataItem, getTableItem) end

return p