跳转到内容

Module:定数表

来自Bleap Wiki

此模块的文档可以在Module:定数表/doc创建

local p = {}

-- 数据页: 曲目列表 (含定数)
local DATA_TITLE = '模板:曲目列表.json'
local validator = require('模块:数据页校验')
local MIN_CONST = 9.0

local DIFF_CLASS = { CASUAL = 'cas', TOUGH = 'tou', INSANE = 'ins', PRO = 'pro' }
local DIFF_RANK = { CASUAL = 1, TOUGH = 2, INSANE = 3, PRO = 4 }

local function esc(s)
	return (s:gsub('|', '|'))
end

-- 链接目标: # 是 MediaWiki 的锚点分隔符, 标题里一律换成全角 #
-- 优先用「链接名」字段; 没有就回退到曲名并自动替换 (双保险)
-- 注意: 光用 <nowiki>&#35;</nowiki> 之类的转义救不了 —— # 在标题解析阶段就被切走了
local function pageName(song, suffix)
	local n = song['链接名'] or song['曲名']
	if suffix then
		n = n .. '(' .. suffix .. ')'
	end
	return (n:gsub('#', '#'))
end

local function langWrap(song)
	local lang = song['lang']
	if lang == 'ja' then
		return '{{lang|ja|' .. esc(song['曲名']) .. '}}'
	elseif lang == 'zh-Hant' then
		return '{{lang|zh-Hant|' .. esc(song['曲名']) .. '}}'
	end
	return esc(song['曲名'])
end

function p.render(frame)
	local data, dataErr = validator.load(DATA_TITLE)
	if not data then
		return dataErr
	end

	-- 收集 >= MIN_CONST 的条目, 按定数分档
	local steps = {}
	for _, song in ipairs(data.songs or {}) do
		local consts = song['定数'] or {}
		for _, diff in ipairs(song['难度'] or {}) do
			local c = consts[diff]
			if type(c) == 'number' and c >= MIN_CONST then
				local key = string.format('%.1f', c)
				steps[key] = steps[key] or {}
				table.insert(steps[key], { song = song, diff = diff })
			end
		end
	end

	-- 定数从高到低, 每 0.1 一档连续列到 MIN_CONST
	local keys = {}
	for key in pairs(steps) do
		table.insert(keys, tonumber(key))
	end
	table.sort(keys, function(a, b) return a > b end)
	local maxConst = keys[1] or MIN_CONST

	local out = {}
	table.insert(out, '{| class="wikitable" style="width:100%"')
	for i = math.floor(maxConst * 10 + 0.5), math.floor(MIN_CONST * 10 + 0.5), -1 do
		local key = string.format('%.1f', i / 10)
		local items = steps[key]

		if not items then
			table.insert(out, '|-\n| style="width:60px;text-align:center;font-size:135%;font-weight:bold;color:#999" | '
				.. key .. ' || <span style="color:#999">—</span>')
		else
			-- 难度从低到高, 同难度按曲名
			table.sort(items, function(a, b)
				local ra = DIFF_RANK[a.diff] or 9
				local rb = DIFF_RANK[b.diff] or 9
				if ra ~= rb then
					return ra < rb
				end
				return a.song['曲名'] < b.song['曲名']
			end)

			local tiles = {}
			for _, it in ipairs(items) do
				local song = it.song
				local name = song['曲名']
				local art = (song['曲绘'] or name):gsub(' ', '_')
				local cls = DIFF_CLASS[it.diff] or 'unknown'
				local link = '曲目:' .. esc(pageName(song))
				local tile = '<div style="display:inline-block;text-align:center;margin:3px 6px;vertical-align:top;width:124px;font-size:88%">'
					.. '[[File:曲绘-' .. esc(art) .. '.png|96px|link=' .. link .. ']]<br>'
					.. '[[' .. link .. '|' .. langWrap(song) .. ']]<br>'
					.. ' {{难度|' .. it.diff .. '}}'
					.. '</div>'
				table.insert(tiles, tile)
			end

			table.insert(out, '|-\n| style="width:60px;text-align:center;font-size:135%;font-weight:bold" | '
				.. key .. ' || ' .. table.concat(tiles))
		end
	end
	table.insert(out, '|}')

	-- Scribunto 返回文本中的 {{模板}} 不会被自动展开, 必须显式 preprocess
	return frame:preprocess('__NOCONTENTCONVERT__\n__NOTITLECONVERT__\n' .. table.concat(out, '\n'))
end

function p.renderDetail(frame)
	local data, dataErr = validator.load(DATA_TITLE)
	if not data then
		return dataErr
	end

	local DIFFS = { 'CASUAL', 'TOUGH', 'INSANE', 'PRO' }

	local out = {}
	table.insert(out, '{| class="wikitable sortable empty-last" style="width:100%;text-align:center"')
	table.insert(out, '! 曲名 !! 曲包 !! {{难度|CASUAL}} !! {{难度|TOUGH}} !! {{难度|INSANE}} !! {{难度|PRO}}')

	for _, song in ipairs(data.songs or {}) do
		local name = song['曲名']
		local pack = song['曲包'] or ''
		local link = '曲目:' .. esc(pageName(song))
		local cells = {}
		table.insert(cells, '[[' .. link .. '|' .. langWrap(song) .. ']]')
		if pack ~= '' then
			table.insert(cells, '[[曲包:' .. esc(pack) .. '|' .. esc(pack) .. ']]')
		else
			table.insert(cells, '—')
		end
		local consts = song['定数'] or {}
		for _, diff in ipairs(DIFFS) do
			local c = consts[diff]
			if type(c) == 'number' then
				table.insert(cells, string.format('%.1f', c))
			else
				table.insert(cells, '<span class="bleap-sort-empty">—</span>')
			end
		end
		table.insert(out, '|-\n| ' .. table.concat(cells, ' || '))
	end
	table.insert(out, '|}')

	return frame:preprocess('__NOCONTENTCONVERT__\n__NOTITLECONVERT__\n' .. table.concat(out, '\n'))
end

return p