Module:NBVA Points

From zunagi

Revision as of 08:42, 18 September 2026 by Lee G (talk | contribs)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

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

local p = {}

-- NBVA's own points scheme (as printed on the points-scheme image supplied 2026-09-14), a
-- plain place x division lookup table -- unlike Module:ABVRS Points, there is no single
-- base(place) x multiplier(division) formula that reproduces every printed value exactly
-- (checked: a per-division multiplier reconstructed off the AAA column and rounded gets
-- most cells right but not all, e.g. 2nd/BBB prints as 51 where a clean 0.112 multiplier
-- would round to 50) -- so this stores the 12 x 6 grid literally instead of reverse-
-- engineering a formula the source doesn't actually follow everywhere.
local points = {
	[1]  = { 500, 225, 113, 56, 28, 14 },
	[2]  = { 450, 203, 101, 51, 25, 13 },
	[3]  = { 360, 162, 81, 41, 20, 10 },
	[4]  = { 360, 162, 81, 41, 20, 10 },
	[5]  = { 275, 124, 62, 31, 15, 8 },
	[6]  = { 275, 124, 62, 31, 15, 8 },
	[7]  = { 275, 124, 62, 31, 15, 8 },
	[8]  = { 275, 124, 62, 31, 15, 8 },
	[9]  = { 190, 86, 43, 21, 11, 5 },
	[10] = { 190, 86, 43, 21, 11, 5 },
	[11] = { 145, 65, 32, 16, 8, 4 },
	[12] = { 145, 65, 32, 16, 8, 4 },
}

-- Division 1..6 column labels, left to right, matching the image's header row exactly.
local divisionLabel = { "AAA", "AA", "A", "BBB", "BB", "B" }

-- Draw size -> number of "Place" rows to show. Same field/values as Module:ABVRS Points'
-- own drawSizes table (this is driven by the event's existing abvrs_draw_size field, not a
-- separate NBVA-only one) -- but the points scheme above only has printed values for a
-- 12-team draw. A 16-team NBVA event still renders 16 rows (so the table's shape matches
-- what abvrs_draw_size asked for); places 13-16 just come back blank until NBVA publishes
-- a scheme that covers them.
local drawSizes = { ["12"] = 12, ["12 teams"] = 12, ["16"] = 16, ["16 teams"] = 16 }

local ordinal = {
	[1] = "1st", [2] = "2nd", [3] = "3rd", [4] = "4th", [5] = "5th", [6] = "6th",
	[7] = "7th", [8] = "8th", [9] = "9th", [10] = "10th", [11] = "11th", [12] = "12th",
	[13] = "13th", [14] = "14th", [15] = "15th", [16] = "16th",
}

local function trim(s)
	if not s then return nil end
	s = mw.text.trim(s)
	if s == "" then return nil end
	return s
end

-- Prefers org_code, falls back to the deprecated region_code -- deliberately mirrors
-- Module:Beach Org's own resolveCode rather than requiring that module, so this module has
-- no load-order dependency on it. Keep the two in sync by hand if the org_code/region_code
-- fallback rule ever changes.
local function resolveCode(args)
	return trim(args.org_code) or trim(args.region_code) or ""
end

-- {{#invoke:NBVA Points|table|org_code=...|region_code=...|draw_size=...|divisions=...}}
-- Shows the "NBVA Points on Offer" table only when the event's resolved org is NBVA --
-- there's no separate on/off flag, it's entirely derived from the same org_code/
-- region_code fields the Organisation row already uses. draw_size and divisions are the
-- event's existing abvrs_draw_size / abvrs_divisions fields, passed straight through by
-- the template rather than duplicated as NBVA-only fields.
function p.table(frame)
	local args = frame.args

	local code = resolveCode(args)
	if string.lower(code) ~= "nbva" then
		return ""
	end

	local drawSizeRaw = trim(args.draw_size)
	local divisionsRaw = trim(args.divisions)

	if not drawSizeRaw or not divisionsRaw then
		return ""
	end

	local drawSize = drawSizes[string.lower(drawSizeRaw)]
	local divisions = tonumber(divisionsRaw)

	if not drawSize or not divisions then
		return ""
	end

	divisions = math.floor(divisions)
	if divisions < 1 then
		return ""
	end

	-- Subheading reads "Division 1 is an NBVA AAA event with a 12-team draw" -- same
	-- pattern as the ABVRS table's own subheading (see Module:ABVRS Points), just without
	-- a star rating to plug in since NBVA divisions aren't star-rated.
	local topLabel = divisionLabel[1] or ""
	local article = "a"
	if topLabel:match("^[AEIOUaeiou]") then
		article = "an"
	end
	local tab1Text = "Division 1 is " .. article .. " NBVA " .. topLabel .. " event with a " .. drawSize .. "-team draw"

	-- Mobile tabs always split into "first 3 divisions" / "the rest", so tab 2 always
	-- starts at Division 4. Only computed when a 4th division actually exists - for a
	-- 3-or-fewer-division event both tabs show the same columns, so there's nothing to
	-- swap the subheading to (the JS leaves it alone when this attribute is absent).
	local tab2Text = nil
	if divisions >= 4 then
		local tab2Label = divisionLabel[4] or ""
		if tab2Label ~= "" then
			local tab2Article = "a"
			if tab2Label:match("^[AEIOUaeiou]") then
				tab2Article = "an"
			end
			tab2Text = "Division 4 is " .. tab2Article .. " NBVA " .. tab2Label .. " event with a " .. drawSize .. "-team draw"
		end
	end

	local out = mw.html.create("")

	out:tag("div")
		:addClass("zunagi-points-heading")
		:css("font-size", "1.1em")
		:css("font-weight", "bold")
		:css("margin", "1em 0 0")
		:wikitext("NBVA Points on Offer")

	local subheading = out:tag("div")
		:addClass("zunagi-points-subheading")
		:css("font-size", "0.8em")
		:css("color", "#666")
		:css("margin", "4px 0 12px 0")
		:attr("data-tab1-text", tab1Text)
		:wikitext(tab1Text)

	if tab2Text then
		subheading:attr("data-tab2-text", tab2Text)
	end


	-- Same classes as the ABVRS table's wrapper/table (see "Deliberately reuses the ABVRS
	-- table's CSS classes" above) -- this is what makes the existing mobile
	-- equal-column-width fix in MediaWiki:Common.js apply here too, with no JS changes.
	local wrapper = out:tag("div")
		:addClass("zunagi-points-table-wrapper")
		:css("overflow-x", "auto")
		:css("width", "100%")
		:css("box-sizing", "border-box")

	local columns = divisions + 1
	local colWidth = string.format("%.4f%%", 100 / columns)

	local tbl = wrapper:tag("table")
		:addClass("wikitable zunagi-points-table")
		:css("width", "100%")
		:css("margin-top", "0")
		:css("border-collapse", "collapse")
		:css("table-layout", "fixed")
		:css("font-size", "1em")
		:css("border-top", "1px solid #c8ccd1")
		:css("border-bottom", "1px solid #c8ccd1")

	local headerRow = tbl:tag("tr")
	headerRow:tag("th")
		:css("padding", "6px 10px")
		:css("background-color", "#f8f9fa")
		:css("border", "1px solid #eaecf0")
		:css("width", colWidth)
		:wikitext("Place")
	for d = 1, divisions do
		headerRow:tag("th")
			:css("padding", "6px 14px")
			:css("background-color", "#f8f9fa")
			:css("border", "1px solid #eaecf0")
			:css("width", colWidth)
			:css("text-align", "center")
			:css("white-space", "nowrap")
			:wikitext(divisionLabel[d] or "")
	end

	for place = 1, drawSize do
		local row = tbl:tag("tr")
		row:tag("th")
			:css("padding", "6px 10px")
			:css("background-color", "#f8f9fa")
			:css("border", "1px solid #eaecf0")
			:css("width", colWidth)
			:wikitext(ordinal[place] or (place .. "th"))
		local placeRow = points[place]
		for d = 1, divisions do
			local cell = row:tag("td")
				:css("text-align", "center")
				:css("padding", "6px 14px")
				:css("background-color", "#fff")
				:css("border", "1px solid #eaecf0")
				:css("width", colWidth)
			if placeRow and placeRow[d] then
				cell:wikitext(tostring(placeRow[d]))
			end
		end
	end

	return tostring(out)
end

return p