Module:CraftingTable: Difference between revisions

From Pixelrus
Jump to navigation Jump to search
No edit summary
No edit summary
 
(2 intermediate revisions by the same user not shown)
Line 1: Line 1:
-- Module:CraftingTable animated crafting-grid slots
-- Module:CraftingTable
-- Renders an animated crafting-table grid with per-slot and output
-- stack-size overlays.
 
local p      = {}
local p      = {}
local getArgs = require('Module:Arguments').getArgs
local getArgs = require('Module:Arguments').getArgs
local trim    = mw.text.trim


----------------------------------------------------------------------
----------------------------------------------------------------------
Line 17: Line 21:


----------------------------------------------------------------------
----------------------------------------------------------------------
-- collect *all* numbered args for a slot  (A1, A1-2, A1-3, …)
-- collect *all* numbered args for a slot  (A1, A1-2, …)
-- returns  { {label=…, image=…, link=}, … },  qty
----------------------------------------------------------------------
----------------------------------------------------------------------
local function collectItems(args, base)
local function collectItems(args, base)
local items = {}
local items, qty = {}, tonumber(args[base .. '-qty'])
for key, val in pairs(args) do
for key, val in pairs(args) do
if mw.ustring.match(key, '^' .. base .. '$') or
if mw.ustring.match(key, '^' .. base .. '$') or
Line 26: Line 31:
local label = val
local label = val
if label and label ~= '' then
if label and label ~= '' then
local image = args[key .. '-image'] or ''
table.insert(items, {
local link  = args[key .. '-link']  or ''
label = label,
table.insert(items, {label = label, image = image, link = link})
image = args[key .. '-image'] or '',
link  = args[key .. '-link']  or ''
})
end
end
end
end
end
end
table.sort(items, function(a, b) return a.label < b.label end) -- deterministic order
table.sort(items, function(a, b) return a.label < b.label end) -- deterministic
return items
return items, qty
end
 
----------------------------------------------------------------------
-- inject the expanded {{GridText}} overlay into *parent*
-- strips the automatic <p> wrapper to avoid mis-alignment
----------------------------------------------------------------------
local function putQtyOverlay(parent, frame, colour, num, left, bottom)
local html = frame:expandTemplate{ title = 'GridText', args = { colour, num } }
html = trim(html):gsub('^<p>(.*)</p>$', '%1')  -- drop wrapper
parent:tag('div')
:css{
position = 'absolute',
left    = left  or '0',
bottom  = bottom or '0',
width    = '32px',
height  = '14px',
overflow = 'hidden'
}
:wikitext(html)
end
end


Line 40: Line 66:
----------------------------------------------------------------------
----------------------------------------------------------------------
function p.grid(frame)
function p.grid(frame)
local args = getArgs(frame, {removeBlanks = false})
local args = getArgs(frame, { removeBlanks = false })


-- slot coordinates (input 3×3 + output)
-- slot coordinates (input 3 × 3 + output)
local slots = {
local slots = {
A1 = {left=14,  top=14},  A2 = {left=14,  top=50},  A3 = {left=14,  top=86},
A1 = { 14,  14 },  A2 = { 14,  50 },  A3 = { 14,  86 },
B1 = {left=50,  top=14},  B2 = {left=50,  top=50},  B3 = {left=50,  top=86},
B1 = { 50,  14 },  B2 = { 50,  50 },  B3 = { 50,  86 },
C1 = {left=86,  top=14},  C2 = {left=86,  top=50},  C3 = {left=86,  top=86},
C1 = { 86,  14 },  C2 = { 86,  50 },  C3 = { 86,  86 },
Output = {left=202, top=50},
Output = { 202, 50 },
}
}


-- outer container (the template already provides a relative parent)
-- outer container (template already provides a relative parent)
local root = mw.html.create()
local root = mw.html.create()


for slot, pos in pairs(slots) do
for slot, pos in pairs(slots) do
local items = collectItems(args, slot)
local items, qty = collectItems(args, slot)
if #items > 0 then
if #items > 0 then
local holder = root:tag('div')
local holder = root:tag('div')
:css('position', 'absolute')
:css{
:css('left', pos.left .. 'px'):css('top', pos.top .. 'px')
position = 'absolute',
:css('width', '32px'):css('height', '32px')
left     = pos[1] .. 'px',
top     = pos[2] .. 'px',
width   = '32px',
height   = '32px'
}


if #items == 1 then
if #items == 1 then
Line 71: Line 101:
:wikitext(slotImage(it.label, it.image, it.link))
:wikitext(slotImage(it.label, it.image, it.link))
end
end
end
-- per-slot quantity
if qty and qty > 1 then
putQtyOverlay(holder, frame, 'white', qty)
end
end
end
end
Line 77: Line 112:
-- shapeless icon
-- shapeless icon
if args.shapeless and args.shapeless ~= '' then
if args.shapeless and args.shapeless ~= '' then
local tooltip = 'This recipe is shapeless; the ingredients may be placed in any arrangement in the crafting grid.'
local tip = 'This recipe is shapeless; the ingredients may be placed in any arrangement in the crafting grid.'
root:tag('div')
root:tag('div')
:css{position='absolute', left='135px', top='96px',
:css{ position='absolute', left='135px', top='96px',
    width='19px', height='15px'}
      width='19px', height='15px' }
:wikitext(string.format(
:wikitext(string.format(
'<span title="%s">[[File:Shapeless.png|19px|class=pixelated|link=|alt=Shapeless recipe]]</span>',
'<span title="%s">[[File:Shapeless.png|19px|class=pixelated|link=|alt=Shapeless recipe]]</span>',
mw.text.nowiki(tooltip)
mw.text.nowiki(tip)
))
))
end
end


-- output-amount overlay
-- output-stack amount
if args.OA and args.OA ~= '' then
if args.OA and tonumber(args.OA) and tonumber(args.OA) > 1 then
root:tag('div')
local box = root:tag('div')
:css{position='absolute', left='201px', top='71px',
:css{ position='absolute', left='201px', top='71px',
    width='64px', height='24px', overflow='hidden'}
      width='64px', height='24px', overflow='hidden' }
:wikitext(string.format('{{GridText|white|%s}}', args.OA))
-- centre overlay inside 64-px area (32-px slot is at +33 px)
putQtyOverlay(box, frame, 'white', args.OA, '33px', '0')
end
end



Latest revision as of 20:49, 24 June 2025

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

-- Module:CraftingTable
-- Renders an animated crafting-table grid with per-slot and output
-- stack-size overlays.

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

----------------------------------------------------------------------
-- helper : render a 32-px inventory-slot image
----------------------------------------------------------------------
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 ('Special:MyLanguage/' .. label)
	return string.format(
		'[[File:%s|32px|class=pixelated|link=%s|alt=%s]]',
		file, tgt, label
	)
end

----------------------------------------------------------------------
-- collect *all* numbered args for a slot  (A1, A1-2, …)
-- returns   { {label=…, image=…, link=…}, … },  qty
----------------------------------------------------------------------
local function collectItems(args, base)
	local items, qty = {}, tonumber(args[base .. '-qty'])
	for key, val in pairs(args) do
		if mw.ustring.match(key, '^' .. base .. '$') or
		   mw.ustring.match(key, '^' .. base .. '%-%d+$') then
			local label = val
			if label and label ~= '' then
				table.insert(items, {
					label = label,
					image = args[key .. '-image'] or '',
					link  = args[key .. '-link']  or ''
				})
			end
		end
	end
	table.sort(items, function(a, b) return a.label < b.label end) -- deterministic
	return items, qty
end

----------------------------------------------------------------------
-- inject the expanded {{GridText}} overlay into *parent*
-- strips the automatic <p> wrapper to avoid mis-alignment
----------------------------------------------------------------------
local function putQtyOverlay(parent, frame, colour, num, left, bottom)
	local html = frame:expandTemplate{ title = 'GridText', args = { colour, num } }
	html = trim(html):gsub('^<p>(.*)</p>$', '%1')  -- drop wrapper
	parent:tag('div')
		:css{
			position = 'absolute',
			left     = left   or '0',
			bottom   = bottom or '0',
			width    = '32px',
			height   = '14px',
			overflow = 'hidden'
		}
		:wikitext(html)
end

----------------------------------------------------------------------
-- public entry – {{#invoke:CraftingTable|grid|…}}
----------------------------------------------------------------------
function p.grid(frame)
	local args  = getArgs(frame, { removeBlanks = false })

	-- slot coordinates (input 3 × 3 + output)
	local slots = {
		A1 = {  14,  14 },  A2 = {  14,  50 },  A3 = {  14,  86 },
		B1 = {  50,  14 },  B2 = {  50,  50 },  B3 = {  50,  86 },
		C1 = {  86,  14 },  C2 = {  86,  50 },  C3 = {  86,  86 },
		Output = { 202,  50 },
	}

	-- outer container (template already provides a relative parent)
	local root = mw.html.create()

	for slot, pos in pairs(slots) do
		local items, qty = collectItems(args, slot)
		if #items > 0 then
			local holder = root:tag('div')
				:css{
					position = 'absolute',
					left     = pos[1] .. 'px',
					top      = pos[2] .. 'px',
					width    = '32px',
					height   = '32px'
				}

			if #items == 1 then
				holder:wikitext(slotImage(items[1].label, items[1].image, items[1].link))
			else
				for i, it in ipairs(items) do
					holder:tag('div')
						:addClass('slot-frame')
						:css('animation-duration', (#items * 2) .. 's')
						:css('animation-delay', ((i - 1) * 2) .. 's')
						:wikitext(slotImage(it.label, it.image, it.link))
				end
			end

			-- per-slot quantity
			if qty and qty > 1 then
				putQtyOverlay(holder, frame, 'white', qty)
			end
		end
	end

	-- shapeless icon
	if args.shapeless and args.shapeless ~= '' then
		local tip = 'This recipe is shapeless; the ingredients may be placed in any arrangement in the crafting grid.'
		root:tag('div')
			:css{ position='absolute', left='135px', top='96px',
			      width='19px', height='15px' }
			:wikitext(string.format(
				'<span title="%s">[[File:Shapeless.png|19px|class=pixelated|link=|alt=Shapeless recipe]]</span>',
				mw.text.nowiki(tip)
			))
	end

	-- output-stack amount
	if args.OA and tonumber(args.OA) and tonumber(args.OA) > 1 then
		local box = root:tag('div')
			:css{ position='absolute', left='201px', top='71px',
			      width='64px', height='24px', overflow='hidden' }
		-- centre overlay inside 64-px area (32-px slot is at +33 px)
		putQtyOverlay(box, frame, 'white', args.OA, '33px', '0')
	end

	return tostring(root)
end

return p