打开/关闭菜单
打开/关闭外观设置菜单
打开/关闭个人菜单
未登录
未登录用户的IP地址会在进行任意编辑后公开展示。

本站正在进行早期测试,目前仍存在许多内容的缺失。

模块: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