模块:Achievement
来自星砂岛百科
更多操作
概述
Achievement 提供成就域的数据读取、奖励摘要与阶段表格渲染,供 {{Infobox achievement}} 与 {{AchievementLevels}} 调用。
用法
{{#invoke:Achievement|getField|岛上的印记|category_display}}
{{#invoke:Achievement|getField|岛上的印记|reward_total_summary}}
{{#invoke:Achievement|overviewBlocks|岛上的印记}}
{{#invoke:Achievement|levelTable|岛上的印记}}
函数
getField:读取成就字段,默认查当前页面标题。overviewBlocks:输出解锁说明、奖励总览与关联玩法区块。levelSummary:返回阶段标题摘要。levelTable:渲染完整阶段表。
页面装配
{{Infobox achievement}}
{{AchievementLevels}}
数据来源
local common = require('Module:Common')
local item_common = require('Module:ItemCommon')
local item = require('Module:Item')
local css = require('Module:CSS')
local p = {}
local FIELD_MAP = {
description = 'd',
ui_type = 'ut',
category_display = 'cd',
order_priority = 'op',
auto_unlock = 'au',
unlock_condition_summary = 'uc',
reward_summary = 'rs',
icon = 'ic',
background_image = 'bg',
related_systems = 'sy',
related_items = 'ri',
levels = 'lv',
}
local LEVEL_FIELD_MAP = {
title = 't',
condition_text = 'c',
reward_summary = 'r',
reward_items = 'i',
reward_currencies = 'cy',
always_active = 'a',
}
local data_cache
local mapping_cache
local function default_mapping()
return {
name_to_id = {},
id_to_name = {},
aliases = {},
overrides = {
name_to_id = {},
aliases = {},
},
}
end
local function unwrap_index(raw)
if type(raw) ~= 'table' then
return {}
end
if type(raw.by_name) == 'table' then
return raw.by_name
end
return raw
end
local function load_data()
if data_cache then
return
end
data_cache = unwrap_index(common.loadJsonData('数据:Achievement/achievement_index.json') or {})
mapping_cache = common.loadJsonData('数据:Achievement/achievement_mapping.json') or default_mapping()
end
local function find_record(key)
load_data()
return item_common.findRecord(data_cache, mapping_cache, key)
end
local function get_record_value(record, key, field)
if type(record) ~= 'table' then
return nil
end
if field == 'id' or field == 'name' or field == 'name_en' then
return item_common.getIdentityField(record, key, field)
end
if record[field] ~= nil then
return record[field]
end
local mapped = FIELD_MAP[field]
if mapped then
return record[mapped]
end
return nil
end
local function get_level_value(level, field)
if type(level) ~= 'table' then
return nil
end
if level[field] ~= nil then
return level[field]
end
local mapped = LEVEL_FIELD_MAP[field]
if mapped then
return level[mapped]
end
return nil
end
local function normalize_bool(value)
if value == true or value == 'true' or value == '1' or value == 1 then
return '是'
end
if value == false or value == 'false' or value == '0' or value == 0 then
return '否'
end
return common.toText(value)
end
local function get_levels(record)
local levels = get_record_value(record, nil, 'levels')
if type(levels) ~= 'table' then
return {}
end
local out = {}
for _, level in ipairs(levels) do
if type(level) == 'table' then
out[#out + 1] = level
end
end
return out
end
local function sum_currency_rewards(levels)
local totals = {}
for _, level in ipairs(levels) do
local rewards = get_level_value(level, 'reward_currencies')
if type(rewards) == 'table' then
for _, reward in ipairs(rewards) do
if type(reward) == 'table' then
local currency_id = common.trim(reward.type or reward.id or reward.currency_id or '')
local value = tonumber(reward.value or reward.count or 0) or 0
if currency_id ~= '' and value ~= 0 then
totals[currency_id] = (totals[currency_id] or 0) + value
end
end
end
end
end
return totals
end
local function currency_label(currency_id)
local normalized = common.normalizeKey(currency_id)
if normalized == 'currency.default' then
return '金币'
end
if normalized == 'currency.achievementpoints' then
return '星砂'
end
if normalized == 'currency.achievementexp' then
return '成就经验'
end
return common.trim(currency_id)
end
local function currency_template(currency_id)
local normalized = common.normalizeKey(currency_id)
if normalized == 'currency.default' then
return 'Gold'
end
if normalized == 'currency.exp' or normalized == 'currency.achievementexp' then
return 'Exp'
end
if normalized == 'item.gamecoin' or normalized == 'currency.star' then
return 'Star'
end
return ''
end
local function render_currency(currency_id, value)
local amount = tonumber(value or 0) or 0
if amount == 0 then
return ''
end
local template = currency_template(currency_id)
if template ~= '' then
return ('{{%s|%s}}'):format(template, tostring(amount))
end
return mw.text.encode(currency_label(currency_id)) .. ' x' .. tostring(amount)
end
local function render_item_reward(frame, reward)
if type(reward) ~= 'table' then
return ''
end
local item_id = common.trim(reward.item_id or reward.id or '')
if item_id == '' then
return ''
end
local args = { item_id }
local count = tonumber(reward.count or reward.value or 0) or 0
if count > 1 then
args[2] = tostring(count)
end
return item.renderItemWithArgs(frame, args)
end
local function render_reward_inline(frame, level)
local reward_summary = common.trim(common.toText(get_level_value(level, 'reward_summary')))
if reward_summary ~= '' then
return reward_summary
end
local parts = {}
local reward_currencies = get_level_value(level, 'reward_currencies')
if type(reward_currencies) == 'table' then
for _, reward in ipairs(reward_currencies) do
if type(reward) == 'table' then
local rendered = render_currency(reward.type or reward.id or reward.currency_id, reward.value or reward.count)
if rendered ~= '' then
parts[#parts + 1] = rendered
end
end
end
end
local reward_items = get_level_value(level, 'reward_items')
if type(reward_items) == 'table' then
for _, reward in ipairs(reward_items) do
local rendered = render_item_reward(frame, reward)
if rendered ~= '' then
parts[#parts + 1] = rendered
end
end
end
return table.concat(parts, '、')
end
local function summarize_condition_text(text)
local value = common.trim(common.toText(text))
if value == '' then
return ''
end
value = value:gsub(';', ';<br>')
value = value:gsub(' 或 ', '<br>或 ')
return value
end
function p.findRecord(key)
return find_record(key)
end
function p.getField(frame)
local key = common.getArg(frame, 1, '')
local field = common.getArg(frame, 2, '')
if field == '' then
return ''
end
local record = find_record(key)
if not record then
return ''
end
if field == 'auto_unlock_display' then
return normalize_bool(get_record_value(record, key, 'auto_unlock'))
end
if field == 'stage_count' then
return tostring(#get_levels(record))
end
if field == 'reward_total_summary' then
local explicit = common.trim(common.toText(get_record_value(record, key, 'reward_summary')))
if explicit ~= '' then
return explicit
end
local totals = sum_currency_rewards(get_levels(record))
local parts = {}
for currency_id, value in pairs(totals) do
parts[#parts + 1] = render_currency(currency_id, value)
end
table.sort(parts)
return table.concat(parts, '、')
end
if field == 'related_systems_display' then
return common.toText(get_record_value(record, key, 'related_systems'))
end
if field == 'unlock_condition_display' then
return summarize_condition_text(get_record_value(record, key, 'unlock_condition_summary'))
end
if field == 'image' then
local image_name = common.trim(common.toText(get_record_value(record, key, 'icon')))
if image_name ~= '' and common.filePageExists(image_name) then
return image_name
end
local item_id = common.trim(common.toText(get_record_value(record, key, 'id')))
if item_id ~= '' then
local fallback = item_id .. '.png'
if common.filePageExists(fallback) then
return fallback
end
end
return ''
end
return common.toText(get_record_value(record, key, field))
end
function p.levelSummary(frame)
local record = find_record(common.getArg(frame, 1, ''))
if not record then
return ''
end
local levels = get_levels(record)
if #levels == 0 then
return ''
end
local parts = {}
for _, level in ipairs(levels) do
local title = common.trim(common.toText(get_level_value(level, 'title')))
if title ~= '' then
parts[#parts + 1] = title
end
end
return table.concat(parts, ';')
end
function p.overviewBlocks(frame)
local record = find_record(common.getArg(frame, 1, ''))
if not record then
return ''
end
local blocks = {}
local unlock_text = summarize_condition_text(get_record_value(record, nil, 'unlock_condition_summary'))
if unlock_text ~= '' then
blocks[#blocks + 1] = '<h2>解锁说明</h2>\n' .. unlock_text
end
local reward_text = common.trim(common.toText(p.getField({ args = { common.getArg(frame, 1, ''), 'reward_total_summary' } })))
if reward_text ~= '' then
blocks[#blocks + 1] = '<h2>奖励总览</h2>\n' .. reward_text
end
local systems_text = common.trim(common.toText(get_record_value(record, nil, 'related_systems')))
if systems_text ~= '' then
blocks[#blocks + 1] = '<h2>关联玩法</h2>\n' .. systems_text
end
return table.concat(blocks, '\n')
end
function p.levelTable(frame)
local record = find_record(common.getArg(frame, 1, ''))
if not record then
return ''
end
local levels = get_levels(record)
if #levels == 0 then
return ''
end
local out = {}
out[#out + 1] = css.quickCall('Item') or ''
out[#out + 1] = '{| class="wikitable sortable"'
out[#out + 1] = '! 阶段'
out[#out + 1] = '! 目标'
out[#out + 1] = '! 奖励'
out[#out + 1] = '! 状态'
for index, level in ipairs(levels) do
local title = common.trim(common.toText(get_level_value(level, 'title')))
local condition_text = summarize_condition_text(get_level_value(level, 'condition_text'))
local reward_text = render_reward_inline(frame, level)
local active_text = normalize_bool(get_level_value(level, 'always_active'))
out[#out + 1] = '|-'
out[#out + 1] = '| ' .. tostring(index)
out[#out + 1] = '| ' .. (title ~= '' and title or '—')
out[#out + 1] = '| ' .. (condition_text ~= '' and condition_text or '—')
out[#out + 1] = '| ' .. (reward_text ~= '' and reward_text or '—')
out[#out + 1] = '| ' .. (active_text ~= '' and active_text or '—')
end
out[#out + 1] = '|}'
return table.concat(out, '\n')
end
return p