打开/关闭菜单
8
231
3
1270
夜幕之下 Wiki - Reign of Nightfall 中文资料站
打开/关闭外观设置菜单
打开/关闭个人菜单
未登录
未登录用户的IP地址会在进行任意编辑后公开展示。

模块:StyleCollectionSandbox

来自夜幕之下 Wiki - Reign of Nightfall 中文资料站

此模块的文档可以在模块:StyleCollectionSandbox/doc创建

local p = {}

local mockDirectusCard = {
    character_name = '幽灵',
    style_name = '复仇童谣',
    source_style_id = '13001025',
    collection_type = 4,
    collection_type_name = '栖影',
    collection_refine_pool = 1025,
    collection_level = 15,
    collection_material = {
        tier1 = { id = '11210041', name = '栖影结晶Ⅰ' },
        tier2 = { id = '11210042', name = '栖影结晶Ⅱ' },
        tier3 = { id = '11210043', name = '栖影结晶Ⅲ' },
        refine = { id = '11220001', name = '重构之扉' },
    },
    collection_fixed_slots = {
        { position = 1, label = '映像Ⅰ', icon = 'equip_icon_02_01', attrs = { 27, 28, 23 } },
        { position = 2, label = '映像Ⅱ', icon = 'equip_icon_02_02', attrs = { 28, 29, 8 } },
        { position = 3, label = '映像Ⅲ', icon = 'equip_icon_02_03', attrs = { 29, 27, 12 } },
    },
    collection_refine_terms = {
        { effect_id = 1, name = '磷火', effect_type = 2, effect_value = '102573', quality = 4, first_weight = 0, normal_weight = 350, guarantee_count = 10, description = '大招释放时,附加每秒30%攻击力的持续伤害,持续10秒。' },
        { effect_id = 2, name = '弱点洞悉', effect_type = 2, effect_value = '501200', quality = 3, first_weight = 0, normal_weight = 350, guarantee_count = 0, description = '场上最多负面buff的敌方每具备一个负面,自身爆伤+8%,上限40%。' },
        { effect_id = 3, name = '攻其不备', effect_type = 2, effect_value = '501203', quality = 3, first_weight = 0, normal_weight = 350, guarantee_count = 0, description = '攻击具备负面buff的敌方时,伤害增加10%。' },
        { effect_id = 4, name = '资源优化', effect_type = 2, effect_value = '501100', quality = 3, first_weight = 0, normal_weight = 350, guarantee_count = 0, description = '首次释放大招时,费用-1。' },
        { effect_id = 5, name = '暴击', effect_type = 1, effect_value = '8#400', quality = 2, first_weight = 0, normal_weight = 800, guarantee_count = 0 },
        { effect_id = 6, name = '爆伤', effect_type = 1, effect_value = '9#800', quality = 2, first_weight = 0, normal_weight = 800, guarantee_count = 0 },
        { effect_id = 7, name = '终结技', effect_type = 1, effect_value = '59#1000', quality = 2, first_weight = 0, normal_weight = 800, guarantee_count = 0 },
        { effect_id = 8, name = '增伤', effect_type = 1, effect_value = '12#400', quality = 2, first_weight = 1000, normal_weight = 800, guarantee_count = 0 },
        { effect_id = 9, name = '攻击', effect_type = 1, effect_value = '23#400', quality = 1, first_weight = 0, normal_weight = 1350, guarantee_count = 0 },
        { effect_id = 10, name = '生命', effect_type = 1, effect_value = '21#400', quality = 1, first_weight = 0, normal_weight = 1350, guarantee_count = 0 },
        { effect_id = 11, name = '防御', effect_type = 1, effect_value = '24#400', quality = 1, first_weight = 1000, normal_weight = 1350, guarantee_count = 0 },
        { effect_id = 12, name = '增伤', effect_type = 1, effect_value = '12#300', quality = 1, first_weight = 1000, normal_weight = 1350, guarantee_count = 0 },
    },
}

local attrMeta = {
    [8] = { name = '暴击率', kind = 'percent', values = { [0]=0, [1]=224, [2]=448, [3]=672, [4]=896, [5]=1120, [6]=1344, [7]=1568, [8]=1792, [9]=2016, [10]=2240, [11]=2464, [12]=2688, [13]=2912, [14]=3136, [15]=3360 } },
    [9] = { name = '暴击伤害', kind = 'percent', values = { [0]=0, [1]=448, [2]=896, [3]=1344, [4]=1792, [5]=2240, [6]=2688, [7]=3136, [8]=3584, [9]=4032, [10]=4480, [11]=4928, [12]=5376, [13]=5824, [14]=6272, [15]=6720 } },
    [12] = { name = '伤害加成', kind = 'percent', values = { [0]=0, [1]=243, [2]=486, [3]=729, [4]=972, [5]=1216, [6]=1459, [7]=1702, [8]=1945, [9]=2188, [10]=2432, [11]=2675, [12]=2918, [13]=3161, [14]=3404, [15]=3648 } },
    [21] = { name = '生命加成', kind = 'percent', values = { [0]=0, [1]=280, [2]=560, [3]=840, [4]=1120, [5]=1400, [6]=1680, [7]=1960, [8]=2240, [9]=2520, [10]=2800, [11]=3080, [12]=3360, [13]=3640, [14]=3920, [15]=4200 } },
    [23] = { name = '攻击加成', kind = 'percent', values = { [0]=0, [1]=280, [2]=560, [3]=840, [4]=1120, [5]=1400, [6]=1680, [7]=1960, [8]=2240, [9]=2520, [10]=2800, [11]=3080, [12]=3360, [13]=3640, [14]=3920, [15]=4200 } },
    [24] = { name = '防御加成', kind = 'percent', values = { [0]=0, [1]=280, [2]=560, [3]=840, [4]=1120, [5]=1400, [6]=1680, [7]=1960, [8]=2240, [9]=2520, [10]=2800, [11]=3080, [12]=3360, [13]=3640, [14]=3920, [15]=4200 } },
    [27] = { name = '固定生命', kind = 'flat', values = { [0]=0, [1]=270, [2]=540, [3]=810, [4]=1080, [5]=1350, [6]=1620, [7]=1890, [8]=2160, [9]=2430, [10]=2700, [11]=2970, [12]=3240, [13]=3510, [14]=3780, [15]=4050 } },
    [28] = { name = '固定攻击', kind = 'flat', values = { [0]=0, [1]=90, [2]=180, [3]=270, [4]=360, [5]=450, [6]=540, [7]=630, [8]=720, [9]=810, [10]=900, [11]=990, [12]=1080, [13]=1170, [14]=1260, [15]=1350 } },
    [29] = { name = '固定防御', kind = 'flat', values = { [0]=0, [1]=90, [2]=180, [3]=270, [4]=360, [5]=450, [6]=540, [7]=630, [8]=720, [9]=810, [10]=900, [11]=990, [12]=1080, [13]=1170, [14]=1260, [15]=1350 } },
    [59] = { name = '终结技伤害加成', kind = 'percent' },
}

local qualityMeta = {
    [1] = { code = 'C', name = '蓝色', class = 'collection_sandbox-quality--c' },
    [2] = { code = 'B', name = '紫色', class = 'collection_sandbox-quality--b' },
    [3] = { code = 'A', name = '金色', class = 'collection_sandbox-quality--a' },
    [4] = { code = 'S', name = '红色专属', class = 'collection_sandbox-quality--s' },
}

local function formatPercent(raw)
    local n = raw / 100
    local text
    if math.floor(n) == n then
        text = string.format('%.0f', n)
    elseif math.floor(n * 10) == n * 10 then
        text = string.format('%.1f', n)
    else
        text = string.format('%.2f', n)
    end
    return '+' .. text .. '%'
end

local function formatValue(attrId, raw)
    local meta = attrMeta[attrId]
    if meta and meta.kind == 'percent' then
        return formatPercent(raw)
    end
    return '+' .. tostring(raw)
end

local function parseEffectValue(value)
    local attrId, raw = tostring(value or ''):match('^(%d+)#(%d+)$')
    if attrId and raw then
        return tonumber(attrId), tonumber(raw)
    end
    return nil, nil
end

local function fixedCounts(card)
    local counts = {}
    for _, slot in ipairs(card.collection_fixed_slots or {}) do
        for _, attrId in ipairs(slot.attrs or {}) do
            counts[attrId] = (counts[attrId] or 0) + 1
        end
    end
    local rows = {}
    for attrId, count in pairs(counts) do
        table.insert(rows, { attr_id = attrId, count = count, meta = attrMeta[attrId] or { name = '属性' .. tostring(attrId), values = {} } })
    end
    table.sort(rows, function(a, b)
        local order = { [27]=1, [28]=2, [29]=3, [23]=4, [21]=5, [24]=6, [8]=7, [9]=8, [12]=9, [13]=10 }
        return (order[a.attr_id] or a.attr_id) < (order[b.attr_id] or b.attr_id)
    end)
    return rows
end

local function addAttrLine(parent, attrId, raw, count)
    local meta = attrMeta[attrId] or { name = '属性' .. tostring(attrId), values = {} }
    local label = meta.name
    if count and count > 1 then
        label = label .. ' ×' .. tostring(count)
    end
    parent:tag('div'):addClass('collection_sandbox-attr')
        :tag('span'):wikitext(label):done()
        :tag('span'):addClass('collection_sandbox-value'):wikitext(formatValue(attrId, raw)):done()
end

local function renderHero(root, card)
    local box = root:tag('div'):addClass('collection_sandbox-hero')
    box:tag('div'):addClass('collection_sandbox-kicker'):wikitext('STYLE COLLECTION / MOCK DIRECTUS')
    box:tag('h1'):addClass('collection_sandbox-title'):wikitext(card.character_name .. ' · ' .. card.style_name .. ' 映像重构原型')
    box:tag('p'):addClass('collection_sandbox-sub'):wikitext('临时 Lua 数据模拟 Directus 返回:cards 只挂映像类型、固定属性槽位/计数,以及重构池词条。当前展示等级为 Lv.' .. tostring(card.collection_level) .. '。')
end

local function renderMockData(root, card)
    local grid = root:tag('div'):addClass('collection_sandbox-grid')
    local panel = grid:tag('div'):addClass('collection_sandbox-panel')
    panel:tag('h2'):addClass('collection_sandbox-h2'):wikitext('模拟 Directus 数据形状')
    panel:tag('div'):addClass('collection_sandbox-data'):wikitext(
        'cards.stylename = ' .. card.style_name .. '\n' ..
        'cards.character = ' .. card.character_name .. '\n' ..
        'cards.source_style_id = ' .. card.source_style_id .. '\n' ..
        'cards.collection_type = ' .. tostring(card.collection_type) .. ' (' .. card.collection_type_name .. ')\n' ..
        'cards.collection_refine_pool = ' .. tostring(card.collection_refine_pool) .. '\n' ..
        'cards.collection_fixed_slots = 3 positions\n' ..
        'cards.collection_refine_terms = 12 terms'
    )

    local cost = grid:tag('div'):addClass('collection_sandbox-panel')
    cost:tag('h2'):addClass('collection_sandbox-h2'):wikitext('映像类型与消耗')
    cost:tag('p'):addClass('collection_sandbox-note'):wikitext(card.collection_type_name .. '系映像使用 ' .. card.collection_material.tier1.name .. ' / ' .. card.collection_material.tier2.name .. ' / ' .. card.collection_material.tier3.name .. '。重构消耗 ' .. card.collection_material.tier3.name .. ' 与 ' .. card.collection_material.refine.name .. '。')
    cost:tag('div'):addClass('collection_sandbox-data'):wikitext('不锁词条:' .. card.collection_material.tier3.name .. ' ×10 + ' .. card.collection_material.refine.name .. ' ×1 + 金币 50000\n锁 1 条:' .. card.collection_material.tier3.name .. ' ×30 + ' .. card.collection_material.refine.name .. ' ×1 + 金币 150000')
end

local function renderSlots(root, card)
    local panel = root:tag('div'):addClass('collection_sandbox-panel collection_sandbox-panel--wide')
    panel:tag('h2'):addClass('collection_sandbox-h2'):wikitext('三段映像固定加成')
    panel:tag('p'):addClass('collection_sandbox-note'):wikitext('每个部位只存属性 ID;具体数值从全局 Lv.0-15 数值表按当前等级计算。')
    local slots = panel:tag('div'):addClass('collection_sandbox-slots')
    local level = card.collection_level
    for _, slot in ipairs(card.collection_fixed_slots or {}) do
        local node = slots:tag('div'):addClass('collection_sandbox-slot')
        node:tag('div'):addClass('collection_sandbox-slot-title'):wikitext(slot.label .. ' · ' .. slot.icon)
        for _, attrId in ipairs(slot.attrs or {}) do
            local meta = attrMeta[attrId]
            addAttrLine(node, attrId, meta.values[level] or 0)
        end
    end
end

local function renderSummary(root, card)
    local panel = root:tag('div'):addClass('collection_sandbox-panel collection_sandbox-panel--wide')
    panel:tag('h2'):addClass('collection_sandbox-h2'):wikitext('聚合结果:属性 × 次数')
    panel:tag('p'):addClass('collection_sandbox-note'):wikitext('重复属性会被聚合;例如固定生命在两个部位出现,就是全局 Lv.' .. tostring(card.collection_level) .. ' 固定生命值 ×2。')
    local list = panel:tag('div'):addClass('collection_sandbox-summary')
    for _, item in ipairs(fixedCounts(card)) do
        local raw = (item.meta.values[card.collection_level] or 0) * item.count
        local node = list:tag('div'):addClass('collection_sandbox-summary-item')
        node:tag('div'):addClass('collection_sandbox-summary-name'):wikitext(item.meta.name .. ' ×' .. tostring(item.count))
        node:tag('div'):addClass('collection_sandbox-summary-value'):wikitext(formatValue(item.attr_id, raw))
        node:tag('div'):addClass('collection_sandbox-summary-formula'):wikitext('Lv.' .. tostring(card.collection_level) .. ' 单值 ' .. formatValue(item.attr_id, item.meta.values[card.collection_level] or 0) .. ' × ' .. tostring(item.count))
    end
end

local function renderTerm(parent, term)
    local quality = qualityMeta[term.quality] or qualityMeta[1]
    local attrId, raw = parseEffectValue(term.effect_value)
    local desc = term.description
    if term.effect_type == 1 and attrId and raw then
        local meta = attrMeta[attrId] or { name = term.name }
        desc = meta.name .. ' ' .. formatValue(attrId, raw)
    end
    local node = parent:tag('div'):addClass('collection_sandbox-term')
    local head = node:tag('div'):addClass('collection_sandbox-term-head')
    head:tag('span')
        :addClass('collection_sandbox-quality ' .. quality.class)
        :wikitext(quality.code)
    local nameClass = term.quality == 4 and 'collection_sandbox-term-name collection_sandbox-exclusive' or 'collection_sandbox-term-name'
    head:tag('span'):addClass(nameClass):wikitext(term.name)
    if term.quality == 4 then
        head:tag('span'):addClass('collection_sandbox-pill'):wikitext('专属')
    end
    if term.first_weight and term.first_weight > 0 then
        head:tag('span'):addClass('collection_sandbox-pill'):wikitext('初始池')
    end
    node:tag('p'):addClass('collection_sandbox-term-desc'):wikitext(desc or '效果描述待接入')
    local meta = 'effect=' .. tostring(term.effect_value) .. ' · normalWeight=' .. tostring(term.normal_weight)
    if term.first_weight and term.first_weight > 0 then
        meta = meta .. ' · firstWeight=' .. tostring(term.first_weight)
    end
    if term.guarantee_count and term.guarantee_count > 0 then
        meta = meta .. ' · guarantee=' .. tostring(term.guarantee_count)
    end
    node:tag('div'):addClass('collection_sandbox-term-meta'):wikitext(meta)
end

local function renderTerms(root, card)
    local panel = root:tag('div'):addClass('collection_sandbox-panel collection_sandbox-panel--wide')
    panel:tag('h2'):addClass('collection_sandbox-h2'):wikitext('重构池 ' .. tostring(card.collection_refine_pool))
    panel:tag('p'):addClass('collection_sandbox-note'):wikitext('当前约定:只有红色 quality=4 词条标为专属。firstWeight 表示首次生成候选,normalWeight 表示后续重构完整池权重。')
    local terms = panel:tag('div'):addClass('collection_sandbox-terms')
    for _, term in ipairs(card.collection_refine_terms or {}) do
        renderTerm(terms, term)
    end
end

function p.render()
    local root = mw.html.create('div'):addClass('collection_sandbox')
    local card = mockDirectusCard
    renderHero(root, card)
    renderMockData(root, card)
    renderSlots(root, card)
    renderSummary(root, card)
    renderTerms(root, card)
    return tostring(root)
end

return p