Module:RankedWars/data

From NPOWiki
Revision as of 07:10, 19 October 2025 by Bobogoobo (talk | contribs) (terms should be up to date as of now)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

Documentation [edit]

Faction shell and RW corrections information are updated directly in this module. To update ranked war history data, see below.

Updating ranked wars

To update ranked wars data, run the following code on this page and copy the result from the console to Module:RankedWars/data.json. Be sure to fill in your public API key on the second line. Make sure there are no errors in the editor or the saved page. You should also check the diff from the page history after saving, as this will reveal any faction shells that have changed name and need to be added to the corrections here.

Expand to show code
//Get each of our factions' RW history from the Torn API, calculate stats, and output json format for storage.
//Requires faction and war correction data, which instead of requesting through the MediaWiki API, we grab from the module page.
//	Meaning this script must be run on either Module:RankedWars/data or that page's /doc page.
//By Bobogoobo [2618206] for NPOWiki
(function () {
	var apiKey = '';// requires public access key
	if (!apiKey) return 'API key required';
	
	//JS generally does, but is not guaranteed to, give things back in the order you do them.
	//Things get mixed up in between Lua -> JSON - > JS, so we want to be sure to iterate in this order when generating the output.
	var factionOrder = ['strength', 'prosperity', 'endurance', 'valour', 'serenity', 'peace'];
	
	var jsonData = document.getElementById('rw-json-data');
	if (!jsonData) {
		return 'JSON not found. Are you running this on the "Module:RankedWars/data" page?';
	}
	jsonData = JSON.parse(jsonData.firstElementChild.textContent);
	var factions = jsonData.factions;
	var corrections = jsonData.corrections;
	//todo: I put termed for anything that says Derank, but some of the early ones predate terming and there may not have been an official agreement.
	//	Can usually tell from score anyway, but may want to put notes where needed
	
	// wars by faction, newest first (gets reversed in JSON); keys same as in "factions"
	var wars = {
		overall: {},
	};
	var requests = {
		pending: 0,
		completed: 0,
		failed: 0,
		ignoredWars: 0,
	};
	
	async function requestWarHistory(shell, facName, offset, limit) {
		var url = 'https://api.torn.com/v2/faction/';
		url = url.concat(
			shell.id,
			'/rankedwars?offset=',
			offset,
			'&limit=',
			limit,
			'&key=',
			apiKey,
			'&comment=NPOWiki-RW',
		);
		try {
			var response = await fetch(url);
			if (!response.ok) {
				var error = 'Request error:';
				error = error.concat(
					' status ',
					response.status,
					' for faction ',
					shell.id,
					' with offset ',
					offset,
				);
				throw new Error(err);
			}
			var data = await response.json();
			requests.completed += 1;
			processWarHistory(data, shell, facName, offset, limit);
		} catch (err) {
			requests.failed += 1;
			console.error(err);
			//todo: handle error
		} finally {
			requests.pending -= 1;
			if (requests.pending < 1 && requests.completed + requests.failed > 0) {
				finalize();
			}
		}
	}
	
	function processWarHistory(data, shell, facName, offset, limit) {
		data.rankedwars.forEach(function (war) {
			//Wars that started or ended outside of the shell's range will not be included
			if (war.start > shell.startUnix && (war.end || Infinity) < (shell.endUnix || Infinity)) {
				var usFirst = war.factions[0].id === shell.id;
				var usData = war.factions[+!usFirst];
				var themData = war.factions[+usFirst];
				// "chain" property appears to be worthless, and "forfeit" very unlikely.
				var warData = {
					id: war.id,
					start: war.start,
					end: war.end,
					shell: usData.id,
					opponent: themData.id,
					oppName: themData.name,
					win: war.winner === shell.id,
					termed: false,
					target: war.target,
					ourScore: usData.score,
					oppScore: themData.score,
				};
				var correction = corrections[war.id];
				if (correction) {
					if (correction.opponent) {
						warData.oppName = correction.opponent;
					}
					if (correction.termed) {
						warData.termed = true;
					}
					if (correction.note) {
						warData.note = correction.note;
					}
				}
				wars[facName][war.id] = warData;
			} else {
				requests.ignoredWars += 1;
				//todo: track ignored wars, but maybe handle when looking up same shell multiple times
			}
		});
		if (data._metadata.links.next) {
			offset += limit;
			requests.pending += 1;
			setTimeout(requestWarHistory, 750, shell, facName, offset, limit);
		}
	}
	
	function finalize() {
		factionOrder.forEach(function (faction) {
			var stats = {
				wars: 0,
				wins: 0,
				losses: 0,
				termedWins: 0,
				termedLosses: 0,
			};
			Object.keys(wars[faction]).forEach(function (war) {
				war = wars[faction][war];
				stats.wars += 1;
				if (war.win) {
					stats.wins += 1;
					if (war.termed) {
						stats.termedWins += 1;
					}
				} else {
					stats.losses += 1;
					if (war.termed) {
						stats.termedLosses += 1;
					}
				}
			});
			wars.overall[faction] = stats;
		});
		var output = {
			_meta: {
				documentation: ' https://wiki.npowned.net/view/Module:RankedWars/data.json/doc '
			},
			wars,
		}
		console.log(JSON.stringify(output, null, '\t'));
		console.log(requests);
		//todo
	}
	
	factionOrder.forEach(function (faction, i) {
		var limit = 100;// maximum limit for Torn RW API
		
		wars[faction] = {};
		factions[faction].forEach(function (shell, j) {
			//Torn and Lua use seconds, not milliseconds
			shell.startUnix = Date.parse(shell.start) / 1000;
			shell.endUnix = Date.parse(shell.end) / 1000;
			
			var offset = 0;
			requests.pending += 1;
			setTimeout(requestWarHistory, 500 * (i + 1) * (j + 1), shell, faction, offset, limit);
		});
	});
	//todo: consider if worth calling rankedwarreport - definitely would be nice to have full stats.
	//	Maybe a separate script that can pull from this one's output? Although having it all together and only one script to run/page to update would be nice
	//todo: war graphs for in-family wars will be duplicate files
	//need more ways to make the pages visually interesting and not samey - point out important/contested wars. Could color code things for at a glance? (With icons perhaps)
	//todo for module: fun stats - most fought opponents, ...
	//should have something to get at least the appropriate section link for a given war, or just name+disambig in general, since they can change
	//don't have anything to handle having pages for wars against the same opponent by different NPO factions...
	//adding blurbs needs to be done...
})();

JSON

This is taken from the module content and used by the script. It does not need to be expanded for the script to work.

Expand to show JSON data
{
    "factions": {
        "prosperity": [
            {
                "id": 44758,
                "end": "",
                "start": "2022-10-14",
                "label": "Current shell"
            },
            {
                "id": 11162,
                "end": "2022-10-14",
                "start": "2021-10-16",
                "label": "Old shell (sold to PimpChu)"
            },
            {
                "id": 44751,
                "end": "2021-10-16",
                "start": "2020-02-09",
                "label": "Older shell (now Cry of the Lost)"
            }
        ],
        "endurance": [
            {
                "id": 12645,
                "end": "",
                "start": "2024-05-15",
                "label": "Current shell"
            },
            {
                "id": 14052,
                "end": "2024-05-15",
                "start": "2022-08-03",
                "label": "Old shell (now Serenity)"
            }
        ],
        "peace": [
            {
                "id": 18714,
                "end": "",
                "start": "2022-07-16",
                "label": "Current shell"
            }
        ],
        "valour": [
            {
                "id": 26885,
                "end": "",
                "start": "2023-12-31",
                "label": "Current shell"
            }
        ],
        "strength": [
            {
                "id": 10610,
                "end": "",
                "start": "2022-10-03",
                "label": "Current shell"
            },
            {
                "id": 44758,
                "end": "2022-10-03",
                "start": "2020-02-09",
                "label": "Old shell (now Prosperity)"
            }
        ],
        "serenity": [
            {
                "id": 14052,
                "end": "",
                "start": "2024-05-15",
                "label": "Current shell"
            }
        ]
    },
    "corrections": {
        "339": {
            "opponent": "IA Green"
        },
        "401": {
            "opponent": "War Sluts"
        },
        "1009": {
            "opponent": "Legacy"
        },
        "1081": {
            "opponent": "Goodnight Moon"
        },
        "1592": {
            "opponent": "39th Street Killers XR"
        },
        "2072": {
            "opponent": "709's RugRats"
        },
        "2389": {
            "opponent": "Chaos Rising"
        },
        "3253": {
            "opponent": "DropBears",
            "termed": true
        },
        "3305": {
            "termed": true
        },
        "3439": {
            "termed": true
        },
        "3536": {
            "termed": true
        },
        "3632": {
            "termed": true
        },
        "3706": {
            "termed": true
        },
        "3980": {
            "opponent": "The Unwoke"
        },
        "4218": {
            "opponent": "NNGO Deja 2"
        },
        "4286": {
            "opponent": "Clockwork Orange"
        },
        "4305": {
            "opponent": "Forged In Fire"
        },
        "4684": {
            "opponent": "Riot"
        },
        "5006": {
            "opponent": "Ouroboros"
        },
        "5190": {
            "opponent": "Hello High",
            "termed": true
        },
        "5307": {
            "termed": true
        },
        "5341": {
            "termed": true
        },
        "5536": {
            "termed": true
        },
        "5610": {
            "opponent": "Infernum Legion"
        },
        "5823": {
            "opponent": "SWISS COVERT CORPS"
        },
        "6038": {
            "note": "This faction is now NSO II but was still their second faction at the time.",
            "opponent": "New Sith Order"
        },
        "6384": {
            "termed": true
        },
        "6425": {
            "opponent": "Nuova Famiglia"
        },
        "6444": {
            "termed": true
        },
        "7015": {
            "termed": true
        },
        "7066": {
            "termed": true
        },
        "7074": {
            "opponent": "Nuova Famiglia"
        },
        "7103": {
            "termed": true
        },
        "7633": {
            "termed": true
        },
        "8534": {
            "opponent": "Ghost Ship"
        },
        "9302": {
            "termed": true
        },
        "9310": {
            "termed": true
        },
        "9418": {
            "termed": true
        },
        "9588": {
            "termed": true
        },
        "9765": {
            "termed": true
        },
        "10953": {
            "opponent": "WIT-Ranger"
        },
        "11136": {
            "opponent": "Little Stompers",
            "termed": true
        },
        "11546": {
            "termed": true
        },
        "13284": {
            "opponent": "Elements"
        },
        "13875": {
            "opponent": "Monarch Army of Light"
        },
        "14015": {
            "opponent": "The Corporation"
        },
        "14329": {
            "opponent": "The Corporation"
        },
        "14405": {
            "opponent": "Ass, Grass or Cache"
        },
        "14681": {
            "opponent": "WTF Ducks"
        },
        "15016": {
            "termed": true
        },
        "15107": {
            "termed": true
        },
        "15425": {
            "termed": true
        },
        "15559": {
            "termed": true
        },
        "15850": {
            "termed": true
        },
        "16061": {
            "termed": true
        },
        "16603": {
            "termed": true
        },
        "16972": {
            "termed": true
        },
        "17128": {
            "termed": true
        },
        "17403": {
            "termed": true
        },
        "17544": {
            "termed": true
        },
        "17942": {
            "opponent": "Clockwork Orange"
        },
        "17986": {
            "opponent": "FREE PALESTINE",
            "termed": true
        },
        "18181": {
            "opponent": "Happy Vegemites",
            "termed": true
        },
        "19540": {
            "termed": true
        },
        "21146": {
            "note": "Strength did not contest this war."
        },
        "21417": {
            "termed": true
        },
        "21648": {
            "opponent": "Luscious Estuary",
            "termed": true
        },
        "21844": {
            "termed": true
        },
        "22408": {
            "termed": true
        },
        "22547": {
            "termed": true
        },
        "22621": {
            "termed": true
        },
        "22648": {
            "termed": true
        },
        "22809": {
            "termed": true
        },
        "22993": {
            "opponent": "AQUA-Neptune",
            "termed": true
        },
        "23168": {
            "termed": true
        },
        "23498": {
            "termed": true
        },
        "24005": {
            "opponent": "Neon Cartel"
        },
        "24748": {
            "termed": true
        },
        "25092": {
            "termed": true
        },
        "25233": {
            "termed": true
        },
        "25785": {
            "termed": true
        },
        "26378": {
            "termed": true
        },
        "26698": {
            "termed": true
        },
        "26763": {
            "termed": true
        },
        "29101": {
            "termed": true
        },
        "29532": {
            "termed": true
        },
        "29810": {
            "termed": true
        },
        "30645": {
            "termed": true
        },
        "31075": {
            "termed": true
        },
        "31536": {
            "termed": true
        }
    },
    "rw_release": "2021-12-07"
}

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

--Please see the comments for how to update values. Make sure there are no errors.
--This data gets translated into JSON to be used in the script included with the documentation, which generates the war data.
--It is also available to other modules if needed.
return {
	rw_release = '2021-12-07',
	--List of corrections to the Torn API ranked wars data.
	--Indexed by RW id, please keep in reverse chronological order (i.e. descending).
	--Note that NPO faction name will be automatically corrected from the shell list.
	--Only include termed if it WAS termed. Use notes only in extreme cases, should be a brief full sentence.
	--Possible keys (in order): termed (boolean), opponent (string), note (string)
	--//***** LAST UPDATED terming - STR VS MONARCH CHRYSALIS 31536 *****\\
	corrections = {
		[31536] = { termed = true },
		[31075] = { termed = true },
		[30645] = { termed = true },
		[29810] = { termed = true },
		[29532] = { termed = true },
		[29101] = { termed = true },
		[26763] = { termed = true },
		[26698] = { termed = true },
		[26378] = { termed = true },
		[25785] = { termed = true },
		[25233] = { termed = true },
		[25092] = { termed = true },
		[24748] = { termed = true },
		[24005] = { opponent = 'Neon Cartel' },
		[23498] = { termed = true },
		[23168] = { termed = true },
		[22993] = { termed = true, opponent = 'AQUA-Neptune' },
		[22809] = { termed = true },
		[22648] = { termed = true },
		[22621] = { termed = true },
		[22547] = { termed = true },
		[22408] = { termed = true },
		[21844] = { termed = true },
		[21648] = { termed = true, opponent = 'Luscious Estuary' },
		[21417] = { termed = true },
		[21146] = { note = 'Strength did not contest this war.' },
		[19540] = { termed = true },
		[18181] = { termed = true, opponent = 'Happy Vegemites' },
		[17986] = { termed = true, opponent = 'FREE PALESTINE' },
		[17942] = { opponent = 'Clockwork Orange' },
		[17544] = { termed = true },
		[17403] = { termed = true },
		[17128] = { termed = true },
		[16972] = { termed = true },
		[16603] = { termed = true },
		[16061] = { termed = true },
		[15850] = { termed = true },
		[15559] = { termed = true },
		[15425] = { termed = true },
		[15107] = { termed = true },
		[15016] = { termed = true },
		[14681] = { opponent = 'WTF Ducks' },
		[14405] = { opponent = 'Ass, Grass or Cache' },
		[14329] = { opponent = 'The Corporation' },
		[14015] = { opponent = 'The Corporation' },
		[13875] = { opponent = 'Monarch Army of Light' },
		[13284] = { opponent = 'Elements' },
		[11546] = { termed = true },
		[11136] = { termed = true, opponent = 'Little Stompers' },
		[10953] = { opponent = 'WIT-Ranger' },
		[9765] = { termed = true },
		[9588] = { termed = true },
		[9418] = { termed = true },
		[9310] = { termed = true },
		[9302] = { termed = true },
		[8534] = { opponent = 'Ghost Ship' },
		[7633] = { termed = true },
		[7066] = { termed = true },
		[7103] = { termed = true },
		[7074] = { opponent = 'Nuova Famiglia' },
		[7015] = { termed = true },
		[6444] = { termed = true },
		[6425] = { opponent = 'Nuova Famiglia' },
		[6384] = { termed = true },
		[6038] = { opponent = 'New Sith Order', note = 'This faction is now NSO II but was still their second faction at the time.' },
		[5823] = { opponent = 'SWISS COVERT CORPS' },
		[5610] = { opponent = 'Infernum Legion' },
		[5536] = { termed = true },
		[5341] = { termed = true },
		[5307] = { termed = true },
		[5190] = { termed = true, opponent = 'Hello High' },
		[5006] = { opponent = 'Ouroboros' },
		[4684] = { opponent = 'Riot' },
		[4305] = { opponent = 'Forged In Fire' },
		[4286] = { opponent = 'Clockwork Orange' },
		[4218] = { opponent = 'NNGO Deja 2' },
		[3980] = { opponent = 'The Unwoke' },
		[3706] = { termed = true },
		[3632] = { termed = true },
		[3536] = { termed = true },
		[3439] = { termed = true },
		[3305] = { termed = true },
		[3253] = { termed = true, opponent = 'DropBears' },
		[2389] = { opponent = 'Chaos Rising' },
		[2072] = { opponent = "709's RugRats" },
		[1592] = { opponent = '39th Street Killers XR' },
		[1081] = { opponent = 'Goodnight Moon' },
		[1009] = { opponent = 'Legacy' },
		[401] = { opponent = 'War Sluts' },
		[339] = { opponent = 'IA Green' },
	},
	--Full list of shells we have used. Please keep shell lists in reverse chronological order.
	--Dates are approximate due to transition time, merely following official announcements.
	--	END/SER transition approximated around RWs.
	--Ranges are contiguous to avoid missing any events.
	factions = {
		strength = {
			{
				label = 'Current shell',
				id = 10610,
				start = '2022-10-03',
				['end'] = '',
			},
			{
				label = 'Old shell (now Prosperity)',
				id = 44758,
				start = '2020-02-09',
				['end'] = '2022-10-03',
			},
		},
		prosperity = {
			{
				label = 'Current shell',
				id = 44758,
				start = '2022-10-14',
				['end'] = '',
			},
			{
				label = 'Old shell (sold to PimpChu)',
				id = 11162,
				start = '2021-10-16',
				['end'] = '2022-10-14',
			},
			{
				label = 'Older shell (now Cry of the Lost)',
				id = 44751,
				start = '2020-02-09',
				['end'] = '2021-10-16',
			},
		},
		endurance = {
			{
				label = 'Current shell',
				id = 12645,
				start = '2024-05-15',
				['end'] = '',
			},
			{
				label = 'Old shell (now Serenity)',
				id = 14052,
				start = '2022-08-03',
				['end'] = '2024-05-15',
			},
		},
		valour = {
			{
				label = 'Current shell',
				id = 26885,
				start = '2023-12-31',
				['end'] = '',
			},
		},
		serenity = {
			{
				label = 'Current shell',
				id = 14052,
				start = '2024-05-15',
				['end'] = '',
			},
		},
		peace = {
			{
				label = 'Current shell',
				id = 18714,
				start = '2022-07-16',
				['end'] = '',
			},
		},
	},
}