缺氧 wiki 编辑团队提示:注册账号并登录后体验更佳,且可通过参数设置定制优化您的浏览体验!

该站点为镜像站点,如果你想帮助这个由玩家志愿编辑的 wiki 站点,请前往原站点参与编辑,
同时欢迎加入编辑讨论群 851803695 与其他编辑者一起参与建设!

全站通知:

模块:小行星信息框

来自缺氧WIKI_BWIKI_哔哩哔哩
跳到导航 跳到搜索

用于模板:Template:小行星信息框。 视图模块:Module:信息框/小行星。 数据模块:Module:Data/Worldgen/Worlds



-- Module:小行星信息框
local p = {}
local fstr = mw.ustring.format
local utils = require([[Module:Utils]])
local po = require([[Module:Po]]).po
local getArgs = require('Module:Dev/Arguments').getArgs
local infobox = require([[Module:信息框/小行星]])
local gData = require([[Module:Data/Geysers]])
local worldsDataBASE = mw.loadData([[Module:Data/Worldgen/Worlds]])
local worldsDataDLC1 = mw.loadData([[Module:Data/Worldgen/Worlds/Expansion1]])
local worldsDataDLC2 = mw.loadData([[Module:Data/Worldgen/Worlds/Dlc2]])
local clustersDLC1 = mw.loadData([[Module:Data/Worldgen/Clusters/Expansion1]])
local clustersDLC2 = mw.loadData([[Module:Data/Worldgen/Clusters/Dlc2]])
local i18ndw = require([[Module:I18n]]).loadMessages([[Module:i18n/Worlds]])

local seasonNames = {
    MeteorShowers = "[[流星雨]]",
    RegolithMoonMeteorShowers = "[[流星雨]](浮土)",
    GassyMooteorShowers = "[[流星雨]]([[释气海牛|海牛]])"
}

local GeyserGenericRepr = "随机[[间歇泉]]"

-- TUNING.FIXEDTRAITS.SUNLIGHT
local DEFAULT_SPACED_OUT_SUNLIGHT = 40000
local sunlightLevels = {
    sunlightNone = 0,
    sunlightVeryVeryLow = DEFAULT_SPACED_OUT_SUNLIGHT * 0.25,
    sunlightVeryLow = DEFAULT_SPACED_OUT_SUNLIGHT * 0.5,
    sunlightLow = DEFAULT_SPACED_OUT_SUNLIGHT * 0.75,
    sunlightMedLow = DEFAULT_SPACED_OUT_SUNLIGHT * 0.875,
    sunlightMed = DEFAULT_SPACED_OUT_SUNLIGHT,
    sunlightMedHigh = DEFAULT_SPACED_OUT_SUNLIGHT * 1.25,
    sunlightHigh = DEFAULT_SPACED_OUT_SUNLIGHT * 1.5,
    sunlightVeryHigh = DEFAULT_SPACED_OUT_SUNLIGHT * 2,
    sunlightVeryVeryHigh = DEFAULT_SPACED_OUT_SUNLIGHT * 2.5,
    sunlightVeryVeryVeryHigh = DEFAULT_SPACED_OUT_SUNLIGHT * 3,
    default = DEFAULT_SPACED_OUT_SUNLIGHT * 2 -- DEFAULT_VALUE = VERY_HIGH
}

-- TUNING.FIXEDTRAITS.COSMICRADIATION
local BASELINE = 250
local cosmicRadiationLevels = {
    cosmicRadiationNone = 0,
    cosmicRadiationVeryVeryLow = BASELINE * 0.25,
    cosmicRadiationVeryLow = BASELINE * 0.5,
    cosmicRadiationLow = BASELINE * 0.75,
    cosmicRadiationMedLow = BASELINE * 0.875,
    cosmicRadiationMed = BASELINE,
    cosmicRadiationMedHigh = BASELINE * 1.25,
    cosmicRadiationHigh = BASELINE * 1.5,
    cosmicRadiationVeryHigh = BASELINE * 2,
    cosmicRadiationVeryVeryHigh = BASELINE * 3,
    default = BASELINE -- DEFAULT_VALUE = MED
}

local DLC_PATHS = {
    ["expansion1::"] = "/Expansion1",
    ["dlc2::"] = "/Dlc2"
}

local function subworldName(path)
    local subworld = path:match("subworlds/(%w+)/-")
    if subworld:upper() == "EMPTY" then return "EMPTY" end
    return fstr("STRINGS.SUBWORLDS.%s.NAME", subworld:upper())
end

local function getSectionName(worldId)
    if utils.endswith(worldId, "Start") then
        return "开局"
    elseif utils.endswith(worldId, "Warp") then
        return "传送"
    end
    return "基础"
end

local function getDlc(worldData)
    local dlc = ""
    if worldData.requiredDlcIds ~= nil then
        for _, tag in ipairs(worldData.requiredDlcIds) do
            if tag == "EXPANSION1_ID" then
                dlc = "EXPANSION1_ID"
            end
        end
    end
    return dlc
end

local function getWorldDataById(worldId)
    local worldFile = utils.endswith(worldId, ".yaml") and worldId or worldId .. ".yaml"
    if worldsDataBASE[worldFile] ~= nil then
        return worldsDataBASE[worldFile], ""
    elseif worldsDataDLC1[worldFile] ~= nil then
        return worldsDataDLC1[worldFile], "EXPANSION1_ID"
    elseif worldsDataDLC2[worldFile] ~= nil then
        local worldData = worldsDataDLC2[worldFile]
        return worldData, getDlc(worldData)
    end
    return nil, nil
end

local function getWorldListByCode(worldCode)
    local dataList = {}
    for worldId, worldData in pairs(worldsDataBASE) do
        if worldData.name == worldCode then
            table.insert(dataList, {
                data = worldData,
                id = utils.endswith(worldId, ".yaml") and worldId:gsub("%.yaml$", "") or worldId,
                dlc = ""
            })
        end
    end
    for worldId, worldData in pairs(worldsDataDLC1) do
        if worldData.name == worldCode then
            table.insert(dataList, {
                data = worldData,
                id = utils.endswith(worldId, ".yaml") and worldId:gsub("%.yaml$", "") or worldId,
                dlc = "EXPANSION1_ID"
            })
        end
    end
    for worldId, worldData in pairs(worldsDataDLC2) do
        if worldData.name == worldCode then
            table.insert(dataList, {
                data = worldData,
                id = utils.endswith(worldId, ".yaml") and worldId:gsub("%.yaml$", "") or worldId,
                dlc = getDlc(worldData)
            })
        end
    end
    return dataList
end

-- test by: = p.getTemplate("expansion1::poi/radioactive/uranium_fields_liquid_co2_geyser_b")
-- test by: = p.getTemplate("poi/jungle/geyser_steam")
-- test by: = p.getTemplate("geysers/generic")
function p.getTemplate(path)
    local out = path
    local subPath = ""
    for dlcPrefix, dlcPath in pairs(DLC_PATHS) do
        if utils.startswith(path, dlcPrefix) then
            out = path:sub(#dlcPrefix + 1)
            subPath = dlcPath
            break
        end
    end
    local splited = mw.text.split(out, '/', true)
    local capName = splited[1]:sub(1, 1):upper() .. splited[1]:sub(2)
    out = mw.loadData("Module:Data/Templates/" .. capName .. subPath)

    splited[#splited] = splited[#splited] .. ".yaml"
    for i = 2, #splited do
        if out == nil then
            return nil
        end
        out = out[splited[i]]
    end
    return out
end

function p.getGeyserId(template)
    if template == nil then
        return nil
    end
    local prefix = "GeyserGeneric_"
    if template.otherEntities == nil then
        return nil
    end
    for _, e in ipairs(template.otherEntities) do
        if e.id == "GeyserGeneric" then
            return e.id
        end
        if utils.startswith(e.id, prefix) then
            return e.id:sub(#prefix + 1)
        end
    end
    return nil
end

local function getGeyserGruops(worldTemplateRules)
    local gGroups = {}
    for _, rule in ipairs(worldTemplateRules) do
        local geyserIds = {}
        local geyserIdNum = {} -- 该规则下各种间歇泉的重复数
        local ruleTimes = rule.times or 1
        for _, name in ipairs(rule.names) do
            local id = p.getGeyserId(p.getTemplate(name))
            if id ~= nil then
                if not geyserIdNum[id] then
                    geyserIdNum[id] = 1
                    table.insert(geyserIds, id)
                else
                    geyserIdNum[id] = geyserIdNum[id] + 1
                end
            end
        end
        table.sort(geyserIds)

        if #geyserIds ~= 0 then
            local group = {}
            group.id = table.concat(geyserIds)
            group.geysers = utils.map(geyserIds, function(id)
                return gData[id] or {
                    id = id
                }
            end)
            for _, g in ipairs(group.geysers) do -- 在间歇泉数据中添加重复数信息
                g.num = geyserIdNum[g.id]
            end
            group.minNum = 0
            group.maxNum = 0

            if rule.listRule == "GuaranteeAll" then
                for _, g in ipairs(group.geysers) do
                    if gGroups[g.id] ~= nil then
                        gGroups[g.id].minNum = gGroups[g.id].minNum + 1 * ruleTimes * geyserIdNum[g.id]
                        gGroups[g.id].maxNum = gGroups[g.id].maxNum + 1 * ruleTimes * geyserIdNum[g.id]
                    else
                        gGroups[g.id] = {
                            geysers = {g},
                            minNum = 1 * ruleTimes * geyserIdNum[g.id],
                            maxNum = 1 * ruleTimes * geyserIdNum[g.id]
                        }
                    end
                end
            else
                if rule.listRule == "GuaranteeSome" then
                    group.minNum = rule.someCount
                    group.maxNum = rule.someCount
                elseif rule.listRule == "GuaranteeSomeTryMore" then
                    group.minNum = rule.someCount
                    group.maxNum = rule.someCount + rule.moreCount
                elseif rule.listRule == "GuaranteeOne" then
                    group.minNum = 1
                    group.maxNum = 1
                elseif rule.listRule == "TryAll" then -- 不使用间歇泉种类计数,累加全体重复数
                    group.maxNum = 0
                    for _, n in pairs(geyserIdNum) do
                        group.maxNum = group.maxNum + n
                    end
                elseif rule.listRule == "TrySome" then
                    group.maxNum = rule.someCount
                elseif rule.listRule == "TryOne" then
                    group.maxNum = 1
                end
                group.minNum = group.minNum * ruleTimes
                group.maxNum = group.maxNum * ruleTimes

                if gGroups[group.id] ~= nil then
                    gGroups[group.id].minNum = gGroups[group.id].minNum + group.minNum
                    gGroups[group.id].maxNum = gGroups[group.id].maxNum + group.maxNum
                else
                    gGroups[group.id] = group
                end
            end
        end
    end
    return gGroups
end

function p.getInfo(wData, worldId, dlc)
    local out = {}
    local pageCats = {}
    local isBase = dlc == ""

    out["小行星代码"] = table.concat(utils.camel2Array(worldId), "<wbr>") -- in case that the id is too long
    out["小行星代码"] = fstr("-{<code>%s</code>}-", out["小行星代码"]) -- disable language conversion
    out["名称"] = po(wData.name)
    out["图片"] = fstr("%s.png", out["名称"])
    out["图片说明"] = po(wData.description)
    out["大小"] = fstr("%s x %s 格", wData.worldsize.X, wData.worldsize.Y)

    if not isBase then
        out["出现星群"] = {}
        for _, cData in pairs(clustersDLC1) do
            for _, worldInCluster in ipairs(cData.worldPlacements) do
                -- only consider dlc1 worlds
                local worldIdWithPrefix = "expansion1::worlds/" .. worldId
                if worldIdWithPrefix == worldInCluster.world then
                    table.insert(out["出现星群"], cData)
                end
            end
        end
        for _, cData in pairs(clustersDLC2) do
            for _, worldInCluster in ipairs(cData.worldPlacements) do
                -- only consider dlc2 worlds
                local worldIdWithPrefix = "dlc2::worlds/" .. worldId
                if worldIdWithPrefix == worldInCluster.world then
                    table.insert(out["出现星群"], cData)
                end
            end
        end
        table.sort(out["出现星群"], function(a, b)
            if a.clusterCategory ~= b.clusterCategory then
                return a.clusterCategory < b.clusterCategory
            else
                return a.menuOrder < b.menuOrder
            end
        end)
        local list = utils.map(out["出现星群"], function(cData)
            return fstr("\n*[[%s]]", po(cData.name))
        end)
        out["出现星群"] = table.concat(list, "")
        if out["出现星群"] == "" then
            out["出现星群"] = "无"
        end
    end

    if wData.seasons then
        out["天气"] = {}
        for _, s in ipairs(wData.seasons) do
            table.insert(out["天气"], seasonNames[s])
        end
        out["天气"] = table.concat(out["天气"], " {{*}} ")
    end

    out["星球特质"] = "无"
    if wData.worldTraitRules then
        local min = wData.worldTraitRules[1] and wData.worldTraitRules[1].min
        local max = wData.worldTraitRules[1] and wData.worldTraitRules[1].max
        if min and max then
            if (min == max) then
                out["星球特质"] = fstr("%s 个", min)
            else
                out["星球特质"] = fstr("%s - %s 个", min, max)
            end
        end
    end

    if wData.subworldFiles then
        local subworldSet = {}
        local subworlds = {}
        for _, sf in ipairs(wData.subworldFiles) do
            subworldSet[subworldName(sf.name)] = true
        end
        for name, _ in pairs(subworldSet) do
            table.insert(subworlds, name)
        end
        table.sort(subworlds)
        subworlds = utils.map(subworlds, function(code)
            return code == "EMPTY" and "" or fstr("\n*[[%s生态]]", po(code))
        end)
        out["生态"] = table.concat(subworlds, "")
        out["生态"] = out["生态"] == "" and "无" or out["生态"]
    end

    if isBase then
        out["最大光照"] = 80000
    elseif wData.fixedTraits then
        out["最大光照"] = sunlightLevels.default
        out["辐射强度"] = cosmicRadiationLevels.default
        for _, trait in ipairs(wData.fixedTraits) do
            out["最大光照"] = sunlightLevels[trait] and math.floor(sunlightLevels[trait] + 0.5) or
                                      out["最大光照"]
            out["辐射强度"] = cosmicRadiationLevels[trait] and math.floor(cosmicRadiationLevels[trait] + 0.5) or
                                      out["辐射强度"]
        end
    end

    out["间歇泉"] = "无"
    if wData.worldTemplateRules then
        local gGroups = getGeyserGruops(wData.worldTemplateRules)
        local gGroupIds = {}
        for gId, _ in pairs(gGroups) do
            table.insert(gGroupIds, gId)
        end
        table.sort(gGroupIds)

        local geyserText = {}
        for _, gId in ipairs(gGroupIds) do
            local currGroup = gGroups[gId]
            local gNames = utils.map(currGroup.geysers, function(g)
                if g.id == "GeyserGeneric" then
                    return GeyserGenericRepr
                else
                    return fstr("{{*}}{{物品|%s}}", po("STRINGS.CREATURES.SPECIES.GEYSER." .. g.id:upper() .. ".NAME"))
                end
            end)
            local rangeText = tostring(currGroup.minNum)
            if currGroup.minNum ~= currGroup.maxNum then
                rangeText = rangeText .. " - " .. tostring(currGroup.maxNum)
            end
            table.insert(geyserText, fstr("<div>%s</div><div>%s</div>", table.concat(gNames, "<br>"), rangeText))
        end
        out["间歇泉"] = table.concat(geyserText, "<div><hr /></div><div><hr /></div>")
    end

    table.insert(pageCats, "[[Category:小行星]]")
    return out, pageCats
end

-- test by: = p.main(require("Module:debug").frame({},{"Badlands", debug=1}))
-- test by: = p.main(require("Module:debug").frame({},{pagename = "倒置小行星", debug=1}))
-- test by: = p.main(require("Module:debug").frame({},{pagename = "砂土小行星", debug=1}))
-- test by: = p.main(require("Module:debug").frame({},{pagename = "谷神星小行星", debug=1}))
-- test by: = p.main(require("Module:debug").frame({},{"TerraMoonlet", debug=1}))
-- test by: = p.main(require("Module:debug").frame({},{"MiniFlippedStart","MiniFlippedWarp","MiniFlipped", debug=1}))
-- test by: = p.main(require("Module:debug").frame({},{"TinyEmpty","BigEmpty","TinySurface","TinyStart",debug=1}))
function p.main(frame)
    local args = getArgs(frame)

    local sections = {}
    local pageCatsSet = {}

    if args[1] ~= nil then
        for _, worldId in ipairs(args) do
            local worldData, dlc = getWorldDataById(worldId)
            if worldData ~= nil then
                local info, cats = p.getInfo(worldData, worldId, dlc)
                table.insert(sections, {
                    data = info,
                    label = getSectionName(worldId)
                })
                for _, cat in ipairs(cats) do
                    pageCatsSet[cat] = true
                end
            end
        end
    else
        local asteroidCode = i18ndw:msgRev({
            key = args.pagename,
            args = {
                prefix = "STRINGS.WORLDS."
            }
        } or "")
        if asteroidCode == nil then
            error(fstr("找不到小行星 '%s',请使用参数1或检查 [[%s]]。", args.pagename, worldsDataBASE))
        end
        local worlds = getWorldListByCode(asteroidCode)
        for _, worldData in ipairs(worlds) do
            local info, cats = p.getInfo(worldData.data, worldData.id, worldData.dlc)
            table.insert(sections, {
                data = info,
                label = getSectionName(worldData.id)
            })
            for _, cat in ipairs(cats) do
                pageCatsSet[cat] = true
            end
        end
    end

    -- 分类
    local pageCats = {}
    if not (args.namespace or args.nocat) then
        for cat, _ in pairs(pageCatsSet) do
            table.insert(pageCats, cat)
        end
        table.sort(pageCats)
    end
    if args.debug then
        mw.logObject(sections, "Infobox")
        mw.logObject(pageCats, "pageCats")
        return
    end
    local infoboxTitle = args.pagename

    return tostring(infobox.main(infoboxTitle, sections)) .. table.concat(pageCats, "")
end
return p