Module:UI
Jump to navigation
Jump to search
Documentation for this module may be created at Module:UI/doc
-- Used to render Factory UIs
-- Inspired by Minecraft Wiki's [[Module:UI]]
require("Module:No globals");
local checkTypeMulti = require("libraryUtil").checkTypeMulti;
local ustr = mw.ustring;
--- @type fun(args: table): MwHtml
local slot = require("Module:Factory slot").slot;
local p = {};
-- Columns for Crafting grids
local COLUMNS = { "A", "B", "C", "D", "E", "F", "G", "H" }
--- Creates a Factory UI slot from the arguments named by `name`,
--- `(name or prefix) .. "link"`, and `(name or prefix) .. "title"`
---
--- @param args table
--- @param name string
--- @param prefix? string
--- @param class? string
--- @param default? string
local function createSlot(args, name, prefix, class, default)
return slot{
args[name],
link = args[(prefix or name) .. "link"],
title = args[(prefix or name) .. "title"],
class = class,
default = default,
};
end
--- @param amount number Non-negative double precision float
local function implFormatDoubleInteger(amount)
if (amount >= math.huge) then
return "∞";
end
amount = math.floor(amount);
if (amount < 1e6) then
-- less than a million
return tostring(amount);
end
local exp = 3;
while true do
exp = exp + 3;
amount = math.floor(amount / 1e3 + 0.5);
if (amount < 1e6) then
--- @type string, string
local result, b = tostring(amount):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
--- Formats a non-negative double precision integer value
---
--- @param amount string|number
--- @param nonNegative? boolean
--- @return string|nil
function p.formatDoubleInteger(amount, nonNegative)
checkTypeMulti('"Module:UI".formatDoubleInteger', 1, amount, { "string", "number" });
amount = tonumber(amount);
if (amount == nil or amount ~= amount) then
return mw.text.tag("strong", { class="error" }, "NaN");
end
if (nonNegative and amount < 0) then
amount = 0;
end
local result = implFormatDoubleInteger(math.abs(amount));
if (amount < 0) then
result = "-" .. result;
end
return result;
end
--- Crafting grid (size scales with Factory tier)
---
--- @param args table
function p.crafting(args)
--- @type integer, integer
local minRow, maxRow = math.huge, -math.huge;
--- @type integer, integer
local minCol, maxCol = math.huge, -math.huge;
for row = 1, 4 do
for col = 1, 8 do
local name = COLUMNS[col] .. row;
if ((args[name] or "") ~= "") then
minRow = math.min(minRow, row);
maxRow = math.max(maxRow, row);
minCol = math.min(minCol, col);
maxCol = math.max(maxCol, col);
end
end
end
local unlockedRows = maxRow - minRow + 1;
local unlockedCols = maxCol - minCol + 1;
-- Minimum crafting grid size is 2×2
if (unlockedRows < 2) then
unlockedRows = 2;
end
if (unlockedCols < 2) then
unlockedCols = 2;
end
local root = mw.html.create("div")
:addClass("factoryui factoryui-crafting pixel-image");
-- Input grid
do
local input = root:tag("div")
:addClass("factoryui-input");
local rows = 0;
for row = minRow, maxRow do
rows = rows + 1;
local rowHtml = input:tag("div")
:addClass("factoryui-row");
local cols = 0;
for col = minCol, maxCol do
cols = cols + 1;
local name = COLUMNS[col] .. row;
rowHtml:node(createSlot(args, name));
end
while cols < unlockedCols do
cols = cols + 1;
rowHtml:node(slot{});
end
while cols < 8 do
cols = cols + 1;
rowHtml:node(slot{ class = "locked" });
end
end
while rows < unlockedRows do
rows = rows + 1;
local rowHtml = input:tag("div"):addClass("factoryui-row");
for _ = 1, unlockedCols do
rowHtml:node(slot{});
end
for _ = unlockedCols + 1, 8 do
rowHtml:node(slot{ class = "locked" });
end
end
while rows < 4 do
rows = rows + 1;
local rowHtml = input:tag("div"):addClass("factoryui-row locked");
for _ = 1, 8 do
rowHtml:node(slot{ class = "locked" });
end
end
end
-- Output slot and Resource cost
do
local output = root:tag("div")
:addClass("factoryui-output");
output:node(createSlot(args, "Output", "O", "factoryslot-large"));
output:tag("span")
:addClass("factoryui-cost")
:wikitext(
"[[File:Red resource.png|x25px|link=]] ",
p.formatDouble(args.cost or 0)
)
end
return root;
end
return p;