Module:Factory slot
Draws one slot of a Factory grid: an item icon with its stack count. Module:UI uses it for the crafting grids of {{Crafting}}, and Module:Recipe table uses its stack parser. Inspired by and partially based on Minecraft Wiki's Module:Inventory slot.
The look is in Template:Crafting/styles.css (TemplateStyles). main adds that stylesheet; when a module calls slot, the module adds it, as Module:UI does.
Item stacks
A stack is written Name or Name,count. A tier at the end, Circuit Plate T3 or Circuit Plate [T3], gives the name Circuit Plate [T3] and the icon File:Circuit Plate T3.png, shown at 32×32 pixels and pixelated. Counts above 1 show in the corner of the slot: in full below a million, then as 1.5E6 (the E with the brand kit class .tpt-num__e), and as ∞ from 1E18 or when written ∞. The slot count always uses this notation; it doesn't follow the reader's number format.
Counts can be written in full or in E notation, with either case: Plate,1500000, Plate,1.5e6 and Plate,1.5E6 are the same stack.
Functions
slot(args): the slot as anmw.htmlspan.args[1]is a stack string or table; without it the slot is empty.linkis the page the icon and count link to (no link when empty orno).classandstylego on the slot,itemClassanditemStyleon the item,numStyleon the count.main(frame): the same for {{Factory slot}}, which no page uses at the moment.parseStack(text)andstringifyStack(stack): convert between stack strings and{ name, count }tables.formatCount(count): the count text, ornilfor counts below 2.
-- Used to render Factory inventory slots
-- Inspired by and partially based on Minecraft Wiki's [[Module:Inventory slot]]
require("Module:No globals");
local checkType = require("libraryUtil").checkType;
local ustr = mw.ustring;
local INFINITY = "∞";
-- The look of the slots is in [[Template:Crafting/styles.css]] (TemplateStyles).
local STYLES = "Template:Crafting/styles.css";
local p = {};
--- Formats the item stack count
--- @param count integer
--- @return string|nil
function p.formatCount(count)
checkType('"Module:Factory slot".formatCount', 1, count, "number");
count = math.floor(count);
if (count >= 1e18) then
return INFINITY;
end
if (count < 2) then
return nil;
end
if (count < 1e6) then
-- less than a million
return tostring(count);
end
local exp = 3;
while true do
exp = exp + 3;
count = math.floor(count / 1e3 + 0.5);
if (count < 1e6 or exp == 15) then
--- @type string, string
local result, b = tostring(count):match("^(%d-%d)(%d%d%d)$");
b = b:gsub("0+$", "");
if (b ~= "") then
result = result .. "." .. b;
end
result = result .. "e" .. exp;
return result;
end
end
end
--- @class ItemStack
--- @field name string
--- @field count? number
--- Creates the actual HTML node for a given item stack
---
--- @param stack ItemStack
--- @param args? table
local function makeItem(stack, args)
args = args or {}
local item = mw.html.create("span")
:addClass("factoryslot-item")
:addClass(args.itemClass)
:cssText(args.itemStyle);
local name = stack.name;
if ((name or "") == "") then
-- Empty stack
return nil;
end
local escapedName = name:gsub("%[(T%d+)%]$", "[%1]");
local pageName = name:gsub("%[(T%d+)%]$", "%1");
local img = pageName .. ".png";
local link = args.link;
if ((link or "") == "") then
link = nil;
elseif (string.lower(link) == "no") then
link = nil;
end
local altText = img .. ": The Perfect Tower 2 Factory inventory icon of " .. escapedName;
if (link) then
altText = altText .. " linking to " .. link;
end
item:addClass("pixel-image")
:wikitext("[[File:", img, "|32x32px|link=", link or "", "|alt=", altText, "|", escapedName, "]]");
local count = stack.count;
if (count and count > 1) then
count = p.formatCount(count);
if (count ~= nil) then
if (link) then
item:wikitext("[[", link, "|");
end
local number = item:tag("span")
:addClass("factoryslot-stacksize")
:attr("title", name)
:wikitext(count);
number:cssText(args.numStyle);
if (link) then
item:wikitext("]]");
end
end
end
return item;
end
p._makeItem = makeItem;
local function fixTier(name)
local prefix, tier;
prefix, tier = name:match("^%s*(.*) (T%d+)%s*$");
if (tier) then
name = prefix .. " [" .. tier .. "]";
else
name = mw.text.trim(name)
end
return name;
end
--- Parses an Item Stack Definition into an ItemStack table
---
--- Syntax:
--- ```text
--- <Name:string> ( ',' <Count:number> )?
--- ```
---
--- @param itemStackDesc string
--- @return ItemStack
function p.parseStack(itemStackDesc)
-- Simple stack definition with no parts or reserved characters
if (not string.match(itemStackDesc, "[:,]")) then
return { name = fixTier(itemStackDesc) };
end
local stack = {};
local name, count;
name, count = ustr.match(itemStackDesc, "^%s*(.*),%s*([" .. INFINITY .. "0-9%.e]+)%s*$");
if (count == INFINITY) then
count = math.huge;
else
count = count and tonumber(count);
end
if (count) then
name = mw.text.trim(name);
if (count >= 1e18) then
count = math.huge;
else
count = math.floor(count);
end
stack.count = count;
else
name = mw.text.trim(itemStackDesc);
end
stack.name = fixTier(name);
return stack;
end
--- Stringifies an ItemStack table into an Item Stack Definition string
---
--- @param itemStack ItemStack
--- @return string
function p.stringifyStack(itemStack)
local name = itemStack.name;
local count = itemStack.count;
local result = name;
if (count and count >= 0) then
if (count >= 1e18) then
count = INFINITY;
else
count = tostring(count);
end
result = result .. "," .. count;
end
return result;
end
--- Main entry point.
--- Builds the HTML for a Factory inventory slot.
---
--- @param args any
function p.slot(args)
local stack = args[1];
if (type(stack) == "string") then
stack = p.parseStack(stack);
end
local class = args.class;
local body = mw.html.create("span")
:addClass("factoryslot")
:addClass(class)
:cssText(args.style);
if (not stack) then
return body;
end
body:node(makeItem(stack, args));
return body;
end
-- Main template entry point.
function p.main(frame)
return frame:extensionTag("templatestyles", "", { src = STYLES })
.. tostring(p.slot(require("Module:Arguments").getArgs(frame, {
frameOnly = false,
wrappers = { "Template:Factory slot" },
})));
end
return p;