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

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

全站通知:

模块:生态信息框

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

用于模板:Template:生态信息框。 视图模块:Module:信息框/生态。 数据模块:Module:Data/Worldgen/Biomes



-- Module:生态信息框
-- 注意:代码中的 subworld (sw) 才是生态,而 biome 基本指生态所处自然环境(主要是自然砖块元素表)
local p = {}
local fstr = mw.ustring.format -- shortcut for formattig a string
local utils = require([[Module:Utils]])
local po = require([[Module:Po]]).po
local getArgs = require('Module:Dev/Arguments').getArgs
local infobox = require([[Module:信息框/生态]])
local i18nds = require([[Module:I18n]]).loadMessages([[Module:I18n/Subworlds]])
local i18nsv = require([[Module:I18n]]).loadMessages([[Module:I18n/SubworldsVariant]])

local gData = require([[Module:Data/Geysers]])
local elData = require([[Module:Data/Elements]])
local subworldsDataBASE = mw.loadData([[Module:Data/Worldgen/Subworlds]])
local subworldsDataDLC1 = mw.loadData([[Module:Data/Worldgen/Subworlds/Expansion1]])
local subworldsDataDLC2 = mw.loadData([[Module:Data/Worldgen/Subworlds/Dlc2]])
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 biomesDataBASE = mw.loadData([[Module:Data/Worldgen/Biomes]])
local biomesDataDLC1 = mw.loadData([[Module:Data/Worldgen/Biomes/Expansion1]])
local biomesDataDLC2 = mw.loadData([[Module:Data/Worldgen/Biomes/Dlc2]])
local tempertures = mw.loadData([[Module:Data/Worldgen/Temperatures]])
local critters = mw.loadData([[Module:Data/Critters]])
local plants = mw.loadData([[Module:Data/Plants]])
-- local plants = mw.loadData([[Module:Sandbox/Data/Plants]])

local DLC1Prefix = "expansion1::"
local DLC2Prefix = "dlc2::"

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

local function set2Seq(s)
    local ret = {}
    for k, v in pairs(s) do
        if v then
            table.insert(ret, k)
        end
    end
    table.sort(ret)
    return ret
end

local function getWorldListByCode(swNameCode)
    local swCode = swNameCode and swNameCode:match("^STRINGS.SUBWORLDS.(%w+).NAME$")
    if swCode == nil then
        return {}
    end
    local usedWorlds = {}
    local worlds = {}
    for _, subworldsData in ipairs({subworldsDataBASE, subworldsDataDLC1, subworldsDataDLC2}) do
        for swTypeId, swDatas in pairs(subworldsData) do
            if not utils.endswith(swTypeId, ".yaml") and swTypeId:upper() == swCode then
                for swFile, swData in pairs(swDatas) do
                    if usedWorlds[swFile] == nil then
                        usedWorlds[swFile] = true
                        table.insert(worlds, {
                            data = swData,
                            typeId = swTypeId,
                            id = utils.endswith(swFile, ".yaml") and swFile:gsub("%.yaml$", "") or swFile,
                            code = swNameCode
                        })
                    end
                end
            end
        end
    end
    table.sort(worlds, function(a, b)
        if a.typeId == b.typeId then
            return a.id < b.id
        else
            return a.typeId < b.typeId
        end
    end)
    return worlds
end

local function worldsData(output, dataset, pattern, subworldId)
    for _, wData in pairs(dataset) do
        local subworldIdPattern = fstr(pattern, subworldId)
        for _, subworldFile in ipairs(wData.subworldFiles) do
            if subworldFile.name:find(subworldIdPattern) ~= nil then
                table.insert(output, wData)
            end
        end
    end
end

local function getSectionName(swId)
    local newName = i18nsv:msg(swId)
    if not utils.isDefaultT(swId, newName) then
        return newName
    end
    return swId
end

-- test by: = p.getTemplate("expansion1::poi/radioactive/uranium_fields_liquid_co2_geyser_b")
-- test by: = p.getTemplate("poi/jungle/geyser_steam")
function p.getTemplate(path)
    local out = path

    local dlc1 = utils.startswith(path, DLC1Prefix)
    if dlc1 then
        out = path:sub(#DLC1Prefix + 1)
    end
    local dlc2 = utils.startswith(path, DLC2Prefix)
    if dlc2 then
        out = path:sub(#DLC2Prefix + 1)
    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 .. ((dlc1 and "/Expansion1") or (dlc2 and "/Dlc2") or ""))

    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

function p.getGeyserGroups(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(sData, subworldId)
    local out = {}
    local pageCats = {}

    local subworldIdWbr = table.concat(utils.camel2Array(subworldId), "<wbr>") -- in case that the id is too long
    out["生态代码"] = fstr("-{<code>%s</code>}-", subworldIdWbr) -- disable language conversion
    out["生态类型代码"] = fstr("-{<code>%s</code>}-", sData.zoneType) -- disable language conversion

    -- temperatureRange
    local temperatureRange = tempertures.add[sData.temperatureRange]
    out["温度范围"] = fstr("%.2f°C ~ %.2f°C", temperatureRange.min + utils.K0, temperatureRange.max + utils.K0)

    -- biomes(元素、动植物等)
    local biomesTagsSet = {}
    local biomesTerrainSet = {}
    for _, biome in ipairs(sData.biomes) do
        for _, tag in ipairs(biome.tags or {}) do
            biomesTagsSet[tag] = true
        end
        local versionPrefix = ""
        if (utils.startswith(biome.name, DLC1Prefix)) then
            versionPrefix = DLC1Prefix
        elseif (utils.startswith(biome.name, DLC2Prefix)) then
            versionPrefix = DLC2Prefix
        end
        local prefix = versionPrefix .. "biomes/"
        if utils.startswith(biome.name, prefix) then
            local path = mw.text.split(biome.name:sub(#prefix + 1), '/', true)
            local biomeFamily = path[1]
            local biomeVariant = path[2]
            local biomesData = ({
                [''] = biomesDataBASE,
                [DLC1Prefix] = biomesDataDLC1,
                [DLC2Prefix] = biomesDataDLC2
            })[versionPrefix]
            local bFamilyData = biomesData[biomeFamily .. ".yaml"]
            local bData = bFamilyData.TerrainBiomeLookupTable.add[biomeVariant]
            for _, entry in ipairs(bData) do
                biomesTerrainSet[entry.content] = true
            end
        else
            mw.logObject(biome, "Invalid biome")
        end
    end
    local biomesTags = set2Seq(biomesTagsSet)
    local biomesTerrain = set2Seq(biomesTerrainSet)
    local biomesElements = {}
    for _, eleId in ipairs(biomesTerrain) do
        local el = elData[eleId]
        if biomesElements[el.state] == nil then
            biomesElements[el.state] = {}
        end
        table.insert(biomesElements[el.state], fstr("{{物品|%s}}", po(el.localizationID)))
    end
    for state, elements in pairs(biomesElements) do
        out[po("STRINGS.MISC.TAGS." .. state:upper())] = table.concat(elements, ' {{*}} ')
    end
    local entryTags = {}
    for _, tag in ipairs(biomesTags) do
        local entryTag = tag
        if utils.startswith(entryTag, 'med_') then
            entryTag = entryTag:sub(5)
        end
        if utils.startswith(entryTag, 'forestCluster_') then
            entryTag = entryTag:sub(15)
            mw.log(entryTag)
        end
        if utils.endswith(entryTag, 'Sparse') then
            entryTag = entryTag:sub(1, #entryTag - 6)
        end
        if utils.endswith(entryTag, 'Dense') then
            entryTag = entryTag:sub(1, #entryTag - 5)
        end
        if utils.endswith(entryTag, 'Large') then
            entryTag = entryTag:sub(1, #entryTag - 5)
        end
        if utils.endswith(entryTag, 'Small') then
            entryTag = entryTag:sub(1, #entryTag - 5)
        end
        local buried = false
        if utils.endswith(entryTag, 'Buried') then
            entryTag = entryTag:sub(1, #entryTag - 6)
            buried = true
        end
        if entryTag == 'DiverentBeelte' then
            entryTag = 'DivergentBeetle'
        end
        local name, isCat, _, t = utils.getEntry(entryTag)
        local missing = name == nil
        name = name or entryTag
        if critters[entryTag] ~= nil then
            t = 'variant'
        elseif plants[entryTag] ~= nil then
            t = 'plant'
        end

        local entryTypeName = ({
            food = '食物',
            creature = '生物',
            creature_ = '生物',
            family = '小动物',
            variant = '小动物',
            seed = '种子',
            plant = '植物'
        })[t or ''] or "其他物品"
        if entryTags[entryTypeName] == nil then
            entryTags[entryTypeName] = {}
        end
        local suffix = buried and " (掩埋)" or ""
        if missing then
            table.insert(entryTags[entryTypeName], name)
        elseif isCat then
            table.insert(entryTags[entryTypeName], fstr("[[:Category:%s|%s]]%s", name, name, suffix))
        else
            table.insert(entryTags[entryTypeName], fstr("{{物品|%s}}%s", name, suffix))
        end
    end
    for entryTypeName, entries in pairs(entryTags) do
        out[entryTypeName] = table.concat(entries, ' {{*}} ')
    end

    -- 出现小行星
    local usedByWorlds = {}
    worldsData(usedByWorlds, worldsDataBASE, "^subworlds/%%w+/%s$", subworldId)
    worldsData(usedByWorlds, worldsDataDLC1, "^expansion1::subworlds/%%w+/%s$", subworldId)
    worldsData(usedByWorlds, worldsDataDLC2, "^dlc2::subworlds/%%w+/%s$", subworldId)

    local usedByWorldsSet = {}
    local usedByWorldsList = {}
    for _, wData in ipairs(usedByWorlds) do
        local nameCode = wData.name
        if (usedByWorldsSet[nameCode] == nil) then
            usedByWorldsSet[nameCode] = true
            table.insert(usedByWorldsList, fstr("\n*[[%s]]", po(nameCode)))
        end
    end
    out["出现小行星"] = table.concat(usedByWorldsList, "")
    if out["出现小行星"] == "" then
        out["出现小行星"] = "无"
    end

    -- 间歇泉
    if sData.subworldTemplateRules ~= nil then
        local gGroups = p.getGeyserGroups(sData.subworldTemplateRules)
        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

        if #geyserText > 0 then
            out["间歇泉"] = table.concat(geyserText, "<div><hr /></div><div><hr /></div>")
        end
    else
        out["间歇泉"] =
            "<abbr title='但仍可能由地图规则随机生成掩埋的间歇泉'>无本地生成规则</abbr>"
    end

    table.insert(pageCats, "[[Category:生态]]")
    return out, pageCats
end

-- test by: = p.main(require("Module:debug").frame({},{pagename = "岩浆生态", debug=1}))
-- test by: = p.main(require("Module:debug").frame({},{pagename = "砂岩生态", debug=1}))
function p.main(frame)
    local args = getArgs(frame)
    local worlds = {}

    if args.pagename ~= nil then
        local swNamePlain = mw.ustring.match(args.pagename, "^(%w+)生态$")
        local swNameCode = i18nds:msgRev({
            key = swNamePlain,
            args = {
                prefix = "STRINGS.SUBWORLDS."
            }
        } or "")
        if swNameCode == nil then
            error(fstr("找不到生态 '%s',请使用参数1或检查 [[%s]]。", args.pagename,
                "Module:Data/Worldgen/Subworlds"))
        end
        worlds = getWorldListByCode(swNameCode)
    else
        error("找不到参数 pagename")
    end

    local sections = {}
    local pageCatsSet = {}
    if worlds ~= nil and #worlds > 0 then
        for _, worldData in ipairs(worlds) do
            local info, cats = p.getInfo(worldData.data, worldData.id)
            table.insert(sections, {
                data = info,
                label = getSectionName(worldData.id)
            })
            for _, cat in ipairs(cats) do
                pageCatsSet[cat] = true
            end
        end
        local swCode = worlds[1].code
        sections.data = {
            ["图片"] = args.pagename .. ".png",
            ["图片说明"] = po(swCode:sub(1, -6) .. ".DESC")
        }
    else
        error(fstr("找不到生态 '%s',请使用参数1或检查 [[%s]]。", args.pagename,
            "Module:Data/Worldgen/Subworlds"))
    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 title = args.pagename

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

return p