<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.warexpand.com/index.php?action=history&amp;feed=atom&amp;title=Module%3ABuildingStats</id>
	<title>Module:BuildingStats - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.warexpand.com/index.php?action=history&amp;feed=atom&amp;title=Module%3ABuildingStats"/>
	<link rel="alternate" type="text/html" href="https://wiki.warexpand.com/index.php?title=Module:BuildingStats&amp;action=history"/>
	<updated>2026-10-12T07:07:13Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.43.11</generator>
	<entry>
		<id>https://wiki.warexpand.com/index.php?title=Module:BuildingStats&amp;diff=188&amp;oldid=prev</id>
		<title>Warmaninger: Import generated wiki content (units, buildings, fortifications, overview, categories)</title>
		<link rel="alternate" type="text/html" href="https://wiki.warexpand.com/index.php?title=Module:BuildingStats&amp;diff=188&amp;oldid=prev"/>
		<updated>2026-08-21T22:48:50Z</updated>

		<summary type="html">&lt;p&gt;Import generated wiki content (units, buildings, fortifications, overview, categories)&lt;/p&gt;
&lt;table style=&quot;background-color: #fff; color: #202122;&quot; data-mw=&quot;interface&quot;&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;tr class=&quot;diff-title&quot; lang=&quot;en&quot;&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;← Older revision&lt;/td&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;Revision as of 22:48, 21 August 2026&lt;/td&gt;
				&lt;/tr&gt;&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot; id=&quot;mw-diff-left-l137&quot;&gt;Line 137:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 137:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;	return table.concat( {&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;	return table.concat( {&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;		&amp;#039;{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;float:right; margin:0 0 1em 1em; min-width:18em&amp;quot;\n&amp;#039;,&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;		&amp;#039;{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;float:right; margin:0 0 1em 1em; min-width:18em&amp;quot;\n&amp;#039;,&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;−&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;		string.format( &#039;|+ %s &lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;&amp;amp;mdash; &lt;/del&gt;level %d\n&#039;, building.name, level ),&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;		string.format( &#039;|+ %s &lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;(&lt;/ins&gt;level %d&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;)&lt;/ins&gt;\n&#039;, building.name, level ),&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;		row( &amp;#039;Kind&amp;#039;, building.kind ),&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;		row( &amp;#039;Kind&amp;#039;, building.kind ),&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;		row( &amp;#039;Max level&amp;#039;, levelsLabel ),&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;		row( &amp;#039;Max level&amp;#039;, levelsLabel ),&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot; id=&quot;mw-diff-left-l185&quot;&gt;Line 185:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 185:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;	local out = {&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;	local out = {&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;		&amp;#039;{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align:center&amp;quot;\n&amp;#039;,&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;		&amp;#039;{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align:center&amp;quot;\n&amp;#039;,&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;−&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;		string.format( &#039;|+ %s &lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;&amp;amp;mdash; &lt;/del&gt;stats by level\n&#039;, building.name ),&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;		string.format( &#039;|+ %s&lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;: &lt;/ins&gt;stats by level\n&#039;, building.name ),&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;		&amp;#039;! Stat\n&amp;#039;,&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;		&amp;#039;! Stat\n&amp;#039;,&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;	}&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;	}&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot; id=&quot;mw-diff-left-l201&quot;&gt;Line 201:&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Line 201:&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;				cells[#cells + 1] = string.format( &amp;#039;| %s\n&amp;#039;, value )&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;				cells[#cells + 1] = string.format( &amp;#039;| %s\n&amp;#039;, value )&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;			else&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;			else&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;−&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;				cells[#cells + 1] = &#039;| &lt;del style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;&amp;amp;mdash;&lt;/del&gt;\n&#039;&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot; data-marker=&quot;+&quot;&gt;&lt;/td&gt;&lt;td style=&quot;color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;				cells[#cells + 1] = &#039;| &lt;ins style=&quot;font-weight: bold; text-decoration: none;&quot;&gt;-&lt;/ins&gt;\n&#039;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;			end&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;			end&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;		end&lt;/div&gt;&lt;/td&gt;&lt;td class=&quot;diff-marker&quot;&gt;&lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #202122; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;		end&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;

&lt;!-- diff cache key warexpand_wiki:diff:1.41:old-96:rev-188:php=table --&gt;
&lt;/table&gt;</summary>
		<author><name>Warmaninger</name></author>
	</entry>
	<entry>
		<id>https://wiki.warexpand.com/index.php?title=Module:BuildingStats&amp;diff=96&amp;oldid=prev</id>
		<title>Warmaninger: Import generated wiki content (units, buildings, fortifications, overview, categories)</title>
		<link rel="alternate" type="text/html" href="https://wiki.warexpand.com/index.php?title=Module:BuildingStats&amp;diff=96&amp;oldid=prev"/>
		<updated>2026-08-21T22:28:01Z</updated>

		<summary type="html">&lt;p&gt;Import generated wiki content (units, buildings, fortifications, overview, categories)&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;-- Renders building statistics from [[Module:Data/Buildings]].&lt;br /&gt;
--&lt;br /&gt;
-- This module is hand-written, in the same style as Module:UnitStats.&lt;br /&gt;
-- Module:Data/Buildings is meant to be generated by scripts/export-wiki-data.cjs&lt;br /&gt;
-- (which only writes under the Module:Data/ prefix), so this file is never&lt;br /&gt;
-- overwritten by the export.&lt;br /&gt;
--&lt;br /&gt;
-- Entry points:&lt;br /&gt;
--   infobox  - stat box for ONE level        {{#invoke:BuildingStats|infobox|code=metal_mine|level=1}}&lt;br /&gt;
--   levels   - comparison table, ALL levels  {{#invoke:BuildingStats|levels|code=metal_mine}}&lt;br /&gt;
--&lt;br /&gt;
-- Expected shape of Module:Data/Buildings (field names follow the game&amp;#039;s&lt;br /&gt;
-- building tier table: resource_output, unit_efficiency, maintenance_cost,&lt;br /&gt;
-- build_time, required_&amp;lt;resource&amp;gt;, upkeep_&amp;lt;resource&amp;gt;):&lt;br /&gt;
--&lt;br /&gt;
--   return {&lt;br /&gt;
--     metal_mine = {&lt;br /&gt;
--       name      = &amp;#039;Metal Mine&amp;#039;,&lt;br /&gt;
--       kind      = &amp;#039;Resource Production&amp;#039;,   -- optional&lt;br /&gt;
--       produces  = &amp;#039;metal&amp;#039;,                 -- optional, resource code&lt;br /&gt;
--       trains    = &amp;#039;Infantry&amp;#039;,              -- optional, free text&lt;br /&gt;
--       max_level = 5,                       -- optional&lt;br /&gt;
--       levels = {&lt;br /&gt;
--         [1] = {&lt;br /&gt;
--           output      = 50,                -- resource_output, per hour&lt;br /&gt;
--           efficiency  = 1.0,               -- unit_efficiency&lt;br /&gt;
--           maintenance = 10,                -- maintenance_cost&lt;br /&gt;
--           build_time  = &amp;#039;1h&amp;#039;,&lt;br /&gt;
--           cost   = { money = 100, metal = 0, concrete = 20, petrol = 0, uranium = 0 },&lt;br /&gt;
--           upkeep = { metal = 0, concrete = 0, petrol = 0, uranium = 0 },&lt;br /&gt;
--         },&lt;br /&gt;
--         [2] = { ... },&lt;br /&gt;
--       },&lt;br /&gt;
--     },&lt;br /&gt;
--   }&lt;br /&gt;
&lt;br /&gt;
local p = {}&lt;br /&gt;
&lt;br /&gt;
-- Module:Data/Buildings is absent until the export has run; fail soft instead&lt;br /&gt;
-- of printing a Lua error on every building page.&lt;br /&gt;
local loaded, data = pcall( mw.loadData, &amp;#039;Module:Data/Buildings&amp;#039; )&lt;br /&gt;
if not loaded then&lt;br /&gt;
	data = nil&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local PENDING = &amp;quot;&amp;#039;&amp;#039;Stats not yet available.&amp;#039;&amp;#039;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
local RESOURCES = { &amp;#039;money&amp;#039;, &amp;#039;food&amp;#039;, &amp;#039;metal&amp;#039;, &amp;#039;concrete&amp;#039;, &amp;#039;petrol&amp;#039;, &amp;#039;uranium&amp;#039; }&lt;br /&gt;
&lt;br /&gt;
-- &amp;quot;100 money, 20 concrete&amp;quot;, or &amp;quot;free&amp;quot; when nothing is required.&lt;br /&gt;
local function formatResources( bundle )&lt;br /&gt;
	if not bundle then&lt;br /&gt;
		return nil&lt;br /&gt;
	end&lt;br /&gt;
	local parts = {}&lt;br /&gt;
	for _, name in ipairs( RESOURCES ) do&lt;br /&gt;
		local amount = bundle[name]&lt;br /&gt;
		if amount and amount &amp;gt; 0 then&lt;br /&gt;
			parts[#parts + 1] = string.format( &amp;#039;%s %s&amp;#039;, amount, name )&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	if #parts == 0 then&lt;br /&gt;
		return &amp;#039;free&amp;#039;&lt;br /&gt;
	end&lt;br /&gt;
	return table.concat( parts, &amp;#039;, &amp;#039; )&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Emits nothing at all for a missing value, so empty rows never show up.&lt;br /&gt;
local function row( label, value )&lt;br /&gt;
	if value == nil or value == &amp;#039;&amp;#039; then&lt;br /&gt;
		return &amp;#039;&amp;#039;&lt;br /&gt;
	end&lt;br /&gt;
	return string.format( &amp;#039;|-\n! %s\n| %s\n&amp;#039;, label, value )&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- &amp;quot;50 metal/h&amp;quot; when both are known, the bare resource otherwise.&lt;br /&gt;
local function producesOf( building, stats )&lt;br /&gt;
	if not building.produces then&lt;br /&gt;
		return nil&lt;br /&gt;
	end&lt;br /&gt;
	if stats and stats.output then&lt;br /&gt;
		return string.format( &amp;#039;%s %s/h&amp;#039;, stats.output, building.produces )&lt;br /&gt;
	end&lt;br /&gt;
	return building.produces&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Level numbers of a building, sorted ascending. Works on mw.loadData tables&lt;br /&gt;
-- (which support pairs() but not the # operator) and tolerates gaps.&lt;br /&gt;
local function levelNumbers( building )&lt;br /&gt;
	local nums = {}&lt;br /&gt;
	for key in pairs( building.levels or {} ) do&lt;br /&gt;
		local n = tonumber( key )&lt;br /&gt;
		if n then&lt;br /&gt;
			nums[#nums + 1] = n&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	table.sort( nums )&lt;br /&gt;
	return nums&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function unknownBuilding( code )&lt;br /&gt;
	return string.format(&lt;br /&gt;
		&amp;#039;&amp;lt;strong class=&amp;quot;error&amp;quot;&amp;gt;Unknown building code: %s&amp;lt;/strong&amp;gt;&amp;#039;,&lt;br /&gt;
		tostring( code )&lt;br /&gt;
	)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--- Stat box for one level of one building.&lt;br /&gt;
-- Usage: {{#invoke:BuildingStats|infobox|code=metal_mine|level=1}}&lt;br /&gt;
function p.infobox( frame )&lt;br /&gt;
	local code = frame.args.code&lt;br /&gt;
	local level = tonumber( frame.args.level ) or 1&lt;br /&gt;
&lt;br /&gt;
	if not data then&lt;br /&gt;
		return PENDING&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local building = data[code]&lt;br /&gt;
	if not building then&lt;br /&gt;
		return unknownBuilding( code )&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local stats = building.levels and building.levels[level]&lt;br /&gt;
	if not stats then&lt;br /&gt;
		return string.format(&lt;br /&gt;
			&amp;#039;&amp;lt;strong class=&amp;quot;error&amp;quot;&amp;gt;%s has no level %s&amp;lt;/strong&amp;gt;&amp;#039;,&lt;br /&gt;
			building.name, tostring( level )&lt;br /&gt;
		)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local maxLevel = building.max_level or #levelNumbers( building )&lt;br /&gt;
	local levelsLabel = nil&lt;br /&gt;
	if maxLevel and maxLevel &amp;gt; 1 then&lt;br /&gt;
		levelsLabel = string.format( &amp;#039;%d (see [[#Stats|all levels]])&amp;#039;, maxLevel )&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return table.concat( {&lt;br /&gt;
		&amp;#039;{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;float:right; margin:0 0 1em 1em; min-width:18em&amp;quot;\n&amp;#039;,&lt;br /&gt;
		string.format( &amp;#039;|+ %s &amp;amp;mdash; level %d\n&amp;#039;, building.name, level ),&lt;br /&gt;
		row( &amp;#039;Kind&amp;#039;, building.kind ),&lt;br /&gt;
		row( &amp;#039;Max level&amp;#039;, levelsLabel ),&lt;br /&gt;
		row( &amp;#039;Produces&amp;#039;, producesOf( building, stats ) ),&lt;br /&gt;
		row( &amp;#039;Trains&amp;#039;, building.trains ),&lt;br /&gt;
		row( &amp;#039;Unit efficiency&amp;#039;, stats.efficiency ),&lt;br /&gt;
		row( &amp;#039;Maintenance&amp;#039;, stats.maintenance ),&lt;br /&gt;
		row( &amp;#039;Build time&amp;#039;, stats.build_time ),&lt;br /&gt;
		row( &amp;#039;Cost&amp;#039;, formatResources( stats.cost ) ),&lt;br /&gt;
		row( &amp;#039;Upkeep&amp;#039;, formatResources( stats.upkeep ) ),&lt;br /&gt;
		&amp;#039;|}&amp;#039;,&lt;br /&gt;
	} )&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Rows of the level comparison table: label + accessor. A row is skipped&lt;br /&gt;
-- entirely when no level has a value for it.&lt;br /&gt;
local LEVEL_ROWS = {&lt;br /&gt;
	{ &amp;#039;Output /h&amp;#039;,       function( s ) return s.output end },&lt;br /&gt;
	{ &amp;#039;Unit efficiency&amp;#039;, function( s ) return s.efficiency end },&lt;br /&gt;
	{ &amp;#039;Maintenance&amp;#039;,     function( s ) return s.maintenance end },&lt;br /&gt;
	{ &amp;#039;Build time&amp;#039;,      function( s ) return s.build_time end },&lt;br /&gt;
	{ &amp;#039;Cost&amp;#039;,            function( s ) return formatResources( s.cost ) end },&lt;br /&gt;
	{ &amp;#039;Upkeep&amp;#039;,          function( s ) return formatResources( s.upkeep ) end },&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
--- Comparison table of every level of one building (levels as columns).&lt;br /&gt;
-- Usage: {{#invoke:BuildingStats|levels|code=metal_mine}}&lt;br /&gt;
function p.levels( frame )&lt;br /&gt;
	local code = frame.args.code&lt;br /&gt;
&lt;br /&gt;
	if not data then&lt;br /&gt;
		return PENDING&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local building = data[code]&lt;br /&gt;
	if not building then&lt;br /&gt;
		return unknownBuilding( code )&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local nums = levelNumbers( building )&lt;br /&gt;
	if #nums == 0 then&lt;br /&gt;
		return string.format(&lt;br /&gt;
			&amp;#039;&amp;lt;strong class=&amp;quot;error&amp;quot;&amp;gt;%s has no level data&amp;lt;/strong&amp;gt;&amp;#039;, building.name&lt;br /&gt;
		)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local out = {&lt;br /&gt;
		&amp;#039;{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;text-align:center&amp;quot;\n&amp;#039;,&lt;br /&gt;
		string.format( &amp;#039;|+ %s &amp;amp;mdash; stats by level\n&amp;#039;, building.name ),&lt;br /&gt;
		&amp;#039;! Stat\n&amp;#039;,&lt;br /&gt;
	}&lt;br /&gt;
	for _, n in ipairs( nums ) do&lt;br /&gt;
		out[#out + 1] = string.format( &amp;#039;! Level %d\n&amp;#039;, n )&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	for _, def in ipairs( LEVEL_ROWS ) do&lt;br /&gt;
		local label, get = def[1], def[2]&lt;br /&gt;
		local cells, any = {}, false&lt;br /&gt;
		for _, n in ipairs( nums ) do&lt;br /&gt;
			local value = get( building.levels[n] )&lt;br /&gt;
			if value ~= nil and value ~= &amp;#039;&amp;#039; then&lt;br /&gt;
				any = true&lt;br /&gt;
				cells[#cells + 1] = string.format( &amp;#039;| %s\n&amp;#039;, value )&lt;br /&gt;
			else&lt;br /&gt;
				cells[#cells + 1] = &amp;#039;| &amp;amp;mdash;\n&amp;#039;&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
		if any then&lt;br /&gt;
			out[#out + 1] = string.format( &amp;#039;|-\n! style=&amp;quot;text-align:left&amp;quot; | %s\n&amp;#039;, label )&lt;br /&gt;
			out[#out + 1] = table.concat( cells )&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	out[#out + 1] = &amp;#039;|}&amp;#039;&lt;br /&gt;
	return table.concat( out )&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
return p&lt;/div&gt;</summary>
		<author><name>Warmaninger</name></author>
	</entry>
</feed>