本站文本内容除另有声明外,转载时均必须注明出处,并遵守CC BY-NC-SA 3.0协议。(转载须知)
本站是中文Minecraft Wiki的镜像站,与Mojang Studios、Weird Gloop没有从属关系。(免责声明)
全站通知:
模块:Breaking table
刷
历
编
跳到导航
跳到搜索
local p = {}
local Autovalue = require( [[Module:Autovalue]] )
local Autolink = require( [[Module:Autolink]] )
local Sprite = require( [[Module:Sprite]] )
local Reverselink = require( [[Module:Reverselink]] )
local ProcessArgs = require( [[Module:ProcessArgs]] )
local function ComputeBreakingTime( hardness, breakingRate, rateFactor )
return math.max(
1,
math.ceil( ( hardness * 30 / rateFactor ) / breakingRate )
) / 20
end
local localStrings = {
['ref_group'] = '挖掘',
['category_missing_hardness'] = '缺失硬度',
['table_data_description'] = '挖掘时间',
['note_breakingtime'] = '根据受影响因素修正前的基础挖掘速度计算出的挖掘时间,单位:秒。更多信息详见[[挖掘#挖掘速度]]。',
['note_unbreakable'] = '硬度为负数的方块不可通过挖掘来破坏。',
['header_breakingtime'] = '[[挖掘]]时间',
['header_blocks'] = '方块',
['header_hardness'] = '硬度',
['header_breaking_tool'] = '合适挖掘工具',
['header_breakingtime_notool'] = '<abbr title="包含空手或使用错误种类的工具">徒手</abbr>',
['header_breakingtime_sword'] = '剑',
['header_breakingtime_shears'] = '剪刀',
['header_breakingtime_tier_wooden'] = '木质',
['header_breakingtime_tier_stone'] = '石质',
['header_breakingtime_tier_iron'] = '铁质',
['header_breakingtime_tier_diamond'] = '钻石质',
['header_breakingtime_tier_netherite'] = '下界合金质',
['header_breakingtime_tier_golden'] = '金质',
}
local breakingTimeHeader
local function getBreakingTimeHeader()
if breakingTimeHeader == nil then
breakingTimeHeader = localStrings.header_breakingtime .. mw.getCurrentFrame():callParserFunction {
name = '#tag:ref',
args = {
localStrings.note_breakingtime,
name = 'breakingtimenote',
group = localStrings.ref_group
}
}
end
return breakingTimeHeader
end
local function ParseLineHeaderToTableCell( lineName, horizontal, onlyFlag, SwordJEandSwordBESame, toolsColspan )
if lineName == 'blockname' then
if horizontal then
return '! '..localStrings.header_blocks
else
return '! rowspan = "2" | '..localStrings.header_blocks
end
elseif lineName == 'hardness' then
if horizontal then
return '! '..localStrings.header_hardness
else
return '! rowspan = "2" | '..localStrings.header_hardness
end
elseif lineName == 'breaking_tool' then
if horizontal then
return '! '..localStrings.header_breaking_tool
else
return '! rowspan = "2" | '..localStrings.header_breaking_tool
end
elseif lineName == 'notool' then
return table.concat({
'! colspan="'..toolsColspan..'" | '..getBreakingTimeHeader(),
'|-',
'! '..localStrings.header_breakingtime_notool
}, '\n')
elseif lineName == 'swordJE' then
if onlyFlag == 'je' or SwordJEandSwordBESame then
return '! '..localStrings.header_breakingtime_sword
else
return '! '..localStrings.header_breakingtime_sword..mw.getCurrentFrame():expandTemplate { title = 'Only', args = { 'je' } }
end
elseif lineName == 'swordBE' then
if onlyFlag == 'be' or SwordJEandSwordBESame then
return '! '..localStrings.header_breakingtime_sword
else
return '! '..localStrings.header_breakingtime_sword..mw.getCurrentFrame():expandTemplate { title = 'Only', args = { 'be' } }
end
elseif lineName == 'shears' then
return '! '..localStrings.header_breakingtime_shears
elseif lineName == 'tierWooden' then
return '! '..localStrings.header_breakingtime_tier_wooden
elseif lineName == 'tierStone' then
return '! '..localStrings.header_breakingtime_tier_stone
elseif lineName == 'tierIron' then
return '! '..localStrings.header_breakingtime_tier_iron
elseif lineName == 'tierDiamond' then
return '! '..localStrings.header_breakingtime_tier_diamond
elseif lineName == 'tierNetherite' then
return '! '..localStrings.header_breakingtime_tier_netherite
elseif lineName == 'tierGolden' then
return '! '..localStrings.header_breakingtime_tier_golden
else
return '! ??????'
end
end
local function ParseLineToTableCell(lineName, breakingDataEntry, onlyFlag)
if lineName == 'blockname' then
local blocklinks = {}
local categories = {}
for i, blockId in ipairs( breakingDataEntry.blockIds ) do
local only = ''
local blocklink, spriteCat = Sprite.link({
Reverselink.xlink(blockId.blockId),
['data'] = 'BlockSprite'
})
if blockId.hasJE and not blockId.hasBE then
if onlyFlag ~= 'je' then
only = mw.getCurrentFrame():expandTemplate { title = 'Only', args = { 'je' } }
end
elseif blockId.hasBE and not blockId.hasJE then
if onlyFlag ~= 'be' then
only = mw.getCurrentFrame():expandTemplate { title = 'Only', args = { 'be' } }
end
end
table.insert( blocklinks, blocklink..only )
table.insert( categories, spriteCat )
end
return '! '..table.concat(blocklinks, '<br>')..table.concat(categories)
end
if lineName == 'breaking_tool' then
if type(breakingDataEntry.breaking_tool) == 'table' then
local valueTable = {}
local frame = mw.getCurrentFrame()
for k, v in pairs( breakingDataEntry.breaking_tool ) do
table.insert(valueTable, frame:expandTemplate { title = 'BreakingToolTooltip', args = { v } })
end
if #valueTable <= 0 then
return '| '..frame:expandTemplate { title = 'BreakingToolTooltip', args = { 'none' } }
end
return '| '..table.concat(valueTable)
end
return '| ?'
end
if lineName == 'hardness' then
local note = ''
local attrible = ''
if type(breakingDataEntry.hardness) == 'number' and breakingDataEntry.hardness < 0 then
attrible = 'data-sort-value="999999999" | '
local frame = mw.getCurrentFrame()
if frame:callParserFunction( '#dplvar', 'unbreakable note' ) == '' then
note = frame:callParserFunction { name = '#tag:ref', args = { localStrings.note_unbreakable, name = 'unbreakable', group = localStrings.ref_group } }
frame:callParserFunction( '#dplvar:set', 'unbreakable note', '1' )
else
note = frame:callParserFunction { name = '#tag:ref', args = { '', name = 'unbreakable', group = localStrings.ref_group } }
end
end
return '| '..attrible..breakingDataEntry.hardness..note
end
if lineName == 'notool'
or lineName == 'tierWooden'
or lineName == 'tierStone'
or lineName == 'tierIron'
or lineName == 'tierDiamond'
or lineName == 'tierNetherite'
or lineName == 'tierGolden'
or lineName == 'swordJE'
or lineName == 'swordBE'
or lineName == 'shears'
then
if breakingDataEntry[lineName] then
local att = ''
if breakingDataEntry[lineName] == '∞' then
att = 'data-sort-value="999999999" '
end
local choose
if breakingDataEntry.reds[lineName] then
choose = 'class="tc-no" |' --mw.getCurrentFrame():expandTemplate{ title = 'Table Choice', args = { 'no', '' } }
else
choose = 'class="tc-yes" |' --mw.getCurrentFrame():expandTemplate{ title = 'Table Choice', args = { 'yes', '' } }
end
return '| '..att..choose..' '..breakingDataEntry[lineName]
else
return '| —'
end
else
return '| ?????????'
end
end
local function GenerateDataLines(breakingData, onlyFlag)
local SwordJEandNotoolSame = true
local SwordBEandNotoolSame = true
local SwordJEandSwordBESame = true
local hasSwrodJE = false
local hasSwrodBE = false
local hasShears = false
local hasTier = false
for i, breakingDataEntry in ipairs( breakingData ) do
if breakingDataEntry.tierDiamond then
hasTier = true
end
if breakingDataEntry.swordJE then
hasSwrodJE = true
end
if breakingDataEntry.swordBE then
hasSwrodBE = true
end
if breakingDataEntry.shears then
hasShears = true
end
if breakingDataEntry.swordJE ~= nil and breakingDataEntry.swordJE ~= breakingDataEntry.notool then
SwordJEandNotoolSame = false
end
if breakingDataEntry.swordBE ~= nil and breakingDataEntry.swordBE ~= breakingDataEntry.notool then
SwordBEandNotoolSame = false
end
if breakingDataEntry.swordJE ~= breakingDataEntry.swordBE then
SwordJEandSwordBESame = false
end
end
local lines = {}
table.insert(lines, 'blockname')
table.insert(lines, 'hardness')
table.insert(lines, 'breaking_tool')
table.insert(lines, 'notool')
if hasTier then
table.insert(lines, 'tierWooden')
table.insert(lines, 'tierStone')
table.insert(lines, 'tierIron')
table.insert(lines, 'tierDiamond')
table.insert(lines, 'tierNetherite')
table.insert(lines, 'tierGolden')
end
if hasSwrodJE and not SwordJEandNotoolSame then
table.insert(lines, 'swordJE')
end
if hasSwrodBE and not SwordBEandNotoolSame and not SwordJEandSwordBESame then
table.insert(lines, 'swordBE')
end
if hasShears then
table.insert(lines, 'shears')
end
local dataLines = {}
for i, breakingDataEntry in ipairs( breakingData ) do
local dataLine = {}
for i, line in ipairs( lines ) do
dataLine[line]=ParseLineToTableCell(line, breakingDataEntry, onlyFlag)
end
table.insert(dataLines, dataLine)
end
return lines, dataLines, SwordJEandSwordBESame
end
local function BreakingDataToVerticalTable(breakingData, onlyFlag)
local lines, dataLines, SwordJEandSwordBESame = GenerateDataLines(breakingData, onlyFlag)
local finalTableStrings = {}
table.insert(finalTableStrings, ' {| class="wikitable sortable" style="text-align:center;" data-sort-type="number" data-description="'..localStrings.table_data_description..'"')
for i, line in ipairs( lines ) do
table.insert(finalTableStrings, ParseLineHeaderToTableCell(line, false, onlyFlag, SwordJEandSwordBESame, #lines + -3) )
end
table.insert(finalTableStrings, '|-')
for i, dataLine in ipairs( dataLines ) do
for i, line in ipairs( lines ) do
table.insert(finalTableStrings, dataLine[line] )
end
table.insert(finalTableStrings, '|-')
end
table.insert(finalTableStrings, '|}')
table.insert(finalTableStrings, mw.getCurrentFrame():callParserFunction { name = '#tag:references', args = { '', group = localStrings.ref_group } })
mw.getCurrentFrame():callParserFunction( '#dplvar:set', 'unbreakable note', '' )
return table.concat(finalTableStrings, '\n')
end
local function BreakingDataToHorizontalTable(breakingData, onlyFlag)
local lines, dataLines, SwordJEandSwordBESame = GenerateDataLines(breakingData, onlyFlag)
local finalTableStrings = {}
table.insert(finalTableStrings, ' {| class="wikitable" style="text-align:center;" data-description="'..localStrings.table_data_description..'"')
for i, line in ipairs( lines ) do
table.insert(finalTableStrings, ParseLineHeaderToTableCell(line, true, onlyFlag, SwordJEandSwordBESame, #dataLines + 1) )
for i, dataLine in ipairs( dataLines ) do
table.insert(finalTableStrings, dataLine[line] )
end
table.insert(finalTableStrings, '|-')
end
table.insert(finalTableStrings, '|}')
table.insert(finalTableStrings, mw.getCurrentFrame():callParserFunction { name = '#tag:references', args = { '', group = localStrings.ref_group } })
mw.getCurrentFrame():callParserFunction( '#dplvar:set', 'unbreakable note', '' )
return table.concat(finalTableStrings, '\n')
end
local ToolType = {
['pickaxe'] = 'pickaxe',
['wooden pickaxe'] = 'pickaxe',
['stone pickaxe'] = 'pickaxe',
['iron pickaxe'] = 'pickaxe',
['diamond pickaxe'] = 'pickaxe',
['netherite pickaxe'] = 'pickaxe',
['shovel'] = 'shovel',
['wooden shovel'] = 'shovel',
['axe'] = 'axe',
['wooden axe'] = 'axe',
['hoe'] = 'hoe',
['sword'] = 'sword',
['wooden sword'] = 'sword',
['shears'] = 'shears',
['shears required'] = 'shears',
['null required'] = 'none',
['none'] = 'none',
}
local ToolTier = {
['pickaxe'] = 0,
['wooden pickaxe'] = 1,
['stone pickaxe'] = 2,
['iron pickaxe'] = 3,
['diamond pickaxe'] = 4,
['netherite pickaxe'] = 5,
['shovel'] = 0,
['wooden shovel'] = 1,
['axe'] = 0,
['wooden axe'] = 1,
['hoe'] = 0,
['sword'] = 0,
['wooden sword'] = 0.5,
['shears'] = 0,
['shears required'] = 0.5,
['null required'] = 1,
['none'] = 0,
}
local function ParseBreakingDatas(breakingStats)
local hardness = breakingStats.hardness
local breaking_tool = breakingStats.breaking_tool
local swordRateJE = breakingStats.swordRateJE
local swordRateBE = breakingStats.swordRateBE
local shearsRate = breakingStats.shearsRate
local result = {}
result.reds = {}
local broken = false
result.hardness = hardness
result.breaking_tool = breaking_tool
if hardness == nil then
result.hardness = '?[[Category:'..localStrings.category_missing_hardness..']]'
broken = true
end
if breaking_tool == nil then
result.breaking_tool = {'?'}
broken = true
end
if broken then
return result
end
local tool = 'none'
local tier = 0
local hasShears = false
local hasSword = false
for i, tooltext in ipairs(breaking_tool) do
if ToolType[tooltext] == 'shears' then
hasShears = true
elseif ToolType[tooltext] == 'sword' then
hasSword = true
elseif ToolType[tooltext] ~= 'none' then
tool = ToolType[tooltext]
end
tier = ToolTier[tooltext]
end
if hardness < 0 then
result.notool = '∞'
result.reds.notool = true
return result
end
local notoolRatio = 1
local swordRatio = 1
local tierWoodenRatio = 1
local tierStoneRatio = 1
local tierIronRatio = 1
local tierDiamondRatio = 1
local tierNetheriteRatio = 1
local tierGoldenRatio = 1
if tier > 0 then
notoolRatio = 0.3
result.reds.notool = true
end
if tier > 0.5 then
swordRatio = 0.3
result.reds.swordJE = true
result.reds.swordBE = true
end
if tier > 1 then
tierWoodenRatio = 0.3
tierGoldenRatio = 0.3
result.reds.tierWooden = true
result.reds.tierGolden = true
end
if tier > 2 then
tierStoneRatio = 0.3
result.reds.tierStone = true
end
if tier > 3 then
tierIronRatio = 0.3
result.reds.tierIron = true
end
if tier > 4 then
tierDiamondRatio = 0.3
result.reds.tierDiamond = true
end
if tier > 5 then
tierNetheriteRatio = 0.3
result.reds.tierNetherite = true
end
result.notool = ComputeBreakingTime(hardness, 1, notoolRatio)
if tool ~= 'none' then
result.tierWooden = ComputeBreakingTime(hardness, 2, tierWoodenRatio)
result.tierStone = ComputeBreakingTime(hardness, 4, tierStoneRatio)
result.tierIron = ComputeBreakingTime(hardness, 6, tierIronRatio)
result.tierDiamond = ComputeBreakingTime(hardness, 8, tierDiamondRatio)
result.tierNetherite = ComputeBreakingTime(hardness, 9, tierNetheriteRatio)
result.tierGolden = ComputeBreakingTime(hardness, 12, tierGoldenRatio)
end
if swordRateJE then
result.swordJE = ComputeBreakingTime(hardness, swordRateJE, swordRatio)
end
if swordRateBE then
result.swordBE = ComputeBreakingTime(hardness, swordRateBE, swordRatio)
end
if hasShears then
result.shears = ComputeBreakingTime(hardness, shearsRate, 1)
end
return result
end
local function tableHasValue (targetTable, targetValue)
for index, value in ipairs(targetTable) do
if value == targetValue then
return true
end
end
return false
end
local function IsSameTool(tools1, tools2)
if tools1 == nil and tools2 == nil then
return true
end
if tools1 == nil or tools2 == nil then
return false
end
for i, tool1 in pairs( tools1 ) do
if not tableHasValue(tools2, tool1) then
return false
end
end
for i, tool2 in pairs( tools2 ) do
if not tableHasValue(tools1, tool2) then
return false
end
end
return true
end
local function GenBreakingStats(blockId, onlyBE)
return {
['hardness'] = Autovalue.getRawValue(blockId, 'hardness', onlyBE),
['breaking_tool'] = Autovalue.getRawValue(blockId, 'breaking tool', onlyBE),
}
end
local function IsSameBreakingStats(breakingStats1, breakingStats2)
return (
breakingStats1.hardness == breakingStats2.hardness
and breakingStats1.swordRateJE == breakingStats2.swordRateJE
and breakingStats1.swordRateBE == breakingStats2.swordRateBE
and breakingStats1.shearsRate == breakingStats2.shearsRate
and IsSameTool(breakingStats1.breaking_tool, breakingStats2.breaking_tool) )
end
local function GetSwordRate(blockId, breakingStats, onlyBE)
if blockId == "蜘蛛网" then
return 15
elseif blockId == "竹子" then
return 1000000000
elseif onlyBE then
return 1.5
elseif breakingStats and breakingStats.breaking_tool and (tableHasValue (breakingStats.breaking_tool, 'sword') or tableHasValue (breakingStats.breaking_tool, 'wooden sword')) then
return 1.5
else
return 1
end
end
local function GetShearsRate(blockId, breakingStats, onlyBE)
if blockId == "蜘蛛网" then
return 15
elseif string.find(blockId,"树叶$") then
return 15
elseif blockId == "羊毛" then
return 5
elseif breakingStats and breakingStats.breaking_tool and (tableHasValue (breakingStats.breaking_tool, 'shears') or tableHasValue (breakingStats.breaking_tool, 'shears requird')) then
return 2
else
return 1
end
end
local ExclusiveBE = {
'平滑石砖',
'物品展示框',
'荧光物品展示框',
'下界反应核',
'发光的黑曜石',
'切石机(MATTIS)',
'reserved6',
'客户端请求占位符方块',
'数据更新方块',
'未知',
'未知方块',
'隐形基岩',
'允许方块',
'拒绝方块',
'边界',
'相机',
'紫色火把',
'蓝色火把',
'绿色火把',
'红色火把',
'彩色火把',
'化合物创建器',
'元素',
'元素构造器',
'强化玻璃',
'染色强化玻璃',
'强化玻璃板',
'染色强化玻璃板',
'实验台',
'材料分解器',
'化学仪器',
'加热块',
'水下火把',
'水下TNT',
'黑板',
}
local function BreakingDataBuilder(blockIds, onlyFlag, enableGrouping)
local groupedBlockData = {}
for i, blockId in ipairs( blockIds ) do
local breakingStatsList = {}
local localOnlyFlag = onlyFlag
if localOnlyFlag ~= 'je' and localOnlyFlag ~= 'be' then
if tableHasValue (ExclusiveBE, blockId) then
localOnlyFlag = 'be'
end
end
if localOnlyFlag == 'je' then
local breakingStats = GenBreakingStats(blockId, false)
breakingStats.hasJE = true
breakingStats.shearsRate = GetShearsRate(blockId, breakingStats)
breakingStats.swordRateJE = GetSwordRate(blockId, breakingStats, false)
table.insert(breakingStatsList, breakingStats)
elseif localOnlyFlag == 'be' then
local breakingStats = GenBreakingStats(blockId, true)
breakingStats.hasBE = true
breakingStats.shearsRate = GetShearsRate(blockId, breakingStats)
breakingStats.swordRateBE = GetSwordRate(blockId, breakingStats, true)
table.insert(breakingStatsList, breakingStats)
else
local breakingStatsJE = GenBreakingStats(blockId, false)
local breakingStatsBE = GenBreakingStats(blockId, true)
breakingStatsJE.shearsRate = GetShearsRate(blockId, breakingStatsJE)
breakingStatsBE.shearsRate = GetShearsRate(blockId, breakingStatsBE)
if IsSameBreakingStats(breakingStatsJE, breakingStatsBE) then
breakingStatsJE.hasJE = true
breakingStatsJE.hasBE = true
breakingStatsJE.swordRateJE = GetSwordRate(blockId, breakingStatsJE, false)
breakingStatsJE.swordRateBE = GetSwordRate(blockId, breakingStatsJE, true)
table.insert(breakingStatsList, breakingStatsJE)
else
breakingStatsJE.hasJE = true
breakingStatsBE.hasBE = true
breakingStatsJE.swordRateJE = GetSwordRate(blockId, breakingStatsJE, false)
breakingStatsBE.swordRateBE = GetSwordRate(blockId, breakingStatsBE, true)
table.insert(breakingStatsList, breakingStatsJE)
table.insert(breakingStatsList, breakingStatsBE)
end
end
for i, breakingStats in ipairs( breakingStatsList ) do
local mergeTargetNotFound = true
if enableGrouping then
for i, blockDataGroup in ipairs( groupedBlockData ) do
if IsSameBreakingStats(blockDataGroup.breakingStats, breakingStats) then
table.insert(blockDataGroup.blockIds, {
['blockId'] = blockId,
['hasJE'] = breakingStats.hasJE,
['hasBE'] = breakingStats.hasBE,
} )
mergeTargetNotFound = false
break
end
end
end
if mergeTargetNotFound then
table.insert(groupedBlockData, {
['blockIds'] = { {
['blockId'] = blockId,
['hasJE'] = breakingStats.hasJE,
['hasBE'] = breakingStats.hasBE,
} },
['breakingStats'] = breakingStats,
})
end
end
end
return groupedBlockData
end
local function ParseGroupedBlockDatasToTableEntries (groupedBlockData)
local tableEntries = {}
for i, blockDataGroup in ipairs( groupedBlockData ) do
local tableEntry = ParseBreakingDatas(blockDataGroup.breakingStats)
tableEntry.blockIds = blockDataGroup.blockIds
table.insert(tableEntries, tableEntry)
end
return tableEntries
end
local function StripSpaceAndLineAtBothEnds(str)
return (string.gsub(str, '^[%s\n]*(.-)[%s\n]*$', '%1'))
end
local function StringToArray (str, splitter)
local rawSplit = mw.text.split(str, splitter)
local results = {}
for i,value in ipairs( rawSplit ) do
local stripped = StripSpaceAndLineAtBothEnds( value )
if stripped ~= '' then
table.insert(results, stripped)
end
end
return results
end
function p.genBreakingTable(f)
local args = f
local frame = mw.getCurrentFrame()
if f == frame then
args = require('Module:ProcessArgs').merge(true)
end
local targetNames = {}
local argTargetNames
if args[1] then
argTargetNames = mw.text.trim(args[1])
else
local titleName = mw.text.trim(mw.title.getCurrentTitle().rootText)
if tableHasValue (ExclusiveBE, titleName)
or require( [[Module:Block id values]] )[titleName]
or require( [[Module:Autovalue/groups]] )[titleName]
then
argTargetNames = titleName
end
end
if argTargetNames then
targetNames = Autovalue.expandGroups(StringToArray(argTargetNames, ','))
end
local argOnly = StripSpaceAndLineAtBothEnds( args.only or '' )
if argOnly == 'java' then argOnly = 'je' end
if argOnly == 'bedrock' then argOnly = 'be' end
if args.vertical then
return BreakingDataToVerticalTable(
ParseGroupedBlockDatasToTableEntries(
BreakingDataBuilder(
targetNames,
argOnly,
false
)
),
argOnly
)
else
return BreakingDataToHorizontalTable(
ParseGroupedBlockDatasToTableEntries(
BreakingDataBuilder(
targetNames,
argOnly,
true
)
),
argOnly
)
end
end
return p