Module:RankedWars

From NPOWiki
Revision as of 10:53, 21 October 2025 by Bobogoobo (talk | contribs) (use error module)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

Documentation [edit]

This page is a stub - it only covers the very basics of its subject. More information should be added to make the page informative and useful. If no more information is available, the page should be considered for a merge, redirect, or deletion.

Details: documentation to be written

If you can correct the issue, please edit the page to do so, then remove this notice.

Please see Template:Ranked war for usage information. Use the template rather than invoking the module. Data for this module is imported from Module:RankedWars/data and Module:RankedWars/data.json.

For how to update data, please see Module:RankedWars/data/doc.

The above documentation is transcluded from Module:RankedWars/doc.

--todo:
--	Handle ongoing wars (end = 0) - existing logic is untested
--	Add function to get title+disambig of a war for easier linking to correct section, or full link including faction
--	War lookup without faction (special case for internal) - remember to use faction name not shell name.
--	Add overall and per-faction stats - most fought opponents, shortest/longest wars, most/least score, most contested (total score), etc
--	See todos in JS
local data = mw.loadData('Module:RankedWars/data')
local jsonData = mw.loadJsonData('Module:RankedWars/data.json')
local err = require('Module:Error').call

local p = {}

local function factionName(facKey)
	return mw.ustring.upper(mw.ustring.sub(facKey, 1, 1)) .. mw.ustring.sub(facKey, 2)
end

local function displayDataJson(ugly)
	local flag = mw.text.JSON_PRETTY
	if ugly and ugly ~= '' then
		flag = 0
	end
	return mw.text.jsonEncode(data, flag)
end

local function displayFactionStats(faction)
	local capName = factionName(faction)
	local overall = jsonData.wars.overall[faction]
	local warplural = 'wars'
	if overall.wars == 1 then
		warplural = 'war'
	end
		
	return table.concat({
		'NPO - ' .. capName,
		'has participated in',
		overall.wars,
		'ranked ' .. warplural .. ', winning',
		overall.wins,
		'(' .. overall.termedWins .. ' termed)',
		'and losing',
		overall.losses,
		'(' .. overall.termedLosses .. ' termed).',
	}, ' ')
end

local function displayWarData(faction, warId)
	local capName = factionName(faction)
	local warData = jsonData.wars[faction][warId]
	local frame = mw.getCurrentFrame()
	
	local ongoing = false
	if warData['end'] == 0 then
		ongoing = true
		warData.note = 'This war is ongoing.'
	end
		
	local outcome = 'fought'
	if ongoing then
		outcome = 'is fighting'
	elseif warData.win then
		outcome = frame:expandTemplate({
			title = 'color',
			args = { 'green', 'bold', 'won' }
		}) .. ' against'
	else
		outcome = frame:expandTemplate({
			title = 'color',
			args = { 'red', 'bold', 'lost' }
		}) .. ' to'
	end
	local terms = 'war'
	if warData.termed then
		terms = frame:expandTemplate({
			title = 'color',
			args = { 'sandybrown', 'termed' }
		}) .. ' war'
	end
	local opponent = frame:expandTemplate({
		title = 'Tornp',
		args = { warData.oppName }
	})
	local hours = '?'
	if not ongoing then
		hours = string.format('%.0f', (warData['end'] - warData['start']) / 3600)
	end
	local hourplural = 'hours'
	if tonumber(hours) == 1 then
		hourplural = 'hour'
	end
	
	return mw.text.trim(table.concat({
		'NPO - ' .. capName,
		outcome,
		opponent,
		'in a',
		terms,
		'that started at',
		os.date('!%F %T TCT', warData.start),
		'and lasted',
		hours .. ' ' .. hourplural .. '.',
		'With a lead target of',
		warData.target .. ',',
		capName,
		'scored',
		warData.ourScore,
		'while the opponent scored',
		warData.oppScore .. '.',
		warData.note or '',
	}, ' '))
end

local function displayWarHistory(faction, args)
	local warIDs = {}
	local repeats = {}
	local wars = jsonData.wars[faction]
	local out = ''
	local frame = mw.getCurrentFrame()
	
	--The JSON sorts the wars numerically and pairs is random, we want newest first
	for warID, warData in pairs(wars) do
		table.insert(warIDs, 1, warID)
		if repeats[warData.oppName] then
			repeats[warData.oppName] = repeats[warData.oppName] + 1
		else
			repeats[warData.oppName] = 1
		end
	end
	table.sort(warIDs, function(wa, wb)
		return wb < wa
	end)
	
	for _, id in ipairs(warIDs) do
		local warData = wars[id]

		local heading = warData.oppName
		local disambig
		if repeats[warData.oppName] > 1 then
			disambig = os.date('!%b %Y', warData.start)
			heading = heading .. ' (' .. disambig .. ')'
		end
		out = out .. '===' .. heading .. '===\n'
		
		local filename = faction .. ' vs ' .. warData.oppName
		if disambig then
			filename = filename .. ' (' .. disambig .. ')'
		end
		filename = filename .. ' ranked war graph.png'
		out = out .. '[' .. '[' .. 'File:' .. filename .. '|right|400px|alt=Ranked war graph]]\n'
		
		local warpage
		if mw.ustring.find(args['has page'], ',' .. warData.id .. ',', 1, true) then
			warpage = warData.oppName .. ' Ranked War'
			if disambig then
				warpage = warpage .. ' (' .. disambig .. ')'
			end
		end
		if warpage then
			out = out .. frame:expandTemplate({
				title = 'main',
				args = { warpage }
			}) .. '\n'
		end
		
		out = out .. displayWarData(faction, warData.id) .. '\n'
		local blurb = args[tostring(warData.id)]
		if blurb then
			out = out .. '\n' .. blurb .. '\n'
		end
		out = out .. '*[https://www.torn.com/war.php?step=rankreport&rankID=' .. warData.id .. ' War report on Torn]\n'
		out = out .. frame:expandTemplate({ title='clear' }) .. '\n'
		out = out .. '\n'
	end
	
	return out
end

function p.main(frame)
	return p.call(frame:getParent().args)
end

function p.call(args)
	local faction, war, mode
	if not args then args = {} end
	
	if args[1] then
		faction = mw.ustring.lower(args[1])
	end
	if args[2] then
		war = tonumber(args[2])
	end
	mode = mw.ustring.lower(args.mode or '')
	args['has page'] = mw.ustring.gsub(
		',' .. (args['has page'] or '') .. ',',
		' ',
		''
	)
	
	if not faction and mode ~= 'json' then
		return err('faction is currently required')
	end
	
	if faction and not data.factions[faction] then
		return err('incorrect faction name')
	end
	if faction and war and not jsonData.wars[faction][war] then
		return err('specified war not found for the given faction')
	end
	
	if mode == 'history' then
		return displayWarHistory(faction,  args)
	elseif mode == 'overall' then
		return displayFactionStats(faction)
	elseif mode == 'war' then
		if not war then
			return err('war id must be specified for war lookup')
		end
		return displayWarData(faction, war)
	elseif mode == 'json' then
		return displayDataJson(args.ugly)
	elseif mode then
		return err('invalid mode')
	else
		return err('mode is currently required')
	end
end

return p