<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://www.perfecttower2.com/wiki/index.php?action=history&amp;feed=atom&amp;title=Module%3AUI</id>
	<title>Module:UI - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://www.perfecttower2.com/wiki/index.php?action=history&amp;feed=atom&amp;title=Module%3AUI"/>
	<link rel="alternate" type="text/html" href="https://www.perfecttower2.com/wiki/index.php?title=Module:UI&amp;action=history"/>
	<updated>2026-04-20T10:14:10Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.33.1</generator>
	<entry>
		<id>https://www.perfecttower2.com/wiki/index.php?title=Module:UI&amp;diff=4079&amp;oldid=prev</id>
		<title>Exe boss: Create module for rendering Factory UI interfaces, inspired by and partially based on Minecraft Wiki's “Module:UI”; starting with the Crafting grid</title>
		<link rel="alternate" type="text/html" href="https://www.perfecttower2.com/wiki/index.php?title=Module:UI&amp;diff=4079&amp;oldid=prev"/>
		<updated>2026-04-12T08:58:13Z</updated>

		<summary type="html">&lt;p&gt;Create module for rendering Factory UI interfaces, inspired by and partially based on Minecraft Wiki&amp;#039;s “Module:UI”; starting with the Crafting grid&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;-- Used to render Factory UIs&lt;br /&gt;
-- Inspired by Minecraft Wiki's [[Module:UI]]&lt;br /&gt;
require(&amp;quot;Module:No globals&amp;quot;);&lt;br /&gt;
local checkTypeMulti = require(&amp;quot;libraryUtil&amp;quot;).checkTypeMulti;&lt;br /&gt;
&lt;br /&gt;
local ustr = mw.ustring;&lt;br /&gt;
--- @type fun(args: table): MwHtml&lt;br /&gt;
local slot = require(&amp;quot;Module:Factory slot&amp;quot;).slot;&lt;br /&gt;
&lt;br /&gt;
local p = {};&lt;br /&gt;
&lt;br /&gt;
-- Columns for Crafting grids&lt;br /&gt;
local COLUMNS = { &amp;quot;A&amp;quot;, &amp;quot;B&amp;quot;, &amp;quot;C&amp;quot;, &amp;quot;D&amp;quot;, &amp;quot;E&amp;quot;, &amp;quot;F&amp;quot;, &amp;quot;G&amp;quot;, &amp;quot;H&amp;quot; }&lt;br /&gt;
&lt;br /&gt;
--- Creates a Factory UI slot from the arguments named by `name`,&lt;br /&gt;
--- `(name or prefix) .. &amp;quot;link&amp;quot;`, and `(name or prefix) .. &amp;quot;title&amp;quot;`&lt;br /&gt;
---&lt;br /&gt;
--- @param args table&lt;br /&gt;
--- @param name string&lt;br /&gt;
--- @param prefix? string&lt;br /&gt;
--- @param class? string&lt;br /&gt;
--- @param default? string&lt;br /&gt;
local function createSlot(args, name, prefix, class, default)&lt;br /&gt;
	return slot{&lt;br /&gt;
		args[name],&lt;br /&gt;
		link	= args[(prefix or name) .. &amp;quot;link&amp;quot;],&lt;br /&gt;
		title	= args[(prefix or name) .. &amp;quot;title&amp;quot;],&lt;br /&gt;
		class	= class,&lt;br /&gt;
		default	= default,&lt;br /&gt;
	};&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--- @param amount number Non-negative double precision float&lt;br /&gt;
local function implFormatDoubleInteger(amount)&lt;br /&gt;
	if (amount &amp;gt;= math.huge) then&lt;br /&gt;
		return &amp;quot;∞&amp;quot;;&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	amount = math.floor(amount);&lt;br /&gt;
	if (amount &amp;lt; 1e6) then&lt;br /&gt;
		-- less than a million&lt;br /&gt;
		return tostring(amount);&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local exp = 3;&lt;br /&gt;
	while true do&lt;br /&gt;
		exp = exp + 3;&lt;br /&gt;
		amount = math.floor(amount / 1e3 + 0.5);&lt;br /&gt;
&lt;br /&gt;
		if (amount &amp;lt; 1e6) then&lt;br /&gt;
			--- @type string, string&lt;br /&gt;
			local result, b = tostring(amount):match(&amp;quot;^(%d-%d)(%d%d%d)$&amp;quot;);&lt;br /&gt;
			b = b:gsub(&amp;quot;0+$&amp;quot;, &amp;quot;&amp;quot;);&lt;br /&gt;
			if (b ~= &amp;quot;&amp;quot;) then&lt;br /&gt;
				result = result .. &amp;quot;.&amp;quot; .. b;&lt;br /&gt;
			end&lt;br /&gt;
			result = result .. &amp;quot;e&amp;quot; .. exp;&lt;br /&gt;
			return result;&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--- Formats a non-negative double precision integer value&lt;br /&gt;
---&lt;br /&gt;
--- @param amount string|number&lt;br /&gt;
--- @param nonNegative? boolean&lt;br /&gt;
--- @return string|nil&lt;br /&gt;
function p.formatDoubleInteger(amount, nonNegative)&lt;br /&gt;
	checkTypeMulti('&amp;quot;Module:UI&amp;quot;.formatDoubleInteger', 1, amount, { &amp;quot;string&amp;quot;, &amp;quot;number&amp;quot; });&lt;br /&gt;
	amount = tonumber(amount);&lt;br /&gt;
	if (amount == nil or amount ~= amount) then&lt;br /&gt;
		return mw.text.tag(&amp;quot;strong&amp;quot;, { class=&amp;quot;error&amp;quot; }, &amp;quot;NaN&amp;quot;);&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	if (nonNegative and amount &amp;lt; 0) then&lt;br /&gt;
		amount = 0;&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local result = implFormatDoubleInteger(math.abs(amount));&lt;br /&gt;
	if (amount &amp;lt; 0) then&lt;br /&gt;
		result = &amp;quot;-&amp;quot; .. result;&lt;br /&gt;
	end&lt;br /&gt;
	return result;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
--- Crafting grid (size scales with Factory tier)&lt;br /&gt;
---&lt;br /&gt;
--- @param args table&lt;br /&gt;
function p.crafting(args)&lt;br /&gt;
	--- @type integer, integer&lt;br /&gt;
	local minRow, maxRow = math.huge, -math.huge;&lt;br /&gt;
&lt;br /&gt;
	--- @type integer, integer&lt;br /&gt;
	local minCol, maxCol = math.huge, -math.huge;&lt;br /&gt;
&lt;br /&gt;
	for row = 1, 4 do&lt;br /&gt;
		for col = 1, 8 do&lt;br /&gt;
			local name = COLUMNS[col] .. row;&lt;br /&gt;
			if ((args[name] or &amp;quot;&amp;quot;) ~= &amp;quot;&amp;quot;) then&lt;br /&gt;
				minRow = math.min(minRow, row);&lt;br /&gt;
				maxRow = math.max(maxRow, row);&lt;br /&gt;
&lt;br /&gt;
				minCol = math.min(minCol, col);&lt;br /&gt;
				maxCol = math.max(maxCol, col);&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local unlockedRows = maxRow - minRow + 1;&lt;br /&gt;
	local unlockedCols = maxCol - minCol + 1;&lt;br /&gt;
&lt;br /&gt;
	-- Minimum crafting grid size is 2×2&lt;br /&gt;
	if (unlockedRows &amp;lt; 2) then&lt;br /&gt;
		unlockedRows = 2;&lt;br /&gt;
	end&lt;br /&gt;
	if (unlockedCols &amp;lt; 2) then&lt;br /&gt;
		unlockedCols = 2;&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local root = mw.html.create(&amp;quot;div&amp;quot;)&lt;br /&gt;
		:addClass(&amp;quot;factoryui factoryui-crafting pixel-image&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
	-- Input grid&lt;br /&gt;
	do&lt;br /&gt;
		local input = root:tag(&amp;quot;div&amp;quot;)&lt;br /&gt;
			:addClass(&amp;quot;factoryui-input&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
		local rows = 0;&lt;br /&gt;
		for row = minRow, maxRow do&lt;br /&gt;
			rows = rows + 1;&lt;br /&gt;
			local rowHtml = input:tag(&amp;quot;div&amp;quot;)&lt;br /&gt;
				:addClass(&amp;quot;factoryui-row&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
			local cols = 0;&lt;br /&gt;
			for col = minCol, maxCol do&lt;br /&gt;
				cols = cols + 1;&lt;br /&gt;
&lt;br /&gt;
				local name = COLUMNS[col] .. row;&lt;br /&gt;
				rowHtml:node(createSlot(args, name));&lt;br /&gt;
			end&lt;br /&gt;
&lt;br /&gt;
			while cols &amp;lt; unlockedCols do&lt;br /&gt;
				cols = cols + 1;&lt;br /&gt;
				rowHtml:node(slot{});&lt;br /&gt;
			end&lt;br /&gt;
&lt;br /&gt;
			while cols &amp;lt; 8 do&lt;br /&gt;
				cols = cols + 1;&lt;br /&gt;
				rowHtml:node(slot{ class = &amp;quot;locked&amp;quot; });&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		while rows &amp;lt; unlockedRows do&lt;br /&gt;
			rows = rows + 1;&lt;br /&gt;
&lt;br /&gt;
			local rowHtml = input:tag(&amp;quot;div&amp;quot;):addClass(&amp;quot;factoryui-row&amp;quot;);&lt;br /&gt;
			for _ = 1, unlockedCols do&lt;br /&gt;
				rowHtml:node(slot{});&lt;br /&gt;
			end&lt;br /&gt;
			for _ = unlockedCols + 1, 8 do&lt;br /&gt;
				rowHtml:node(slot{ class = &amp;quot;locked&amp;quot; });&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		while rows &amp;lt; 4 do&lt;br /&gt;
			rows = rows + 1;&lt;br /&gt;
			local rowHtml = input:tag(&amp;quot;div&amp;quot;):addClass(&amp;quot;factoryui-row locked&amp;quot;);&lt;br /&gt;
			for _ = 1, 8 do&lt;br /&gt;
				rowHtml:node(slot{ class = &amp;quot;locked&amp;quot; });&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- Output slot and Resource cost&lt;br /&gt;
	do&lt;br /&gt;
		local output = root:tag(&amp;quot;div&amp;quot;)&lt;br /&gt;
			:addClass(&amp;quot;factoryui-output&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
		output:node(createSlot(args, &amp;quot;Output&amp;quot;, &amp;quot;O&amp;quot;, &amp;quot;factoryslot-large&amp;quot;));&lt;br /&gt;
&lt;br /&gt;
		output:tag(&amp;quot;span&amp;quot;)&lt;br /&gt;
			:addClass(&amp;quot;factoryui-cost&amp;quot;)&lt;br /&gt;
			:wikitext(&lt;br /&gt;
				&amp;quot;[[File:Red resource.png|x25px|link=]] &amp;quot;,&lt;br /&gt;
				p.formatDouble(args.cost or 0)&lt;br /&gt;
			)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return root;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
return p;&lt;/div&gt;</summary>
		<author><name>Exe boss</name></author>
		
	</entry>
</feed>