Jump to content

Module:AmmoStats

From WarExpand Wiki

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

-- Renders ammunition statistics from [[Module:Data/Ammo]].
--
-- This module is hand-written, in the same style as Module:UnitStats.
-- Module:Data/Ammo is meant to be generated by scripts/export-wiki-data.cjs
-- (which only writes under the Module:Data/ prefix), so this file is never
-- overwritten by the export.
--
-- Entry point:
--   table  - one row per ammunition   {{#invoke:AmmoStats|table}}  or  {{#invoke:AmmoStats|table|kind=unit}}
--
-- Expected shape of Module:Data/Ammo (field names follow the game's ammo
-- table: volume, craft_time, batch_size, required_<resource>, and for
-- strategic ordnance impact_radius_meters, loss_percent, build_time):
--
--   return {
--     light_infantry_ammo = {
--       name       = 'Rifle Rounds',
--       kind       = 'unit',            -- 'unit' | 'fortification' | 'strategic'
--       fired_by   = 'Light Infantry',  -- optional, wiki page name
--       volume     = 0.5,               -- m3 per unit, optional
--       craft_time = '10m',             -- optional
--       batch_size = 100,               -- optional
--       cost       = { money = 50, metal = 10, concrete = 0, petrol = 0, uranium = 0 },
--       impact_radius = 5000,           -- metres, strategic only
--       loss_percent  = 40,             -- strategic only
--     },
--   }

local p = {}

local loaded, data = pcall( mw.loadData, 'Module:Data/Ammo' )
if not loaded then
	data = nil
end

local PENDING = "''Stats not yet available.''"

local RESOURCES = { 'money', 'food', 'metal', 'concrete', 'petrol', 'uranium' }
local KIND_ORDER = { unit = 1, fortification = 2, strategic = 3 }
local KIND_LABEL = { unit = 'Unit', fortification = 'Fortification', strategic = 'Strategic' }

local function formatResources( bundle )
	if not bundle then
		return nil
	end
	local parts = {}
	for _, name in ipairs( RESOURCES ) do
		local amount = bundle[name]
		if amount and amount > 0 then
			parts[#parts + 1] = string.format( '%s %s', amount, name )
		end
	end
	if #parts == 0 then
		return 'free'
	end
	return table.concat( parts, ', ' )
end

local function cell( value )
	if value == nil or value == '' then
		return '| -\n'
	end
	return string.format( '| %s\n', value )
end

--- Table of every ammunition, optionally filtered by kind.
-- Usage: {{#invoke:AmmoStats|table|kind=fortification}}
function p.table( frame )
	if not data then
		return PENDING
	end
	local wanted = frame.args.kind
	if wanted == '' then
		wanted = nil
	end

	local codes = {}
	for code, ammo in pairs( data ) do
		if not wanted or ammo.kind == wanted then
			codes[#codes + 1] = code
		end
	end
	table.sort( codes, function( a, b )
		local ka, kb = KIND_ORDER[data[a].kind] or 9, KIND_ORDER[data[b].kind] or 9
		if ka ~= kb then
			return ka < kb
		end
		return ( data[a].name or a ) < ( data[b].name or b )
	end )
	if #codes == 0 then
		return "''No ammunition of this kind.''"
	end

	local strategic = false
	for _, code in ipairs( codes ) do
		if data[code].kind == 'strategic' then
			strategic = true
		end
	end

	local out = {
		'{| class="wikitable sortable" style="text-align:center"\n',
		'! Ammunition !! Kind !! Fired by !! Batch size !! Craft time !! Batch cost !! Volume (m³)',
	}
	if strategic then
		out[#out + 1] = ' !! Impact radius !! Losses'
	end
	out[#out + 1] = '\n'
	for _, code in ipairs( codes ) do
		local a = data[code]
		out[#out + 1] = '|-\n'
		out[#out + 1] = cell( a.name or code )
		out[#out + 1] = cell( KIND_LABEL[a.kind] or a.kind )
		out[#out + 1] = cell( a.fired_by and string.format( '[[%s]]', a.fired_by ) or nil )
		out[#out + 1] = cell( a.batch_size )
		out[#out + 1] = cell( a.craft_time )
		out[#out + 1] = cell( formatResources( a.cost ) )
		out[#out + 1] = cell( a.volume )
		if strategic then
			out[#out + 1] = cell( a.impact_radius and string.format( '%s m', a.impact_radius ) or nil )
			out[#out + 1] = cell( a.loss_percent and string.format( '%s%%', a.loss_percent ) or nil )
		end
	end
	out[#out + 1] = '|}'
	return table.concat( out )
end

return p