米斯特利亚Wiki正在建设中,本WIKI编辑权限开放!欢迎参与~!

全站通知:

模块:Bugs

来自米斯特利亚WIKI_BWIKI_哔哩哔哩
跳到导航 跳到搜索

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

-- 模块:bugs
-- 说明:本模块用于查询 bugs.lua 中的昆虫数据。
-- 数据请在“模块:bugs/Data”子页面维护,其结构可参考仓库中的 ./data_lua/bugs.lua
local data = require('模块:bugs/Data')
local Utils = require('模块:Utils')
local Custom = require('模块:Custom')
local Items = require('模块:Items')
local p = {}

-- 合并默认值:以 data.default 为基底,叠加具体昆虫的字段(元表回退)
local function mergeWithDefault(id)
    if not id or type(id) ~= 'string' then
        return nil
    end
    local raw = data and data[id]
    if not raw then
        return nil
    end
    local base = data.default or {}
    local merged = {}
    setmetatable(merged, {
        __index = base
    })
    for k, v in pairs(raw) do
        merged[k] = v
    end
    merged.id = id
    return merged
end

-- 获取指定昆虫的单个属性值
-- @param frame.args[1] string 昆虫ID
-- @param frame.args[2] string 属性名
-- @return any 找到的属性值(已合并默认值),找不到则返回 nil。
function p.get(frame)
    local bugId = frame and frame.args and frame.args[1]
    local propertyName = frame and frame.args and frame.args[2]
    if not bugId or not propertyName or bugId == '' or propertyName == '' then
        return nil
    end
    local info = mergeWithDefault(bugId)
    if info and info[propertyName] ~= nil then
        return info[propertyName]
    end
    return nil
end

-- 获取指定昆虫的所有属性(已合并默认值,并附带 id 字段)
-- @param frame.args[1] string 昆虫ID
-- @return table or nil 找到的完整数据表,找不到则返回 nil。
function p.getAll(frame)
    local bugId = frame and frame.args and frame.args[1]
    return mergeWithDefault(bugId)
end

-- 获取昆虫的中文名 name
function p._name(id)
    local name = Items._name(id)
    return name or id
end
function p.name(frame)
    local id = frame and frame.args and frame.args[1]
    return p._name(id)
end

-- 获取昆虫的图标
function p._icon(id)
    local icon = Items._icon(id)
    return icon or id
end
function p.icon(frame)
    local id = frame and frame.args and frame.args[1]
    return p._icon(id)
end

-- 获取昆虫的类型 type,默认crawl
local bugsType = {
    crawl = "爬行",
    fly_wave = "波浪飞行",
    jump = "跳跃",
    fly = "飞行"
}
function p._type(id)
    local info = mergeWithDefault(id)
    local typeKey = info and info.type or "crawl"
    return bugsType[typeKey] or typeKey
end
function p.type(frame)
    local id = frame and frame.args and frame.args[1]
    return p._type(id)
end

-- 获取昆虫的稀有度 rarity
function p._rarity(id)
    local info = mergeWithDefault(id)
    if info and info.rarity then
        return Custom._rarity(info.rarity)
    end
    return "未知稀有度"
end
function p.rarity(frame)
    local id = frame and frame.args and frame.args[1]
    return p._rarity(id)
end

-- 获取昆虫的出现季节 seasons
function p._season(id)
    local info = mergeWithDefault(id)
    local seasons = info and info.seasons or nil
    if type(seasons) == 'table' then
        return Custom._nameTable2Str(seasons)
    elseif type(seasons) == 'string' then
        return Custom._nameStr(seasons)
    end
end
function p.season(frame)
    local id = frame and frame.args and frame.args[1]
    return p._season(id)
end

-- 获取昆虫的出现天气 weather
function p._weather(id)
    local info = mergeWithDefault(id)
    local weather = info and info.weather or {}
    if type(weather) == 'table' then
        return Custom._nameTable2Str(weather)
    elseif type(weather) == 'string' then
        return Custom._nameStr(weather)
    end
end
function p.weather(frame)
    local id = frame and frame.args and frame.args[1]
    return p._weather(id)
end

-- 获取昆虫的出现时间区间 hours
function p._hours(id)
    local info = mergeWithDefault(id)
    if info and info.hours then
    	return Utils.hours(info.hours)
    end
    return ""
end
function p.hours(frame)
    local id = frame and frame.args and frame.args[1]
    return p._hours(id)
end

-- 获取昆虫的生成规则 spawn
local spawnMap = {
    default = "",
    rock = "岩石",
    canopy = "树冠",
    grass = "草地"
}
function p._spawn(id)
    local info = mergeWithDefault(id)
    local s = info and info.spawn
    if not s then
        return ""
    end
    local rStr = Utils.mapST2table(spawnMap, s)
    return rStr
end
function p.spawn(frame)
    local id = frame and frame.args and frame.args[1]
    return p._spawn(id)
end

-- 获取昆虫的生成位置 locations
function p._locations(id)
    local info = mergeWithDefault(id)
    if info and info.locations then
        return Custom._locationByTable(info.locations)
    end
    return ""
end
function p.locations(frame)
    local id = frame and frame.args and frame.args[1]
    return p._locations(id)
end

-- 获取昆虫是否水生 can_spawn_on_water
function p._can_spawn_on_water(id)
    local info = mergeWithDefault(id)
    if info and info.can_spawn_on_water then
        return "是"
    else
        return ""
    end
end
function p.can_spawn_on_water(frame)
    local id = frame and frame.args and frame.args[1]
    return p._can_spawn_on_water(id)
end

-- 获取昆虫是否矿井生成 dungeon_biome
local dungeon_biome_map = {
    upper = "上层矿洞",
    tide_caverns = "潮汐洞穴",
    deep_earth = "深域洞穴",
    lava_caves = "熔岩洞穴"
}
function p._dungeon_biome(id)
    local info = mergeWithDefault(id)
    local db = info and info.dungeon_biome or nil
    if db and db ~= -1 then
        return dungeon_biome_map[db] or db
    end
    return ""
end
function p.dungeon_biome(frame)
    local id = frame and frame.args and frame.args[1]
    return p._dungeon_biome(id)
end

-- 获取昆虫偏好环境 liked_object_categories
local like_object_map = {
    crop = "作物",
    grass = "草地",
    stump = "树桩",
    rock = "岩石",
    tree = "树木",
    breakable = "可破坏物",
    building = "建筑物",
    bush = "灌木"
}
function p._liked_object_categories(id)
    local info = mergeWithDefault(id)
    local iobj = info and info.liked_object_categories or nil
    local rStr = Utils.mapST2table(like_object_map, iobj)
    if rStr then
        return rStr
    end
    return ""
end
function p.liked_object_categories(frame)
    local id = frame and frame.args and frame.args[1]
    return p._liked_object_categories(id)
end

-- 获取昆虫吸引机制 attraction
local attraction_map = {
    none = "",
    light = "被光吸引",
    copper = "被铜吸引",
    crystal_berries = "被水晶浆果吸引"
}
function p._attraction(id)
    local info = mergeWithDefault(id)
    local attract = info and info.attraction or nil
    local rStr = Utils.mapST2table(attraction_map, attract)
    if rStr then
        return rStr
    end
    return ""
end
function p.attraction(frame)
    local id = frame and frame.args and frame.args[1]
    return p._attraction(id)
end

-- 根据指定筛选条件筛选并返回昆虫ID列表
-- @param filters table 筛选条件配置表
-- 筛选条件支持两种配置格式:
--   1. 简单格式:直接指定属性值进行匹配,例如 {type="飞行", rarity="普通"}
--   2. 复杂格式:使用操作符指定匹配逻辑,例如 {seasons={op="contains", value="spring"}}
-- 支持的操作符及说明:
--   - equals: 精确匹配值(适用于所有数据类型)
--   - contains: 表中包含指定元素(仅适用于表类型属性)
--   - exact: 表中恰好只包含指定元素(仅适用于表类型属性)
--   - not_contains: 表中不包含指定元素(仅适用于表类型属性)
--   - contains_but_not_exact: 表中包含指定元素但元素数量大于1(仅适用于表类型属性)
-- 常用可筛选属性:type(类型), rarity(稀有度), seasons(季节), weather(天气), hours(时间), spawn(生成方式), 
--                locations(地点), can_spawn_on_water(是否可在水上生成), dungeon_biome(洞穴生物群系)等
-- @return table 符合所有筛选条件的昆虫ID数组
function p._filterBugs(filters)
    local result = {}

    -- 如果没有提供筛选条件,则返回所有昆虫id
    if not filters or type(filters) ~= 'table' then
        for id, _ in pairs(data) do
            if id ~= 'default' then -- 排除默认数据
                table.insert(result, id)
            end
        end
        return result
    end

    -- 遍历所有昆虫数据
    for id, _ in pairs(data) do
        if id ~= 'default' then -- 排除默认数据
            local info = mergeWithDefault(id)
            local match = true

            -- 检查每个筛选条件
            for key, filterValue in pairs(filters) do
                if info[key] ~= nil then
                    -- 判断是简单筛选还是复杂筛选
                    if type(filterValue) == 'table' and filterValue.op and filterValue.value then
                        -- 复杂筛选条件
                        local op = filterValue.op
                        local value = filterValue.value

                        if op == 'equals' then
                            -- 值相等(适用于所有类型)
                            if info[key] ~= value then
                                match = false
                                break
                            end
                        elseif op == 'contains' and type(info[key]) == 'table' then
                            -- 表中包含指定值
                            local found = false
                            for _, v in ipairs(info[key]) do
                                if v == value then
                                    found = true
                                    break
                                end
                            end
                            if not found then
                                match = false
                                break
                            end
                        elseif op == 'exact' and type(info[key]) == 'table' then
                            -- 表中恰好只有指定值
                            if #info[key] ~= 1 or info[key][1] ~= value then
                                match = false
                                break
                            end
                        elseif op == 'not_contains' and type(info[key]) == 'table' then
                            -- 表中不包含指定值
                            for _, v in ipairs(info[key]) do
                                if v == value then
                                    match = false
                                    break
                                end
                            end
                            if not match then
                                break
                            end
                        elseif op == 'contains_but_not_exact' and type(info[key]) == 'table' then
                            -- 表中包含指定元素但元素数量大于1
                            local found = false
                            for _, v in ipairs(info[key]) do
                                if v == value then
                                    found = true
                                    break
                                end
                            end
                            if not found or #info[key] <= 1 then
                                match = false
                                break
                            end
                        end
                    else
                        -- 简单筛选条件
                        if type(info[key]) == 'table' then
                            -- 表类型属性,检查是否包含指定值
                            local found = false
                            for _, v in ipairs(info[key]) do
                                if v == filterValue then
                                    found = true
                                    break
                                end
                            end
                            if not found then
                                match = false
                                break
                            end
                        else
                            -- 基本类型属性,直接比较
                            if info[key] ~= filterValue then
                                match = false
                                break
                            end
                        end
                    end
                end
            end

            if match then
                table.insert(result, id)
            end
        end
    end

    return result
end

-- 传入frame,调用_filterBugs函数获得昆虫id列表,为每个昆虫id调用模板渲染
-- @param frame 参数frame对象
-- @return string 所有昆虫模板渲染结果的拼接
function p.filteredBugs(frame)
    local frame = frame or mw.getCurrentFrame()

    -- 从frame.args中获取筛选条件
    local filters = {}
    for key, value in pairs(frame.args) do
        if key ~= 'args' and key ~= 1 and type(key) ~= 'number' then
            filters[key] = value
        end
    end

    -- 获取符合条件的昆虫id列表
    local bugIds = p._filterBugs(filters)

    -- 为每个昆虫id调用模板渲染
    local results = {}
    for _, id in ipairs(bugIds) do
        -- 获取昆虫的中文名
        local name = p.get {
            args = {id, 'name'}
        } or id

        -- 调用模板渲染
        local rendered = frame:expandTemplate{
            title = '物品',
            args = {name, -- 中文名
            id -- 图标名
            }
        }

        table.insert(results, rendered)
    end

    -- 返回所有渲染结果的拼接
    return table.concat(results, '')
end

-- 根据季节和筛选类型筛选昆虫
-- @param frame 参数frame对象
-- 从frame参数中获取:
--   参数1: 季节,如spring
--   参数2: 类型,如contains, exact, not_contains, contains_but_not_exact
-- @return string 符合条件的昆虫模板渲染结果的拼接
function p.filteredBugsBySeason(frame)
    local frame = frame or mw.getCurrentFrame()

    -- 从frame.args中获取季节和筛选类型参数
    local season = frame.args[1] or '' -- 第一个参数: 季节
    local filterType = frame.args[2] or 'contains' -- 第二个参数: 筛选类型,默认为contains

    -- 构建筛选条件
    local filters = {
        seasons = {
            op = filterType,
            value = season
        }
    }

    -- 获取符合条件的昆虫id列表
    local bugIds = p._filterBugs(filters)

    -- 为每个昆虫id调用模板渲染
    local results = {}
    for _, id in ipairs(bugIds) do
        -- 获取昆虫的中文名和图标
        local name = p._name(id)
        local icon = p._icon(id)

        -- 调用模板渲染
        local rendered = frame:expandTemplate{
            title = '物品',
            args = {name, -- 中文名
            icon -- 图标名
            }
        }

        table.insert(results, rendered)
    end

    -- 返回所有渲染结果的拼接
    return table.concat(results, '')
end

--[[
mw.logObject(p._name("butterfly"))
mw.logObject(p._icon("butterfly"))
mw.logObject(p._type("butterfly")=="波浪飞行")
mw.logObject(p._rarity("butterfly")=="普通")
mw.logObject(p._season("butterfly")=="春天")
mw.logObject(p._weather("butterfly")=="晴朗,特殊天气")
mw.logObject(p._hours("butterfly")=="6,20")
mw.logObject(p._spawn("butterfly")=="默认")
mw.logObject(p._spawn("caterpillar")=="树冠,默认")
mw.logObject(p._locations("lightning_dragonfly")=="狭窄地带,东边小径")
mw.logObject(p._can_spawn_on_water("butterfly")=="否")
mw.logObject(p._can_spawn_on_water("pond_skater")=="是")
mw.logObject(p._dungeon_biome("butterfly")=="地表昆虫")
mw.logObject(p._dungeon_biome("fire_wasp")=="熔岩洞穴")
mw.logObject(p._attraction("butterfly")=="无特殊吸引机制")
mw.logObject(p._attraction("copper_beetle")=="被铜吸引")

-- 春天相关筛选测试
-- 1. 仅筛选春季的昆虫
mw.logObject("=== 仅筛选春季的昆虫 ===")
local springOnlyBugs = p._filterBugs({seasons={op="exact", value="spring"}})
mw.logObject(springOnlyBugs)

-- 2. 筛选包含春季但不止春季的昆虫
mw.logObject("=== 筛选包含春季但不止春季的昆虫 ===")
-- 使用新添加的contains_but_not_exact操作符
local hasSpringButNotOnlyBugs = p._filterBugs({seasons={op="contains_but_not_exact", value="spring"}})
mw.logObject(hasSpringButNotOnlyBugs)


-- 3. 筛选不包含春季的昆虫
mw.logObject("=== 筛选不包含春季的昆虫 ===")
local noSpringBugs = p._filterBugs({seasons={op="not_contains", value="spring"}})
mw.logObject(noSpringBugs)


local frame = mw.getCurrentFrame()
frame.args = { 
"spring",
"contains_but_not_exact"
}
mw.logObject(p.filteredBugsBySeason(frame))


]] --

return p