Module:Stonecutting: Difference between revisions

From I-Pixelmon
Jump to navigation Jump to search
No edit summary
No edit summary
Line 1: Line 1:
------------------------------------------------------------
------------------------------------------------------------
-- Module:Stonecutting  · Stone-cutter recipe carousel
--  Stone-cutter recipe carousel
--  Generates a sliding-frame GUI that flips through the
--  supplied outputs every 4 s (configurable below).
------------------------------------------------------------
------------------------------------------------------------
local p      = {}
local p      = {}
local getArgs = require('Module:Arguments').getArgs
local getArgs = require('Module:Arguments').getArgs
Line 13: Line 10:
------------------------------------------------------------------------
------------------------------------------------------------------------
local function slotImage(label, image, link)
local function slotImage(label, image, link)
if not label or label == '' then
if not label or label == '' then return '' end
return ''
local file = (image ~= '' and image) or ('Grid_' .. label .. '.png')
end
local tgt   = (link  ~= '' and link ) or label
local file = (image ~= '' and image) or ('Grid_' .. label .. '.png')
local tgt = (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]]',
Line 28: Line 23:
------------------------------------------------------------------------
------------------------------------------------------------------------
local function buildFrame(args, idx)
local function buildFrame(args, idx)
local inL  = args.input                 or args[1] or ''
local inL  = args.input                     or args[1] or ''
local inI  = args['input-image']         or ''
local inI  = args['input-image']           or ''
local inLn  = args['input-link']         or ''
local inLn  = 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 outLn = args['output' .. idx .. '-link']  or ''
local outLn = args['output' .. idx .. '-link']  or ''
Line 41: Line 36:
-- input (left)
-- input (left)
html:tag('div'):addClass('sc-slot')
html:tag('div'):addClass('sc-slot')
    :css{left = '11px',  top = '50px'}
    :css{left = '11px',  top = '50px'}
    :wikitext(slotImage(inL, inI, inLn))
    :wikitext(slotImage(inL, inI, inLn))


-- preview (top-centre)
-- preview (top-centre)
Line 67: Line 62:
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 or trim(tostring(raw)) == '' then
if not raw or trim(tostring(raw)) == '' then break end
break
end
count = count + 1
count = count + 1
end
end
Line 76: Line 69:
end
end


------------------------------------------------------------------
-- outer wrapper
-- outer wrapper
------------------------------------------------------------------
local outer = mw.html.create('div')
local outer = mw.html.create('div')
:addClass('stonecutting-carousel')
:addClass('stonecutting-carousel')
Line 85: Line 80:
end
end


------------------------------------------------------------------
-- link the static layout rules
-- STATIC SHEET
------------------------------------------------------------------
-- Pass **nil** (not '') or MW will emit  src=""  and warn
outer:wikitext(frame:extensionTag(
outer:wikitext(frame:extensionTag(
'templatestyles',
'templatestyles', '', {src = 'Stonecutting/styles.css'}
nil,
{src = 'Stonecutting/styles.css'}
))
))


------------------------------------------------------------------
------------------------------------------------------------------
-- DYNAMIC SHEET  (timing calculated from #outputs)
-- inject the animation rules inline (<style>) so TemplateStyles
-- never sees an empty |src= and we get the exact timing we need
------------------------------------------------------------------
------------------------------------------------------------------
local dur = count * 4          -- seconds: 4 s per recipe
local dur = count * 4          -- 4 s per frame
local pct = 100 / count       -- slice size
local pct = 100 / count
local vis = pct - 0.01        -- visible for almost the whole slice


local css = {}
local css = {}


-- every frame: instant flip, no cross-fade
-- global rule – one animation definition for every .sc-frame
css[#css+1] = string.format(
css[#css+1] = string.format(
'.stonecutting-carousel .sc-frame{animation:sc-cycle %ds step-start infinite;}',
'.stonecutting-carousel .sc-frame{animation:sc-cycle %ds steps(1) infinite;}',
dur
dur
)
)


-- start offsets
-- per-frame delays
for i = 1, count do
for i = 1, count do
css[#css+1] = string.format(
css[#css+1] = string.format(
Line 118: Line 108:
end
end


-- keyframes
-- keyframes (visible for its slice, hidden otherwise)
css[#css+1] = string.format(
css[#css+1] = 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;}}',
vis, pct
pct, pct + 0.01
)
)


outer:wikitext(frame:extensionTag(
-- inline <style> block (avoids the TemplateStyles warning)
'templatestyles',
outer:wikitext('<style>' .. table.concat(css, '\n') .. '</style>')
table.concat(css),
{lang = 'css'}
))


return tostring(outer)
return tostring(outer)

Revision as of 02:15, 14 June 2025

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

------------------------------------------------------------
--  Stone-cutter recipe carousel
------------------------------------------------------------
local p       = {}
local getArgs = require('Module:Arguments').getArgs
local trim    = mw.text.trim

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

------------------------------------------------------------------------
-- buildFrame(args, idx) → html for one output variant
------------------------------------------------------------------------
local function buildFrame(args, idx)
	local inL   = args.input                     or args[1] or ''
	local inI   = args['input-image']            or ''
	local inLn  = 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 non-blank outputs
	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

	------------------------------------------------------------------
	-- outer 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

	-- link the static layout rules
	outer:wikitext(frame:extensionTag(
		'templatestyles', '', {src = 'Stonecutting/styles.css'}
	))

	------------------------------------------------------------------
	-- inject the animation rules inline (<style>) so TemplateStyles
	-- never sees an empty |src= and we get the exact timing we need
	------------------------------------------------------------------
	local dur = count * 4          -- 4 s per frame
	local pct = 100 / count

	local css = {}

	-- global rule – one animation definition for every .sc-frame
	css[#css+1] = string.format(
		'.stonecutting-carousel .sc-frame{animation:sc-cycle %ds steps(1) infinite;}',
		dur
	)

	-- per-frame delays
	for i = 1, count do
		css[#css+1] = string.format(
			'.stonecutting-carousel .sc-frame:nth-child(%d){animation-delay:%ds;}',
			i, (i - 1) * 4
		)
	end

	-- keyframes (visible for its slice, hidden otherwise)
	css[#css+1] = string.format(
		'@keyframes sc-cycle{0%%{opacity:1;} %.2f%%{opacity:1;} %.2f%%{opacity:0;} 100%%{opacity:0;}}',
		pct, pct + 0.01
	)

	-- inline <style> block (avoids the TemplateStyles warning)
	outer:wikitext('<style>' .. table.concat(css, '\n') .. '</style>')

	return tostring(outer)
end

return p