Module:Stonecutting: Difference between revisions

From I-Pixelmon
Jump to navigation Jump to search
No edit summary
No edit summary
Line 1: Line 1:
------------------------------------------------------------
------------------------------------------------------------
--  Stone-cutter recipe carousel
--  Stone-cutter recipe carousel
--  Usage example:
--  Example:
--    {{Stonecutting
--    {{Stonecutting
--      |input=Stone
--      |input=Stone
Line 16: Line 16:
local p = {}
local p = {}


local getArgs = require('Module:Arguments').getArgs
local getArgs = require( 'Module:Arguments' ).getArgs
local trim    = mw.text.trim


------------------------------------------------------------------------
------------------------------------------------------------------------
-- tiny helper that turns {label,image,link} → [[File:...]] or text
-- turn {label,image,link} → thumbnail w/ link (32 px)
------------------------------------------------------------------------
------------------------------------------------------------------------
local function slotImage(label, image, link)
local function slotImage( label, image, link )
if not label or label == '' then return '' end
if not label or label == '' then return '' end
local file = image ~= '' and image or ('Grid_' .. label .. '.png')
local file = ( image ~= '' ) and image or ( 'Grid_' .. label .. '.png' )
local alt  = label
local target = ( link ~= '' ) and link or label
local linkTarget = link ~= '' and link or label
return string.format(
return string.format(
'[[File:%s|32px|class=pixelated|link=%s|alt=%s]]',
'[[File:%s|32px|class=pixelated|link=%s|alt=%s]]',
file, linkTarget, alt
file, target, label
)
)
end
end


------------------------------------------------------------------------
------------------------------------------------------------------------
-- build a single frame (= one output variant)
-- build *one* frame (input + preview + output)
------------------------------------------------------------------------
------------------------------------------------------------------------
local function buildFrame(args, idx)
local function buildFrame( args, idx )
local inputL , inputI , inputLink = args.input     or args[1]           ,
local inL , inI , inLn = args.input or args[1] or '',
                                    args['input-image'] or '',
                          args['input-image'] or '',
                                    args['input-link']   or ''
                          args['input-link'] or ''
local outL   = args['output'..idx] or args[idx+1]   or ''
local outL = args[ 'output' .. idx ]           or args[idx+1] or ''
local outI   = args['output'..idx..'-image'] or ''
local outI = args[ 'output' .. idx .. '-image'] or ''
local outLink= args['output'..idx..'-link'] or ''
local outLn = args[ 'output' .. idx .. '-link' ] or ''


local html = mw.html.create('div'):addClass('sc-frame')
local html = mw.html.create( 'div' ):addClass( 'sc-frame' )
html:wikitext( '[[File:StonecutterGUI.png|180px|link=|alt=]]' )


html:wikitext('[[File:StonecutterGUI.png|180px|link=|alt=]]')
-- input (left)
html:tag('div'):addClass('sc-slot')
    :css{ left = '11px', top = '50px' }
    :wikitext( slotImage( inL,  inI,  inLn ) )


-- input slot (left, 48 × 48 px area)
-- preview (top-centre)
local inp = html:tag('div'):addClass('sc-slot'):css{left='11px', top='50px'}
html:tag('div'):addClass('sc-slot')
inp:wikitext(slotImage(inputL, inputI, inputLink))
    :css{ left = '56.5px', top = '23px' }
    :wikitext( slotImage( outL, outI, outLn ) )


    -- Stonecutting Type (middle)
-- output (right)
local out = html:tag('div'):addClass('sc-slot'):css{left='56.5px', top='23px'}
html:tag('div'):addClass('sc-slot')
out:wikitext(slotImage(outL, outI, outLink))
    :css{ left = '127px', top = '50px' }
    :wikitext( slotImage( outL, outI, outLn ) )


-- output slot (right)
return tostring( html )
local out = html:tag('div'):addClass('sc-slot'):css{left='127px', top='50px'}
out:wikitext(slotImage(outL, outI, outLink))
 
return tostring(html)
end
end


Line 65: Line 67:
-- main entry
-- main entry
------------------------------------------------------------------------
------------------------------------------------------------------------
function p.carousel(frame)
function p.carousel( frame )
local args = getArgs(frame, {removeBlanks = false})
local args = getArgs( frame, { removeBlanks = false } )


-- count outputs (ignore blanks and whitespace-only params)
-- count real outputs (skip blanks / whitespace)
    local count = 0
local count = 0
    while true do
while true do
        local raw = args['output' .. (count + 1)] or args[count + 2]
local raw = args[ 'output' .. ( count + 1 ) ] or args[ count + 2 ]
        if not raw then break end                      -- truly missing
if not raw or trim( tostring( raw ) ) == '' then break end
        if mw.text.trim(tostring(raw)) == '' then break end -- empty / spaces
count = count + 1
        count = count + 1
end
    end
if count == 0 then
if count == 0 then
return "<span style='color:red'>Stonecutting: no outputs supplied</span>"
return '<span style="color:red">Stonecutting: no outputs supplied</span>'
end
end


-- build wrapper
------------------------------------------------------------------
local outer = mw.html.create('div')
-- wrapper
:addClass('stonecutting-carousel')
------------------------------------------------------------------
:css{width = '180px', height = '131px', position = 'relative'}
local outer = mw.html.create( 'div' )
:addClass( 'stonecutting-carousel' )
:css{ width = '180px', height = '131px', position = 'relative' }


for i = 1, count do
for i = 1, count do
outer:wikitext(buildFrame(args, i))
outer:wikitext( buildFrame( args, i ) )
end
end


------------------------------------------------------------------------
-- base (static) stylesheet
--  Dynamically adjust animation timing to the number of frames
local base = frame:extensionTag(
------------------------------------------------------------------------
'templatestyles', '', { src = 'Template:Stonecutting/styles.css' }
local dur = count * 4          -- seconds (4 s per recipe)
)
local pct = 100 / count        -- % slice per recipe
outer:wikitext( base )


local cssCode = {}             -- build a single string
------------------------------------------------------------------
-- dynamic stylesheet (duration / delays)
------------------------------------------------------------------
local dur = count * 4          -- seconds (4 s per recipe)
local pct = 100 / count        -- % slice per recipe
local cssParts = {}


-- main animation rule
table.insert( cssParts,
table.insert(cssCode,
string.format(
  string.format(
'.stonecutting-carousel .sc-frame{animation:sc-cycle %ds steps(1) infinite;}',
    '.stonecutting-carousel .sc-frame{animation:sc-cycle %ds steps(1) infinite;}',
dur
    dur
)
  )
)
)


-- per-frame delays
for i = 1, count do
for i = 1, count do
table.insert( cssParts,
  table.insert(cssCode,
string.format(
    string.format(
'.stonecutting-carousel .sc-frame:nth-child(%d){animation-delay:%ds;}',
      '.stonecutting-carousel .sc-frame:nth-child(%d){animation-delay:%ds;}',
i, ( i - 1 ) * 4
      i, (i - 1) * 4
)
    )
)
  )
end
end


-- key-frames (visible for its slice, hidden otherwise)
table.insert( cssParts,
table.insert(cssCode,
string.format(
  string.format('@keyframes sc-cycle{0%%{opacity:1;} %.2f%%{opacity:1;} %.2f%%{opacity:0;} 100%%{opacity:0;}}',
'@keyframes sc-cycle{0%%{opacity:1;} %.2f%%{opacity:1;} %.2f%%{opacity:0;} 100%%{opacity:0;}}',
                pct, pct + 0.01)
pct, pct + 0.01
)
)
)


cssCode = table.concat(cssCode)
local dyn = frame:extensionTag(
 
'templatestyles',
-- inject as a TemplateStyles tag
table.concat( cssParts, '' ),
local styleDyn = frame:extensionTag(
{ lang = 'css' }
  'templatestyles',
)
  cssCode,
outer:wikitext( dyn )
  { lang = 'css' }             -- inline stylesheet
)
outer:wikitext(styleDyn)


return tostring( outer )
end
end


return p
return p

Revision as of 22:00, 13 June 2025

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

------------------------------------------------------------
--  Stone-cutter recipe carousel
--  Example:
--    {{Stonecutting
--      |input=Stone
--      |input-image=Minecraft-stone.png
--      |input-link=https://minecraft.wiki/w/Stone
--      |output1=Slab
--      |output1-image=Minecraft-stoneslab.png
--      |output1-link=https://minecraft.wiki/w/Slab
--      |output2=Chisel
--      |output2-image=Pixelmon-chisel.png
--      |output2-link=Chisel
--    }}
------------------------------------------------------------
local p = {}

local getArgs = require( 'Module:Arguments' ).getArgs
local trim    = mw.text.trim

------------------------------------------------------------------------
-- turn {label,image,link} → thumbnail w/ link (32 px)
------------------------------------------------------------------------
local function slotImage( label, image, link )
	if not label or label == '' then return '' end
	local file = ( image ~= '' ) and image or ( 'Grid_' .. label .. '.png' )
	local target = ( link ~= '' ) and link or label
	return string.format(
		'[[File:%s|32px|class=pixelated|link=%s|alt=%s]]',
		file, target, label
	)
end

------------------------------------------------------------------------
-- build *one* frame (input + preview + output)
------------------------------------------------------------------------
local function buildFrame( args, idx )
	local inL , inI , inLn  = args.input or args[1] or '',
	                          args['input-image'] or '',
	                          args['input-link']  or ''
	local outL  = args[ 'output' .. idx ]            or args[idx+1] or ''
	local outI  = args[ 'output' .. idx .. '-image'] or ''
	local outLn = args[ 'output' .. idx .. '-link' ] or ''

	local html = mw.html.create( 'div' ):addClass( 'sc-frame' )
	html:wikitext( '[[File:StonecutterGUI.png|180px|link=|alt=]]' )

	-- input (left)
	html:tag('div'):addClass('sc-slot')
	    :css{ left = '11px', top = '50px' }
	    :wikitext( slotImage( inL,  inI,  inLn ) )

	-- preview (top-centre)
	html:tag('div'):addClass('sc-slot')
	    :css{ left = '56.5px', top = '23px' }
	    :wikitext( slotImage( outL, outI, outLn ) )

	-- output (right)
	html:tag('div'):addClass('sc-slot')
	    :css{ left = '127px', top = '50px' }
	    :wikitext( slotImage( outL, outI, outLn ) )

	return tostring( html )
end

------------------------------------------------------------------------
-- main entry
------------------------------------------------------------------------
function p.carousel( frame )
	local args = getArgs( frame, { removeBlanks = false } )

	-- count real outputs (skip blanks / whitespace)
	local count = 0
	while true do
		local raw = args[ 'output' .. ( count + 1 ) ] or args[ count + 2 ]
		if not raw or trim( tostring( raw ) ) == '' then break end
		count = count + 1
	end
	if count == 0 then
		return '<span style="color:red">Stonecutting: no outputs supplied</span>'
	end

	------------------------------------------------------------------
	-- wrapper
	------------------------------------------------------------------
	local outer = mw.html.create( 'div' )
		:addClass( 'stonecutting-carousel' )
		:css{ width = '180px', height = '131px', position = 'relative' }

	for i = 1, count do
		outer:wikitext( buildFrame( args, i ) )
	end

	-- base (static) stylesheet
	local base = frame:extensionTag(
		'templatestyles', '', { src = 'Template:Stonecutting/styles.css' }
	)
	outer:wikitext( base )

	------------------------------------------------------------------
	-- dynamic stylesheet (duration / delays)
	------------------------------------------------------------------
	local dur = count * 4          -- seconds (4 s per recipe)
	local pct = 100 / count        -- % slice per recipe
	local cssParts = {}

	table.insert( cssParts,
		string.format(
			'.stonecutting-carousel .sc-frame{animation:sc-cycle %ds steps(1) infinite;}',
			dur
		)
	)

	for i = 1, count do
		table.insert( cssParts,
			string.format(
				'.stonecutting-carousel .sc-frame:nth-child(%d){animation-delay:%ds;}',
				i, ( i - 1 ) * 4
			)
		)
	end

	table.insert( cssParts,
		string.format(
			'@keyframes sc-cycle{0%%{opacity:1;} %.2f%%{opacity:1;} %.2f%%{opacity:0;} 100%%{opacity:0;}}',
			pct, pct + 0.01
		)
	)

	local dyn = frame:extensionTag(
		'templatestyles',
		table.concat( cssParts, '' ),
		{ lang = 'css' }
	)
	outer:wikitext( dyn )

	return tostring( outer )
end

return p