置顶公告:【置顶】关于临时开启评论区所有功能的公告(2022.10.22) | 【置顶】关于本站Widget恢复使用的公告
  • 你好~!欢迎来到萌娘百科镜像站!如需查看或编辑,请联系本站管理员注册账号。
  • 本镜像站和其他萌娘百科的镜像站无关,请注意分别。

Module:FGOServantSkill

贴贴♀百科,万娘皆可贴的百科全书!转载请标注来源页面的网页链接,并声明引自贴贴百科。内容不可商用。
跳到导航 跳到搜索
Template-info.svg 模块文档  [查看] [编辑] [历史] [刷新]

本模块仅用于{{FGO_持有技能}},生成Fate/Grand Order系列从者的持有技能描述。

-- Originally designed and coded by Maya (U:Maya-Maja-Maia)

local getArgs = require("Module:Arguments").getArgs
local getSkillIcon = require("Module:FGOSkillIcon").getSkillIcon
local hashObj = require("Module:HashArgs").hashObj

local upPattern = "%^"
local upString = '<span style="color:gold">▲</span>'

local getSkillValue = function (s)
    if mw.ustring.sub(s, 1, 4) == 'val:' then
        return nil, mw.ustring.sub(s, 5, -1)
    end

    local n = tonumber(s)
    if n then
        return n
    end

    local ssub = mw.ustring.sub(s, 1, -2)
    n = tonumber(ssub)
    if n then
        return n, mw.ustring.sub(s, -1, -1)
    end

    if s == '&empty;' or s == '∅' then
        return nil, '∅'
    end
end

local getRoundValue = function (s)
    if mw.ustring.sub(s, 1, 6) == 'round:' then
        return mw.ustring.sub(s, 7, -1)
    end
end

local roundTo = function (n, to)
    if not tonumber(to) then return n end
    local mult = 10 ^ to
    return math.floor(n * mult + 0.5) / mult
end

local packSkillArgs = function (args, startIdx)
    local i = startIdx
    local retobj = {}
    local addingobj = nil
    while args[i] do
        if args[i] ~= '' then
            local val, suffix = getSkillValue(args[i])
            if not val and not suffix then
                local round = getRoundValue(args[i])
                if round then
                    addingobj.round = round
                else
                    if addingobj then
                        table.insert(retobj, addingobj)
                    end
                    addingobj = {}
                    addingobj.name = args[i]
                end
            else
                table.insert(addingobj, { val = val, suffix = suffix })
            end
        end
        i = i + 1
    end
    if addingobj then table.insert(retobj, addingobj) end
    return retobj
end

local expandSkillArg = function (skillArg)
    if #skillArg == 10 then return skillArg end
    if #skillArg == 1 then return skillArg end
    if #skillArg == 0 then
        skillArg[1] = { suffix = '∅' }
        return skillArg
    end
    if #skillArg ~= 2 then error('技能数值参数数量有误。应为0个、1个、2个或10个,实为' .. #skillArg .. '个') end
    if skillArg[1].suffix ~= skillArg[2].suffix then
        error('技能数值参数单位不匹配,其一为' .. skillArg[1].suffix .. ',另一为' .. skillArg[2].suffix)
    end
    local skillDiff = (skillArg[2].val - skillArg[1].val) / 10
    skillArg[10] = skillArg[2]
    for i = 1, 8 do
        skillArg[i+1] = { val = roundTo(skillArg[1].val + skillDiff * i, skillArg.round), suffix = skillArg[1].suffix }
    end
    return skillArg
end

local formatSkillArg = function (val, suffix)
    if not val then
        return suffix
    else
        return val .. (suffix or '')
    end
end

local getStringPrefixLevelAndStrip = function (str, prefix)
    local level = 0
    local stripped = str
    local prefixlen = mw.ustring.len(prefix)
    while mw.ustring.sub(stripped, 0, prefixlen) == prefix do
        level = level + 1
        stripped = mw.ustring.sub(stripped, prefixlen + 1, -1)
    end
    return { level = level, stripped = stripped }
end

local getStrengthenLevel = function (skillStr)
    local addLevel = getStringPrefixLevelAndStrip(skillStr, '+')
    local changeLevel = getStringPrefixLevelAndStrip(skillStr, '>')
    local subbed
    if addLevel.level > 0 then
        subbed, _ = mw.ustring.gsub(addLevel.stripped, upPattern, upString)
        return {
            type = 'add',
            level = addLevel.level,
            subbed = subbed
        }
    end
    if changeLevel.level > 0 then
        subbed, _ = mw.ustring.gsub(changeLevel.stripped, upPattern, upString)
        return {
            type = 'change',
            level = changeLevel.level,
            subbed = subbed
        }
    end
    return { type = nil, level = 0, subbed = skillStr }
end

local stackSkillArgs = function (skillArgs)
    local retobj = {}
    local addingobj = nil
    local strengthenobj = nil
    local strengthenTimes = 0
    for i = 1, #skillArgs do
        strengthenobj = getStrengthenLevel(skillArgs[i].name)
        if strengthenobj.type ~= 'change' then
            if addingobj then table.insert(retobj, addingobj) end
            addingobj = {}
        end
        if strengthenTimes < strengthenobj.level then
            strengthenTimes = strengthenobj.level
        end

        if addingobj and #addingobj ~= 0 then
            addingobj[#addingobj].stopShow = strengthenobj.level - 1
        end
        skillArgs[i].name = strengthenobj.subbed
        table.insert(addingobj, {
            startShow = strengthenobj.level,
            skillArg = skillArgs[i]
        })
    end
    if addingobj then table.insert(retobj, addingobj) end
    retobj.strengthenTimes = strengthenTimes
    return retobj
end

local getUpStrings = function (num)
    local retstr = ''
    for i = 1, num do
        retstr = retstr .. upString
    end
    return retstr
end

local getChargeString = function (str)
    local num = tonumber(str)
    if num then
        return num .. '→<span style="color:red">' .. num - 1 ..
        '</span>→<span style="color:red">' .. num - 2 .. '</span>'
    else
        return str
    end
end

local generateSkillRowWithClass = function (skillArg, class, add)
    local retstr = ''
    local classaddstr = add or ''
    if class then
        classaddstr = 'class="' .. class .. '" ' .. classaddstr
    end
    retstr = retstr .. [[
        
    |-]] .. classaddstr .. [[
    
    ! colspan="10" |]] .. skillArg.name .. [[

    |-]] .. classaddstr
    if #(skillArg) > 1 then
        for j = 1, 10 do
            retstr = retstr .. [[

            | style="width:75px;max-width:20%]]
            if j == 6 or j == 10 then
                retstr = retstr .. ';color:red'
            end
            retstr = retstr .. '"'
            if j >= 6 then
                retstr = retstr .. ' class="nomobile"'
            end
            retstr = retstr .. ' |' .. formatSkillArg(skillArg[j].val, skillArg[j].suffix)
        end
        retstr = retstr .. [[

        |- class="mobileonly ]] .. (class or '') .. '" ' .. (add or '')
        for j = 6, 10 do
            retstr = retstr .. [[

            | style="width:75px;max-width:20%]]
            if j == 6 or j == 10 then
                retstr = retstr .. ';color:red'
            end
            retstr = retstr .. '" |' .. formatSkillArg(skillArg[j].val, skillArg[j].suffix)
        end
    else
        retstr = retstr .. [[

        | colspan="10" |]] .. formatSkillArg(skillArg[1].val, skillArg[1].suffix)
    end
    return retstr
end

local generateTable = function (args, skillArgs, frame, hash)
    local iconstr = getSkillIcon(args[1])
    local namezhstr = args[2]
    local namejastr = args[3]
    local chargestr = getChargeString(args[4])

    local retstr = ''

    if skillArgs.strengthenTimes ~= 0 then
        local defaultTab = hash .. args["默认"]
        local buttonArgs = {
            'button',
            ['@default'] = defaultTab,
            ['@forceNoCancel'] = 'y',
            ['@radio'] = 'y'
        }
        local buttonSort = '@default|@forceNoCancel|@radio|'
        local buttonText = ''
        for i = 0, skillArgs.strengthenTimes do
            if i == 0 then
                buttonText = args['按钮0'] or '强化前'
            elseif skillArgs.strengthenTimes == 1 then
                buttonText = args['按钮1'] or '强化后'
            else
                buttonText = args['按钮' .. i] or ('强化后' .. i)
            end
            buttonArgs[hash .. i] = buttonText
            buttonSort = buttonSort .. hash .. i .. '|'
            if args['条件' .. i] then
                retstr = retstr ..
                '<span class="textToggleDisplay hidden" data-id="' .. hash .. i ..
                '">' .. args['条件' .. i] .. '</span>\n'
            end
        end
        buttonArgs['@sort'] = buttonSort .. '@sort|'
        retstr = frame:callParserFunction{
            name = '#invoke:切换显示',
            args = buttonArgs
        } .. '\n\n' .. retstr -- cannot use template directly, order preservance issues
    end

    retstr = retstr .. '{| class="wikitable" style="text-align:center;line-height:1.75em;display:table;max-width:100%"'
    for i = 0, skillArgs.strengthenTimes do
        local switchClassStr = ''
        if skillArgs.strengthenTimes ~= 0 then
            switchClassStr = 'class="textToggleDisplay hidden" data-id="' .. hash .. i .. '"'
        end
        if args["图标" .. i] then iconstr = getSkillIcon(args["图标" .. i]) end
        namezhstr = args["中文名" .. i] or namezhstr
        namejastr = args["日文名" .. i] or namejastr
        if args["充能时间" .. i] then chargestr = getChargeString(args["充能时间" .. i]) end
        retstr = retstr .. [[
        
        |-]] .. switchClassStr .. [[

        ! rowspan="2" class="nomobile" style="width:75px;max-width:10%" |]] .. iconstr .. [[

        ! rowspan="3" class="mobileonly" style="width:75px;max-width:20%" |]] .. iconstr .. [[

        ! colspan="4" class="mobileonly" style="width:300px;max-width:80%" |]] .. namezhstr .. getUpStrings(i) .. [[

        ! colspan="6" class="nomobile" style="width:450px;max-width:60%" |]] .. namezhstr .. getUpStrings(i) .. [[

        ! rowspan="2" colspan="3" class="nomobile" style="width:225px;max-width:30%" |充能时间:]] .. chargestr .. [[

        |-]] .. switchClassStr .. [[

        | colspan="6" lang="ja" | -{]] .. namejastr .. getUpStrings(i) .. [[}-
        |-]] .. switchClassStr .. [[

        ! colspan="4" class="mobileonly" |充能时间:]] .. chargestr
    end
    for i = 1, #skillArgs do
        if #(skillArgs[i]) == 1 and skillArgs[i][1].startShow == 0 then
            retstr = retstr .. generateSkillRowWithClass(skillArgs[i][1].skillArg)
        else
            local currentAt = 1
            for j = 0, skillArgs.strengthenTimes do
                if skillArgs[i][currentAt].startShow <= j then
                    retstr = retstr .. generateSkillRowWithClass(skillArgs[i][currentAt].skillArg,
                    'textToggleDisplay hidden',
                    'data-id="' .. hash .. j .. '"')
                end
                if skillArgs[i][currentAt].stopShow and skillArgs[i][currentAt].stopShow <= j then
                    currentAt = currentAt + 1
                end
            end
        end
    end
    retstr = retstr .. [[

    |}]]
    return retstr
end

local FGOServantSkill = {
    main = function (frame)
        local args = getArgs(frame, { removeBlanks = false })
        -- 1. 图标 2. 中文名 3. 日文名 4. CT
        -- 从5开始是技能描述
        local hash = hashObj(args)

        local skillArgs = packSkillArgs(args, 5)
        for i = 1, #skillArgs do
            skillArgs[i] = expandSkillArg(skillArgs[i])
        end

        skillArgs = stackSkillArgs(skillArgs)

        return generateTable(args, skillArgs, frame, hash)
    end
}

return FGOServantSkill