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

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

模块:UnlockBook

来自星砂岛百科

概述

UnlockBook 提供解锁类书本条目的数据读取与展示辅助,供 Template:Infobox unlockbook 调用。

当前数据来自 `数据:UnlockBook/unlockbook_index.json` 与 `数据:UnlockBook/unlockbook_target_index.json` 两页,后者用于去重解锁目标,控制单页大小。

用法

读取字段:

  • {{#invoke:UnlockBook|getField|西番柿炖牛脯食谱|type_display}}

渲染主解锁对象:

  • {{#invoke:UnlockBook|targetSummary|西番柿炖牛脯食谱}}

渲染完整解锁清单:

  • {{#invoke:UnlockBook|targetList|基础建造手册}}

渲染对应设备:

  • {{#invoke:UnlockBook|stationList|弓箭包}}

主要函数

  • getField:读取基础字段。
  • targetSummary:渲染主解锁对象摘要。
  • targetList:渲染完整解锁清单。
  • stationList:渲染对应设备列表。

local common = require('Module:Common')
local css = require('Module:CSS')
local item_common = require('Module:ItemCommon')
local item = require('Module:Item')

local p = {}

local FIELD_MAP = {
    type_display = 'td',
    rarity = 'r',
    base_value = 'bv',
    sell_price = 'sp',
    max_stack = 'ms',
    origin = 'o',
    locked_origin = 'lo',
    use_description = 'u',
    book_family_display = 'fd',
    unlock_target_type_display = 'ud',
    unlock_target_count = 'c',
    unlock_station_hint = 'h',
    unlock_source_description = 'sd',
    target_keys = 'tk',
    station_ids = 'si',
}

local data_cache
local target_cache
local mapping_cache

local function load_data()
    if data_cache then
        return
    end
    data_cache, mapping_cache = item_common.loadDomainData('数据:UnlockBook/unlockbook_index.json')
    target_cache = common.loadJsonData('数据:UnlockBook/unlockbook_target_index.json') or {}
end

local function find_record(key)
    load_data()
    return item_common.findRecord(data_cache, mapping_cache, key)
end

local function get_record_from_frame(frame)
    return find_record(common.getArg(frame, 1, ''))
end

local function get_record_value(record, key, field)
    if type(record) ~= 'table' then
        return nil
    end
    if record[field] ~= nil then
        return record[field]
    end
    local mapped = FIELD_MAP[field]
    if mapped then
        return record[mapped]
    end
    if field == 'id' or field == 'name' or field == 'name_en' then
        return item_common.getIdentityField(record, key, field)
    end
    return nil
end

local function split_target_key(target_key)
    local resolved = common.trim(target_key)
    if resolved == '' then
        return '', ''
    end
    local kind, target_id = mw.ustring.match(resolved, '^(.-)::(.*)$')
    if not kind then
        return '', resolved
    end
    return common.trim(kind), common.trim(target_id)
end

local function render_item_card(frame, item_id, count, css_class)
    local resolved_id = common.trim(item_id)
    if resolved_id == '' then
        return ''
    end

    local args = { resolved_id }
    if count and tonumber(count) and tonumber(count) > 1 then
        args[2] = tostring(count)
    end
    if common.trim(css_class) ~= '' then
        args.class = css_class
    end

    local output = item.renderItemWithArgs(frame, args)
    return common.trim(output) ~= '' and output or ''
end

local function resolve_target_entry(target_key)
    load_data()

    local kind, target_id = split_target_key(target_key)
    local target = type(target_cache) == 'table' and target_cache[target_key] or nil
    if type(target) ~= 'table' then
        return {
            kind = kind,
            id = target_id,
            name = target_id,
            item_id = '',
            result_count = 0,
        }
    end

    return {
        kind = kind,
        id = target_id,
        name = common.trim(target.n or target_id),
        item_id = common.trim(target.i or ''),
        result_count = tonumber(target.c or 0) or 0,
    }
end

local function get_target_entries(record)
    local keys = get_record_value(record, nil, 'target_keys')
    if type(keys) ~= 'table' or #keys == 0 then
        return {}
    end

    local entries = {}
    for _, target_key in ipairs(keys) do
        local entry = resolve_target_entry(target_key)
        if type(entry) == 'table' then
            entries[#entries + 1] = entry
        end
    end
    return entries
end

local function get_station_ids(record)
    local station_ids = get_record_value(record, nil, 'station_ids')
    if type(station_ids) ~= 'table' then
        return {}
    end
    return station_ids
end

local function render_plain_target(entry, show_id)
    local display_name = common.trim(entry.name or entry.id or '')
    if display_name == '' then
        return ''
    end

    local text = mw.text.encode(display_name)
    if show_id and common.trim(entry.item_id or '') == '' then
        local target_id = common.trim(entry.id or '')
        if target_id ~= '' then
            text = text .. ' <span class="unlockbook-target-id"><code>' .. mw.text.encode(target_id) .. '</code></span>'
        end
    end

    return text
end

local function render_target_entry(frame, entry, css_class, show_id)
    if type(entry) ~= 'table' then
        return ''
    end

    local count = tonumber(entry.result_count or 0) or 0
    local card = render_item_card(frame, entry.item_id, count, css_class)
    if card ~= '' then
        return card
    end

    return render_plain_target(entry, show_id)
end

local function render_station_entry(frame, station_id)
    local resolved_id = common.trim(station_id)
    if resolved_id == '' then
        return ''
    end

    local card = render_item_card(frame, resolved_id, nil, 'block')
    if card ~= '' then
        return card
    end

    return mw.text.encode(resolved_id)
end

local function any_item_entry(entries)
    if type(entries) ~= 'table' then
        return false
    end
    for _, entry in ipairs(entries) do
        if type(entry) == 'table' and common.trim(entry.item_id or entry.id or '') ~= '' then
            return true
        end
    end
    return false
end

local function with_item_css(entries, text)
    if common.trim(text) == '' then
        return ''
    end
    if any_item_entry(entries) then
        return (css.quickCall('Item') or '') .. text
    end
    return text
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 == 'image' then
        local item_id = common.trim(get_record_value(record, key, 'id') or '')
        if item_id == '' then
            return ''
        end
        local image_name = item_id .. '.png'
        if common.filePageExists(image_name) then
            return image_name
        end
        return ''
    end

    local value = get_record_value(record, key, field)
    if type(value) == 'table' then
        return common.toText(value)
    end

    return common.toText(value)
end

function p.targetSummary(frame)
    local record = get_record_from_frame(frame)
    if not record then
        return ''
    end

    local targets = get_target_entries(record)
    if #targets == 0 then
        return common.trim(get_record_value(record, nil, 'unlock_station_hint') or '')
    end

    local primary = render_target_entry(frame, targets[1], 'block', false)
    if primary == '' then
        return ''
    end

    local total_count = tonumber(get_record_value(record, nil, 'unlock_target_count') or #targets) or #targets
    local more_count = math.max(total_count - 1, 0)
    if more_count <= 0 then
        return with_item_css({ targets[1] }, primary)
    end

    local out = {}
    out[#out + 1] = primary
    out[#out + 1] = ('<div class="unlockbook-target-summary-note">另含 %d 项</div>'):format(more_count)
    return with_item_css({ targets[1] }, table.concat(out))
end

function p.targetList(frame)
    local record = get_record_from_frame(frame)
    if not record then
        return ''
    end

    local targets = get_target_entries(record)
    if #targets == 0 then
        return ''
    end

    local out = {}
    out[#out + 1] = '<ul class="unlockbook-target-list">'
    for _, entry in ipairs(targets) do
        local rendered = render_target_entry(frame, entry, 'block', true)
        if rendered ~= '' then
            out[#out + 1] = '<li>' .. rendered .. '</li>'
        end
    end
    out[#out + 1] = '</ul>'
    return with_item_css(targets, table.concat(out))
end

function p.stationList(frame)
    local record = get_record_from_frame(frame)
    if not record then
        return ''
    end

    local station_ids = get_station_ids(record)
    if #station_ids == 0 then
        return ''
    end

    local parts = {}
    local entries = {}
    for _, station_id in ipairs(station_ids) do
        local rendered = render_station_entry(frame, station_id)
        if rendered ~= '' then
            parts[#parts + 1] = rendered
            entries[#entries + 1] = {
                id = station_id,
                item_id = station_id,
            }
        end
    end
    if #parts == 0 then
        return ''
    end

    return with_item_css(entries, table.concat(parts))
end

return p