Module:Grid

From Eccentric Biomes Wiki
Jump to: navigation, search

Documentation for this module may be created at Module:Grid/doc

local defaultMod = 'IDTMod'
local p = {}

-- Individual cell
function p.cell( f )
	local args = f.args or f
	if f == mw.getCurrentFrame() and args[1] == nil then
		args = f:getParent().args
	end
	
	args[1] = mw.text.trim( args[1] or '' )
	
	-- Comment this next line out if you're not using aliases
	--local aliases = mw.loadData( 'Module:Grid/Aliases' )
	
	local modAliases = args.modaliases or ''
	if modAliases ~= '' then
		modAliases = mw.loadData( 'Module:' .. modAliases )
	else
		modAliases = nil
	end
	
	if aliases or modAliases then
		local frames = {}
		for frame in mw.text.gsplit( args[1], '%s*;%s*' ) do
			local frameParts = p.getParts( frame, args.mod )
			
			local id = frameParts.name
			if frameParts.mod then
				id = frameParts.mod .. ':' .. id
			end
			
			local alias
			if modAliases and modAliases[id] then
				alias = modAliases[id]
			elseif aliases and aliases[id] then
				alias = aliases[id]
			end
			
			if alias then
				table.insert( frames, p.expandAlias( frameParts, alias ) )
			else
				table.insert( frames, frame )
			end
		end
		
		args[1] = table.concat( frames, ';' )
	end
	
	local sprite
	--local ids = mw.loadData( [[Module:Grid/IDs]] )
	local modIds = {}
	local animated = args[1]:find( ';' )
	local pageName = mw.title.getCurrentTitle().subpageText
	local imgClass = args.imgclass
	local numStyle = args.numstyle
	local body = mw.html.create( 'span' ):addClass( 'grid' ):css{ ['vertical-align'] = args.align }
	if animated then
		body:addClass( 'animated' )
	end
	if args.class then
		body:addClass( args.class )
	end
	if args.style then
		body:cssText( args.style )
	end
	
	if ( args.default or '' ) ~= '' then
		local item = body
			:tag( 'span' )
				:addClass( 'grid-default-item' )
				:wikitext( '[[File:Grid ', args.default, '.png|32x32px|link=|alt=]]' )
		if animated then
			item:addClass( 'skip' )
		end
	end
	
	local first = true
	for frame in mw.text.gsplit( args[1], '%s*;%s*' ) do
		local item
		if frame ~= '' or frame == '' and animated then
			item = body:tag( 'span' ):addClass( 'grid-item' )
			if imgClass then
				item:addClass( imgClass )
			end
		end
		
		if frame == '' then
			( item or body ):tag( 'br' )
		else
			local parts = p.getParts( frame, args.mod )
			local tooltipTitle = parts.title
			local mod = parts.mod
			local name = parts.name
			local num = parts.num
			local tooltipDesc = parts.text
			
			local img, spriteImg
			if mod then
				if not modIds[mod] and mw.title.new( 'Module:Grid/Mods/' .. mod .. '/IDs' ).exists then
					modIds[mod] = mw.loadData( 'Module:Grid/Mods/' .. mod .. '/IDs' )
				end
				if modIds[mod] and modIds[mod][name] then
					spriteImg = modIds[mod][name]
				else
					img = name .. ' (' .. mod .. ')'
				end
			elseif ids and ids[name] then
				spriteImg = ids[name]
			else
				img = name
			end
			
			local link = args.link or ''
			if link == '' then
				if name == pageName then
					link = 'none'
				elseif mod then
					link = 'mcw:'
					if mod ~= 'Minecraft' then
						link = link .. 'Mods/' .. mod .. '/'
					end
					link = link .. name
				else
					link = name
				end
			end
			
			local title = args.title or ''
			if title == '' then
				if tooltipTitle then
					title = tooltipTitle:gsub( '&[0-9a-fk-or]', '' )
				end
				if mw.text.trim( title ) == '' and ( link:lower() == 'none' or link ~= name ) then
					title = name
				end
			end
			
			if link:lower() == 'none' then
				link = nil
			end
			if title == '' then
				title = nil
			elseif title:lower() == 'none' then
				if link then
					title = ''
				else
					title = nil
				end
			end
			
			if img and ( title == '' or not link ) then
				item:attr{ title = title }
			end
			item:attr{
				['data-minetip-title'] = tooltipTitle,
				['data-minetip-text'] = tooltipDesc
			}
			
			if img then
				item:addClass( 'grid-item-image' )
					:wikitext( '[[File:Grid ', img, '.png|32x32px|link=', link or '', '|', title or '', ']]' )
			else
				if not sprite then
					sprite = require( [[Module:Sprite]] ).base
				end
				local settings = 'Grid/Settings'
				local image
				if mod == 'Minecraft' then
					settings = 'Grid/Mods/Minecraft/Settings'
				elseif mod then
					image = args.spritesheet or mod .. 'Sprite.png'
				end
				if link then
					item:wikitext( '[[', link, '|' )
				end
				item:wikitext( sprite{
					pos = spriteImg, title = title,
					image = image, settings = settings
				} )
			end
			
			if num and num > 1 and num < 1000 then
				if img and link then
					item:wikitext( '[[', link, '|' )
				end
				local number = item
					:tag( 'span' )
						:addClass( 'grid-number' )
						:attr{ title = title }
						:wikitext( num )
				if numStyle then
					number:cssText( numStyle )
				end
				if img and link then
					item:wikitext( ']]' )
				end
			end
			
			if spriteImg and link then
				item:wikitext( ']]' )
			end
		end
		
		if first then
			if animated and item then
				item:addClass( 'active' )
			end
			first = false
		end
	end
	
	return tostring( body )
end

function p.expandAlias( frameParts, alias )
	-- If the frame has no parts, we can just return the alias as-is
	if not frameParts.title and not frameParts.mod and not frameParts.num and not frameParts.text then
		return alias
	end
	
	local expandedFrames = {}
	for aliasFrame in mw.text.gsplit( alias, '%s*;%s*' ) do
		local aliasParts = p.getParts( aliasFrame )
		aliasParts.title = frameParts.title or aliasParts.title or ''
		aliasParts.mod = frameParts.mod or aliasParts.mod or defaultMod
		aliasParts.num = frameParts.num or aliasParts.num or ''
		aliasParts.text = frameParts.text or aliasParts.text or ''
		
		table.insert( expandedFrames, string.format(
			'[%s]%s:%s,%s[%s]',
			aliasParts.title, aliasParts.mod, aliasParts.name, aliasParts.num, aliasParts.text
		) )
	end
	
	return table.concat( expandedFrames, ';' )
end

function p.getParts( frame, mod )
	local parts = {}
	parts.title = frame:match( '^%[%s*([^%]]+)%s*%]' )
	
	parts.mod = mw.text.trim( frame:match( '([^:%]]+):' ) or mod or '' )
	
	if parts.mod == '' or mw.ustring.lower( parts.mod ) == mw.ustring.lower( defaultMod ) then
		parts.mod = nil
	else
		local vanilla = { v = 1, vanilla = 1, mc = 1, minecraft = 1 }
		if vanilla[mw.ustring.lower( parts.mod )] then
			parts.mod = 'Minecraft'
		end
	end
	
	local nameStart = ( frame:find( ':' ) or frame:find( '%]' ) or 0 ) + 1
	if nameStart - 1 == #frame then
		nameStart = 1
	end
	parts.name = mw.text.trim( frame:sub( nameStart, ( frame:find( '[,%[]', nameStart ) or 0 ) - 1 ) )
	
	parts.num = math.floor( frame:match( ',%s*(%d+)' ) or 0 )
	if parts.num == 0 then
		parts.num = nil
	end
	
	parts.text = frame:match( '%[%s*([^%]]+)%s*%]$' )
	
	return parts
end

local addCell = function( args, item, prefix, class, default )
	prefix = prefix or item
	return p.cell{
		args[item], mod = args.Mod, link = args[prefix .. 'link'],
		title = args[prefix .. 'title'], class = class, default = default
	}
end

--- GUI variants; called directly to avoid the overhead of a bunch of #invoke calls per GUI
-- Crafting table
function p.craftingTable( f )
	local args = f
	if f == mw.getCurrentFrame() then
		args = f:getParent().args
	else
		f = mw.getCurrentFrame()
	end
	
	local body = mw.html.create( 'span' ):addClass( 'grid-Crafting_Table' )
	
	local input = body:tag( 'span' ):addClass( 'grid-input' )
	for num = 1, 3 do
		local row = input:tag( 'span' ):addClass( 'grid-row' )
		for _, letter in ipairs{ 'A', 'B', 'C' } do
			row:wikitext( addCell( args, letter .. num ) )
		end
	end
	
	local arrow = body:tag( 'span' ):addClass( 'grid-arrow' ):tag( 'br' ):done()
	if args.arrow or '' ~= '' then
		arrow:css( 'background-image',
			f:callParserFunction( '#widget:FileUrl', { url = args.arrow .. ' (' .. args.Mod .. ').png' } )
		)
	end
	
	body
		:tag( 'span' )
			:addClass( 'grid-output' )
			:wikitext( addCell( args, 'Output', 'O', 'grid-large' ) )
	
	if args.shapeless or '' ~= '' then
		body
			:tag( 'span' )
				:addClass( 'grid-icons' )
				:tag( 'span' )
					:addClass( 'grid-shapeless' )
					:attr( 'title',
						'This recipe is shapeless; the inputs may be placed in any arrangement in the crafting grid.'
					)
					:tag( 'br' )
	end
	
	return tostring( mw.html.create( 'div' ):node( body ) )
end

-- Furnace
function p.furnace( f )
	local args = f
	if f == mw.getCurrentFrame() then
		args = f:getParent().args
	else
		f = mw.getCurrentFrame()
	end
	
	local body = mw.html.create( 'span' ):addClass( 'grid-Furnace' )
	
	local input = body:tag( 'span' ):addClass( 'grid-input' )
	input:wikitext( addCell( args, 'Input', 'I' ) )
	local fuel = input:tag( 'span' ):addClass( 'grid-fuel' ):tag( 'br' ):done()
	local fuelImg = args.FuelUsage or ''
	local burning = args.Input or '' ~= '' and args.Fuel or '' ~= ''
	if not burning then
		fuel:addClass( 'grid-inactive' )
		if fuelImg ~= '' then
			fuelImg = fuelImg .. ' (in-active)'
		end
	end
	if fuelImg ~= '' then
		fuel:css( 'background-image', f:callParserFunction( '#widget:FileUrl', {
			url = 'Grid layout ' .. fuelImg .. ' (' .. args.Mod .. ').png'
		} ) )
	end
	input:wikitext( addCell( args, 'Fuel', 'F' ) )
	
	local arrow = body:tag( 'span' ):addClass( 'grid-arrow' ):tag( 'br' ):done()
	local arrowImg = args.Progress or ''
	if not burning or ( args.Output or '' ) == '' then
		arrow:addClass( 'grid-inactive' )
		if arrowImg ~= '' then
			arrowImg = arrowImg .. ' (in-active)'
		end
	end
	if arrowImg ~= '' then
		arrow:css( 'background-image', f:callParserFunction( '#widget:FileUrl', {
			url = 'Grid layout ' .. arrowImg .. ' (' .. args.Mod .. ').png'
		} ) )
	end
	
	body
		:tag( 'span' )
			:addClass( 'grid-output' )
			:wikitext( addCell( args, 'Output', 'O', 'grid-large' ) )
	
	return tostring( mw.html.create( 'div' ):node( body ) )
end

-- Brewing Stand
function p.brewingStand( f )
	local args = f
	if f == mw.getCurrentFrame() then
		args = f:getParent().args
	else
		f = mw.getCurrentFrame()
	end
	
	local body = mw.html.create( 'span' ):addClass( 'grid-Brewing_Stand' )
	
	local input = body:tag( 'span' ):addClass( 'grid-input' )
	input:tag( 'span' ):addClass( 'grid-bubbling' ):tag( 'br' )
	input:wikitext( addCell( 'Input', 'I' ) )
	input:tag( 'span' ):addClass( 'grid-arrow' ):tag( 'br' )
	if args.Input or '' == '' or
		( args.Output1 or '' ~= '' and args.Output2 or '' ~= '' and args.Output3 or '' ~= '' )
	then
		input:addClass( 'grid-inactive' )
	end
	
	body:tag( 'span' ):addClass( 'grid-paths' ):tag( 'br' )
	
	local output = body:tag( 'span' ):addClass( 'grid-output' )
	for i = 1, 3 do
		output:wikitext( addCell( args, 'Output' .. i, 'O' .. i, 'grid-output' .. i, 'layout Brewing Empty' ) )
	end
	
	return tostring( mw.html.create( 'div' ):node( body ) )
end
 
return p