Module:Breaking row

local p = {}

local breakingTimeHeader; local function getBreakingTimeHeader( f ) if breakingTimeHeader == nil then breakingTimeHeader = 'Breaking time' .. f:preprocess( ' ' ) end return breakingTimeHeader end

function p.row( f ) local args = require( Module:ProcessArgs ).norm local function getDplVar( var ) local val = f:callParserFunction( '#dplvar', 'breaking ' .. var ) if val == '' then val = false end return val end local dplVars = {} local function setDplVar( var, val ) table.insert( dplVars, 'breaking ' .. var ) table.insert( dplVars, val or '1' ) end local rows = {} local tableParts = {} local categories = {} local horizontal if args.horizontal or args[1]:match( ';' ) then horizontal = true end local showTool = true local showShears = true local showSword = true local header, sortable, simple if horizontal or not getDplVar( 'header' ) then if args.hidetool or horizontal and ( not args[2] or args[2]:lower == 'any' or args[2]:lower == 'none' ) then showTool = false setDplVar( 'hidetool' ) breakingTimeHeader = 'Breaking time' end if args.hideshears or horizontal and not args.shears then showShears = false setDplVar( 'hideshears' ) end if args.hidesword or horizontal and not args.sword then showSword = false setDplVar( 'hidesword' ) end sortable = not horizontal and args.sort if sortable then setDplVar( 'sortable' ) end simple = args.simple if simple and not horizontal then setDplVar( 'simple' ) end local tableClasses = { 'wikitable' } if sortable then table.insert( tableClasses, 'sortable' ) end table.insert( rows, ' {| class="' .. table.concat( tableClasses, ' ' ) .. '" style="text-align:center"' ) local sortType = '' if sortable then sortType = 'data-sort-type="number"' end local rowspan = '' if not horizontal then rowspan = 'rowspan="2" ' end header = { '! ' .. rowspan .. ' | Block' }		if not simple then table.insert( header, '! ' .. rowspan .. sortType .. ' | Hardness' ) if showTool then table.insert( header, '! ' .. rowspan .. ' | Tool' ) end end local toolColumns = {} if showTool then toolColumns = { 'Wooden', 'Stone', 'Iron', 'Diamond', 'Netherite', 'Golden'} end table.insert( toolColumns, 1, 'Default' ) if not simple then if showShears then table.insert( toolColumns, 'Shears' ) end if showSword then table.insert( toolColumns, 'Sword' ) end end if not horizontal then table.insert( header, '! colspan="' .. #toolColumns .. '" |' .. getBreakingTimeHeader( f ) ) table.insert( header, '|-' ) end for _, tool in ipairs( toolColumns ) do table.insert( header, '! ' .. sortType .. ' | ' .. tool ) end if not horizontal then header = table.concat( header, '\n' ) setDplVar( 'header', header ) end table.insert( tableParts, header ) else showTool = not getDplVar( 'hidetool' ) showShears = not getDplVar( 'hideshears' ) showSword = not getDplVar( 'hidesword' ) sortable = getDplVar( 'sortable' ) simple = getDplVar( 'simple' ) end local sprite = require( Module:Sprite ) local hardness = require( Module:Block value ).value local function fillCells( cellsTable, text, num ) for i = 1, num do			table.insert( cellsTable, text ) end end local materialGrade = { Any = 0, Wooden = 1, Wood = 1, Golden = 1, Stone = 2, Iron = 3, Diamond = 4, Netherite = 5, None = 6 }	local materialSpeed = { None = 1, Any = 1, Wooden = 2, Wood = 2, Stone = 4, Iron = 6, Diamond = 8, Netherite = 9, Golden = 12 }	local numberMaterials = 6 local function insertBlock( blockArgs ) local cells = {} local blocks = mw.text.split( blockArgs[1], '%s*,%s*' ) local hardnessVal = tonumber( hardness{ blocks[1], type = 'hardness' } ) if not hardnessVal then hardnessVal = '?' local title = mw.title.getCurrentTitle if title.namespace == 0 and not title.isSubpage then table.insert(categories, '') end end local unbreakable if hardnessVal == -1 or blockArgs.liquid then unbreakable = true end local blockSprites = {} local links = mw.text.split( blockArgs.link or '', '%s*,%s*' ) local ids = mw.text.split( blockArgs.sprite or '', '%s*,%s*' ) local items = mw.text.split( blockArgs.item or '', '%s*,%s*' ) for i, block in ipairs( blocks ) do			local link if not links[i] and links[1] ~= '' then link = links[1] elseif links[i] ~= '' then link = links[i] end local id			if not ids[i] and ids[1] ~= '' then id = ids[1] elseif ids[i] ~= '' then id = ids[i] end local blockText if args.textTrim then blockText = block:gsub( args.textTrim .. '$', '' ) else blockText = block end local blockSpriteArgs = { data = 'BlockSprite', block, text = blockText, link = link, id = id			} if items[i] == '1' or not items[i] and items[1] == '1' then blockSpriteArgs.data = 'ItemSprite' end local image, spriteCat = sprite.link( blockSpriteArgs ) table.insert( blockSprites, image ) table.insert( categories, spriteCat ) end table.insert( cells,			'! style="text-align:left" | ' .. table.concat( blockSprites, ' ' ) .. ( blockArgs.note or '' )		) local tool = mw.text.trim( simple and 'Tool' or blockArgs[2] or 'Any' ):gsub( '^%l', string.upper ) local material = mw.text.trim( simple and blockArgs[2] or blockArgs[3] or 'Any' ):gsub( '^%l', string.upper ) if tool == 'None' then material = tool end if not simple then local hardnessText = hardnessVal if hardnessVal == -1 then hardnessText = ( sortable and 'data-sort-value="999" | ' or '' ) .. '∞'			end table.insert( cells, '|' .. hardnessText ) if showTool then local toolCell = '—' if tool ~= 'Any' and tool ~= 'None' then if material == 'Wood' then material = 'Wooden' end local toolName = ( material ~= 'Any' and material .. ' ' or '' ) .. tool local image, spriteCat = sprite.sprite{ data = 'ItemSprite', ( material == 'Any' and 'Wooden ' or '' ) .. toolName, title = toolName, link = tool }					toolCell = ( sortable and 'data-sort-value="' .. toolName .. '" |' or '' ) .. image table.insert( categories, spriteCat ) end table.insert( cells, '|' .. toolCell ) end end local choices = {} local function getChoice( choice, text ) if not choices[choice] then choices[choice] = f:expandTemplate{ title = 'Table Choice', args = { choice, '' } } end return choices[choice] .. text end if hardnessVal == '?' then fillCells( cells, '|?', numberMaterials + 1 ) else local function processTime( num ) if num < 0.05 then		-- Blocks have a minimum breaking time of 1 game tick (0.05 seconds) num = 0.05 else					-- And they must be broken in multiples of 1 game tick (0.05 seconds) num = math.ceil( num * 20 ) / 20 end return num end if unbreakable then table.insert( cells, '| ' .. ( sortable and 'data-sort-value="999" ' or '' ) .. getChoice( 'no', '∞' ) ) if showTool then fillCells( cells, '|—', numberMaterials ) end else local drop = 'yes' local forceDrop = false if blockArgs.drop == '0' then drop = 'partial' elseif blockArgs.drop == '1' then forceDrop = 'yes' end local requiredLevel = unbreakable and 999 or materialGrade[material] local function insertMaterialCell( material ) local shouldDrop = drop if materialGrade[material] < requiredLevel then shouldDrop = 'no' end local breakTime = processTime( hardnessVal / materialSpeed[material] * ( shouldDrop == 'no' and 5 or 1.5 ) ) table.insert( cells, '|' .. getChoice( forceDrop or shouldDrop, breakTime ) ) end if not showTool or tool == 'Any' or tool == 'None' then insertMaterialCell( 'Any' ) if showTool then fillCells( cells, '|—', numberMaterials ) end else for _, material in ipairs{ 'Any', 'Wooden', 'Stone', 'Iron', 'Diamond', 'Netherite', 'Golden' } do						insertMaterialCell( material ) end end end if not simple and ( showShears or showSword ) then local tools = {} if showShears then table.insert( tools, 'Shears' ) end if showSword then table.insert( tools, 'Sword' ) end if hardnessVal == '?' then fillCells( cells, '|?', #tools ) else local toolSpeed = { Shears = 1, Sword = 1.5 }					if blocks[1] == 'Wool' then toolSpeed.Shears = 5 elseif blocks[1] == 'Leaves' then toolSpeed.Shears = 15 elseif blocks[1] == 'Cobweb' then toolSpeed.Sword = 15 toolSpeed.Shears = 15 elseif blocks[1] =='Bamboo' then toolSpeed.Sword = 5000 end for _, tool in ipairs( tools ) do						local toolDrop = blockArgs[mw.ustring.lower( tool )] if not toolDrop then table.insert( cells, '|—' ) else local willDrop = 'yes' if toolDrop == '0' then willDrop = 'partial' end local breakTime = processTime( hardnessVal / toolSpeed[tool] * 1.5 ) table.insert( cells, '|' .. getChoice( willDrop, breakTime ) ) end end end end end if not horizontal then cells = table.concat( cells, '\n' ) end table.insert( tableParts, cells ) end if horizontal then local blocksArgs = {} for _, arg in ipairs{ 1, 'note', 'sprite', 'link', 'item', 'drop', 2, 3, 'shears', 'sword' } do			if args[arg] then local col = 0 for colVal in mw.text.gsplit( args[arg], '%s*;%s*' ) do					col = col + 1 if colVal ~= '' then if not blocksArgs[col] then blocksArgs[col] = {} end blocksArgs[col][arg] = colVal end end end end for _, block in ipairs( blocksArgs ) do			insertBlock( block ) end local columns = #tableParts for row = 1, #tableParts[1] do			local cells = {} for col = 1, columns do				table.insert( cells, tableParts[col][row] ) end table.insert( rows, table.concat( cells, '\n' ) ) end -- Insert breaking time header after block row when simple, or after tool or hardness row when not table.insert( rows, simple and 3 or showTool and 5 or 4, '! colspan="' .. columns + 1 .. '" |' .. getBreakingTimeHeader( f ) ) else insertBlock( args ) for _, row in ipairs( tableParts ) do			table.insert( rows, row ) end end table.insert( rows, '' ) local note = '' if args.foot or horizontal then note = f:preprocess( ' ' ) if args.foot == '2' then table.insert( rows, header or getDplVar( 'header' ) ) end table.insert( rows, '|}' ) if not horizontal then f:callParserFunction( '#dplvar:set',				'breaking header', ,				'breaking hidetool', ,				'breaking hideshears', ,				'breaking hidesword', ,				'breaking simple', ,				'breaking sortable', 			) end elseif #dplVars > 0 then f:callParserFunction( '#dplvar:set', dplVars ) end return table.concat( rows, '\n|-\n' ) .. note .. table.concat( categories ) end return p