模块

装备:修订间差异

来自卡厄思梦境WIKI

律Rhyme留言 | 贡献
无编辑摘要
律Rhyme留言 | 贡献
无编辑摘要
 
(未显示同一用户的33个中间版本)
第1行: 第1行:
local p = {}
local p = {}
local data = mw.loadData('模块:装备/data/S1')


-- 兼容不同命名空间的 data 路径
-- 获取装备稀有度
local function loadData()
local rarityMap = {
     local paths = { '模块:装备/data', 'Module:装备/data' }
    ["蓝"] = "蓝",
    for _, path in ipairs(paths) do
    ["金"] = "金",
         local ok, d = pcall(mw.loadData, path)
    ["彩"] = "彩"
         if ok and type(d) == 'table' then
}
             return d
 
         end
-- 稀有度排序权重
local rarityOrder = {
    ["彩"] = 1,
    ["金"] = 2,
    ["蓝"] = 3
}
 
-- 类型排序权重
local typeOrder = {
    ["武器"] = 1,
    ["装甲"] = 2,
    ["戒指"] = 3
}
 
-- 辅助函数:记录数值
local function calculateValue(rarity, itemType, level)
     local BASE_VALUES = {
        ["蓝"] = {
            ["武器"] = { values = {25, 41, 56, 67, 74} },
            ["装甲"] = { values = {9, 15, 21, 24, 28} },
            ["戒指"] = { values = {20, 37, 54, 66, 75} },
        },
         ["金"] = {
            ["武器"] = { values = {28, 45, 62, 74, 82} },
            ["装甲"] = { values = {10, 17, 23, 27, 31} },
            ["戒指"] = { values = {22, 41, 60, 73, 83} },
        },
         ["彩"] = {
            ["武器"] = { values = {31, 50, 68, 81, 90} },
            ["装甲"] = { values = {11, 19, 25, 30, 34} },
             ["戒指"] = { values = {24, 45, 66, 80, 91} },
        },
    }
   
    local levelNum = tonumber(level) or 1
    if BASE_VALUES[rarity] and BASE_VALUES[rarity][itemType] then
         return BASE_VALUES[rarity][itemType].values[levelNum]
     end
     end
     return {}
     return 0
end
end


local data = loadData()
-- 辅助函数:获取属性类型
local function getValueType(itemType)
    local typeMap = {
        ["武器"] = "攻击力",
        ["装甲"] = "防御力",
        ["戒指"] = "HP"
    }
    return typeMap[itemType] or ""
end


-- 更稳健的参数获取(优先使用 Arguments 模块,兼容中英文命名)
-- 装备卡片筛选
local function getArgsCompat(frame)
function p.generateCards(frame)
     local tryModules = { 'Module:Arguments', '模块:Arguments' }
     local html = mw.html.create()
     for _, m in ipairs(tryModules) do
   
         local ok, Arguments = pcall(require, m)
    -- 创建排序数组
         if ok and type(Arguments) == 'table' and type(Arguments.getArgs) == 'function' then
    local equipList = {}
             return Arguments.getArgs(frame, { parentOnly = false })
     for equipName, equipData in pairs(data) do
         table.insert(equipList, {
            name = equipName,
            data = equipData,
            rarityOrder = rarityOrder[equipData.rarity] or 999,
            typeOrder = typeOrder[equipData.type] or 999
        })
    end
   
    -- 按照稀有度、类型排序
    table.sort(equipList, function(a, b)
        -- 先按稀有度排序(升序)
         if a.rarityOrder ~= b.rarityOrder then
            return a.rarityOrder < b.rarityOrder
        end
        -- 再按类型排序(升序)
        if a.typeOrder ~= b.typeOrder then
             return a.typeOrder < b.typeOrder
         end
         end
     end
        -- 最后按名称排序
     -- 回退:合并 frame.args 与 parent.args 到普通表
        return a.name < b.name
    local args = {}
     end)
    local fa = frame.args or {}
   
    for k, v in pairs(fa) do args[k] = v end
     -- 遍历排序后的装备列表
    local parent = frame:getParent()
    for _, item in ipairs(equipList) do
    if parent and parent.args then
        local equipName = item.name
         for k, v in pairs(parent.args) do
        local equipData = item.data
             if args[k] == nil then args[k] = v end
       
        -- 直接使用art字段作为图片文件名
        local artFile = equipData.art or "relic_0000.png"
       
        -- 处理地区数据,支持多个地区
        local areaData = equipData.area or ""
       
        -- 创建可筛选的卡片容器
        local cardWrapper = html:tag('div')
            :addClass('divsort equipment-wrapper')
            :attr('data-param1', equipData.rarity)
            :attr('data-param2', areaData)
            :attr('data-param3', equipData.type)
            :attr('data-sortrarity', rarityOrder[equipData.rarity] or 999)
            :attr('data-sorttype', typeOrder[equipData.type] or 999)
            :cssText('display: inline-block; margin: 5px; position: relative;')
       
        -- 创建卡片和名称的容器
        local cardContainer = cardWrapper:tag('div')
            :cssText('display: flex; flex-direction: column; align-items: center;')
       
        -- 生成卡片内容
        local cardDiv = cardContainer:tag('div')
            :addClass('equipment-card')
            :attr('data-equipment', equipName)
            :attr('data-level', '5')
            :cssText('position: relative; display: inline-block; width:150px; height: 230px; cursor: pointer;')
       
        -- 背景
        cardDiv:tag('div')
            :cssText('position: absolute; top: 0px; left: 0px;')
            :wikitext(string.format('[[File:bg_equipment_rarity_%s.png|150px|link=]]', equipData.rarity))
       
        -- 装备图片
        cardDiv:tag('div')
            :cssText('position: absolute; top: 43px; left: 13px;')
            :wikitext(string.format('[[File:%s|124px|link=]]', artFile))
       
        -- 底部背景
         cardDiv:tag('div')
            :cssText('position: absolute; bottom: 5px; left: 5px; width: 140px; height: 35px; background-color: rgba(0,0,0,0.5); border-radius: 0px 0px 8px 8px')
       
        -- 星级
        cardDiv:tag('div')
            :cssText('position: absolute; bottom: 10px; left: 20px;')
            :wikitext('[[File:icon_star_rating_5.png|link=]]')
       
        -- 顶层蒙版
        cardDiv:tag('div')
            :cssText('position: absolute; top: 0px; left: 0px;')
             :wikitext('[[File:equipment_顶层蒙版.png|150px|link=]]')
       
        -- 装备名称
        local nameDiv = cardContainer:tag('div')
            :addClass('equipment-name-link')
            :cssText('text-align: center; width: 150px;')
       
        -- 根据稀有度设置名称颜色
        local nameColor = '#34638c'  -- 蓝色
        if equipData.rarity == '金' then
            nameColor = '#ff9500'  -- 金色
        elseif equipData.rarity == '彩' then
            nameColor = '#a072d6'  -- 紫色
         end
         end
       
        -- 统一使用普通颜色样式
        nameDiv:wikitext(string.format('[[%s|<span style="color:%s; font-size:14px; font-weight:bold;">%s</span>]]',
            equipName, nameColor, equipName))
       
        -- 生成对应的弹窗
        local popupDiv = cardWrapper:tag('div')
            :addClass('equipment-popup')
            :attr('id', 'equipment-popup-' .. mw.uri.encode(equipName))
            :cssText('position: fixed; display: none; width:368px; height: 335px; background-color: #343434; border-radius: 9px; z-index: 10000;')
       
        -- 弹窗背景
        popupDiv:tag('div')
            :cssText('position: absolute; top: 0px; left: 0px;')
            :wikitext(string.format('[[File:bg_collection_rarity_%s.png|link=]]', equipData.rarity))
       
        -- 弹窗装备图片
        popupDiv:tag('div')
            :cssText('position: absolute; top: 40px; left: 128px;')
            :wikitext(string.format('[[File:%s|124px|link=]]', artFile))
       
        -- 星级背景
        popupDiv:tag('div')
            :cssText('position: absolute; top: 167px; left: 0px; width: 368px; height: 35px; background-color: rgba(0,0,0,0.5); border-radius: 0px 0px 10px 10px ')
       
        -- 星级
        popupDiv:tag('div')
            :cssText('position: absolute; top: 173px; left: 128px;')
            :wikitext('[[File:icon_star_rating_5.png|link=]]')
       
        -- 类型图标
        popupDiv:tag('div')
            :cssText('position: absolute; top: 205px; left: 5px; color: white')
            :wikitext(string.format('[[File:icon_equip_%s_%s.png|25px|link=]]', equipData.type, equipData.rarity))
       
        -- 装备名称
        popupDiv:tag('div')
            :cssText('position: absolute; top: 208px; left: 33px; color: white')
            :wikitext(equipName)
       
        -- 属性背景
        popupDiv:tag('div')
            :cssText('position: absolute; top: 235px; left: 9px; width: 350px; height: 35px; background-color: rgba(255,255,255,0.3); border-radius: 2px')
       
        -- 属性类型
        local valueType = getValueType(equipData.type)
        popupDiv:tag('div')
            :cssText('position: absolute; top: 242px; left: 14px; color: white')
            :wikitext(valueType)
       
        -- 属性值
        local value = calculateValue(equipData.rarity, equipData.type, "5")
        popupDiv:tag('div')
            :cssText('position: absolute; top: 242px; right: 14px; color: white')
            :wikitext(value)
       
        -- 描述(所有星级描述相同)
        local desc = equipData.desc or ""
        local processedDesc = frame:preprocess(desc)
        popupDiv:tag('div')
            :cssText('position: absolute; top: 277px; left: 10px; right: 10px; color: white; font-size: 14px;')
            :wikitext(processedDesc)
       
        -- 关闭按钮
        popupDiv:tag('div')
            :addClass('equipment-popup-close')
            :cssText('position: absolute; top: 10px; right: 10px; width: 24px; height: 24px; cursor: pointer; color: white; font-size: 20px;')
            :wikitext('×')
     end
     end
     return args
   
     return tostring(html)
end
end


local function clampLevel(level)
-- 单个装备卡片
     level = tonumber(level)
function p.card(frame)
     if not level then return 1 end
     local args = frame.args
     if level < 1 then return 1 end
    local name = args[1] or args.name
     if level > 5 then return 5 end
    local level = args[2] or args.level or "1"
     return level
   
     if not name or not data[name] then
        return "装备不存在: " .. (name or "未指定")
    end
      
    local equip = data[name]
   
    -- 直接使用art字段作为图片文件名
    local artFile = equip.art or "relic_0000.png"
   
    -- 生成HTML
    local html = mw.html.create('div')
        :addClass('equipment-card')
        :attr('data-equipment', name)
        :attr('data-level', level)
        :cssText('position: relative; display: inline-block; width:150px; height: 230px; cursor: pointer;')
   
    -- 背景
    html:tag('div')
        :cssText('position: absolute; top: 0px; left: 0px;')
        :wikitext(string.format('[[File:bg_equipment_rarity_%s.png|150px|link=]]', equip.rarity))
   
    -- 装备图片
    html:tag('div')
        :cssText('position: absolute; top: 43px; left: 13px;')
        :wikitext(string.format('[[File:%s|124px|link=]]', artFile))
   
    -- 底部背景
    html:tag('div')
        :cssText('position: absolute; bottom: 5px; left: 5px; width: 140px; height: 35px; background-color: rgba(0,0,0,0.5); border-radius: 0px 0px 8px 8px')
   
    -- 星级
     html:tag('div')
        :cssText('position: absolute; bottom: 10px; left: 20px;')
        :wikitext(string.format('[[File:icon_star_rating_%s.png|link=]]', level))
   
    -- 顶层蒙版
    html:tag('div')
        :cssText('position: absolute; top: 0px; left: 0px;')
        :wikitext('[[File:equipment_顶层蒙版.png|150px|link=]]')
   
     return tostring(html)
end
end


local function starIcon(level)
-- 显示弹窗内容
     level = clampLevel(level)
function p.displaypopup(frame)
     return string.format("icon_star_rating_%d.png", level)
     local args = frame.args
end
    local name = args[1] or args.name
 
    local level = args[2] or args.level or "5"
local function sanitizeId(s)
   
     s = tostring(s or '')
     if not name or not data[name] then
     s = mw.text.trim(s)
        return "装备不存在: " .. (name or "未指定")
     s = mw.ustring.gsub(s, "%s+", "_")
    end
     s = mw.ustring.gsub(s, "[%[%]{}()%c%p]", "_")
   
     return s
    local equipData = data[name]
   
    -- 直接使用art字段作为图片文件名
     local artFile = equipData.art or "relic_0000.png"
   
    -- 创建弹窗容器
     local html = mw.html.create('div')
        :cssText('position: relative; width:368px; height: 335px; background-color: #343434; border-radius: 9px;')
      
    -- 弹窗背景
    html:tag('div')
        :cssText('position: absolute; top: 0px; left: 0px;')
        :wikitext(string.format('[[File:bg_collection_rarity_%s.png|link=]]', equipData.rarity))
   
    -- 弹窗装备图片
    html:tag('div')
        :cssText('position: absolute; top: 40px; left: 128px;')
        :wikitext(string.format('[[File:%s|124px|link=]]', artFile))
      
    -- 星级背景
    html:tag('div')
        :cssText('position: absolute; top: 167px; left: 0px; width: 368px; height: 35px; background-color: rgba(0,0,0,0.5); border-radius: 0px 0px 10px 10px ')
   
    -- 星级
    html:tag('div')
        :cssText('position: absolute; top: 173px; left: 128px;')
        :wikitext(string.format('[[File:icon_star_rating_%s.png|link=]]', level))
   
    -- 类型图标
    html:tag('div')
        :cssText('position: absolute; top: 205px; left: 5px; color: white')
        :wikitext(string.format('[[File:icon_equip_%s_%s.png|25px|link=]]', equipData.type, equipData.rarity))
   
    -- 装备名称
    html:tag('div')
        :cssText('position: absolute; top: 208px; left: 33px; color: white')
        :wikitext(name)
   
    -- 属性背景
    html:tag('div')
        :cssText('position: absolute; top: 235px; left: 9px; width: 350px; height: 35px; background-color: rgba(255,255,255,0.3); border-radius: 2px')
   
    -- 属性类型
    local valueType = getValueType(equipData.type)
    html:tag('div')
        :cssText('position: absolute; top: 242px; left: 14px; color: white')
        :wikitext(valueType)
   
    -- 属性值
    local value = calculateValue(equipData.rarity, equipData.type, level)
    html:tag('div')
        :cssText('position: absolute; top: 242px; right: 14px; color: white')
        :wikitext(value)
   
    -- 描述(所有星级描述相同)
    local desc = equipData.desc or ""
    local processedDesc = frame:preprocess(desc)
    html:tag('div')
        :cssText('position: absolute; top: 277px; left: 10px; right: 10px; color: white; font-size: 14px;')
        :wikitext(processedDesc)
   
     return tostring(html)
end
end


function p.render(frame)
-- 筛选表格
     local args = getArgsCompat(frame)
function p.generateTableRows(frame)
     -- 支持多种参数名(中文键使用方括号访问,避免语法错误)
     local html = {}
     local name = args.name or args['名称'] or args[1]
   
     local level = clampLevel(args.level or args.lv or args['等级'] or args[2] or 1)
     -- 创建排序数组
 
     local equipList = {}
    if not name or name == '' then
     for equipName, equipData in pairs(data) do
        return "<span style='color:red'>[装备] 数据未找到:未指定</span>"
        table.insert(equipList, {
            name = equipName,
            data = equipData,
            rarityOrder = rarityOrder[equipData.rarity] or 999,
            typeOrder = typeOrder[equipData.type] or 999
        })
     end
     end
     if not data[name] then
      
         return string.format("<span style='color:red'>[装备] 数据未找到:%s</span>", mw.text.encode(name))
    -- 按照稀有度、类型排序
    table.sort(equipList, function(a, b)
        if a.rarityOrder ~= b.rarityOrder then
            return a.rarityOrder < b.rarityOrder
        end
        if a.typeOrder ~= b.typeOrder then
            return a.typeOrder < b.typeOrder
        end
        return a.name < b.name
    end)
   
    -- 遍历排序后的装备列表生成表格行
    for _, item in ipairs(equipList) do
        local equipName = item.name
        local equipData = item.data
       
        -- 直接使用art字段作为图片文件名
        local artFile = equipData.art or "relic_0000.png"
       
        -- 处理地区数据
        local areaData = equipData.area or ""
        local areaDisplay = areaData
       
        -- 如果地区为空或"0",显示为"全地区"
        if areaData == "" or areaData == "0" then
            areaDisplay = "全地区"
        else
            areaDisplay = areaData:gsub(",", "<br/>")
        end
       
        -- 稀有度文本映射
        local rarityText = {
            ["蓝"] = "普通",
            ["金"] = "稀有",
            ["彩"] = "传奇"
        }
       
        -- 稀有度颜色
        local rarityColor = {
            ["蓝"] = "#34638c",
            ["金"] = "#ff9500",
            ["彩"] = "#a072d6"
        }
       
        -- 获取属性类型和数值
        local valueType = getValueType(equipData.type)
        local value = calculateValue(equipData.rarity, equipData.type, "5")
        local valueDisplay = string.format("%s %d", valueType, value)
       
        -- 获取描述
        local desc = equipData.desc or ""
        local processedDesc = frame:preprocess(desc)
       
        -- 创建表格行
         local row = string.format(
            '<tr class="divsort" data-param1="%s" data-param2="%s" data-param3="%s" data-param4="%s" data-sortrarity="%s" data-sorttype="%s">' ..
            '<td style="text-align:left;">[[File:%s|50px|link=%s]] [[%s|<span style="color:%s;">%s</span>]]</td>' ..
            '<td><span style="color:%s;">%s</span></td>' ..
            '<td>%s</td>' ..
            '<td>%s</td>' ..
            '<td>%s</td>' ..
            '<td style="text-align:left;">%s</td>' ..
            '</tr>',
            equipData.rarity,
            areaData,
            equipData.type,
            equipData.tag or "",
            rarityOrder[equipData.rarity] or 999,
            typeOrder[equipData.type] or 999,
            artFile, equipName, equipName, rarityColor[equipData.rarity], equipName,
            rarityColor[equipData.rarity], rarityText[equipData.rarity] or equipData.rarity,
            equipData.type,
            valueDisplay,
            areaDisplay,
            processedDesc
        )
       
        table.insert(html, row)
     end
     end
 
      
     local eq = data[name]
     return table.concat(html, '\n')
     local base = eq.base or {}
    local rarity = base.rarity or "蓝"
    local art = base.art or ""
    local typ = base.type or "武器"
    local valueType = base.value_type or ""
    local lvlKey = tostring(level)
    local lvl = eq[lvlKey] or {}
    local value = lvl.value or ""
    local desc = lvl.desc_global or ""
 
    local modalId = "equip_modal_" .. sanitizeId(name) .. "_" .. tostring(level)
 
    local root = mw.html.create('span')
 
    -- 使用锚点触发 :target 显示弹窗(无 JS 也可用)
    local link = root:tag('a')
        :attr('href', '#' .. modalId)
        :attr('style', 'text-decoration:none;')
 
    -- 卡片
    local card = link:tag('div')
        :addClass('equip-card')
        :attr('data-equip-id', modalId)
        :attr('style', 'position: relative; display: inline-block; width:150px; height: 230px; cursor: pointer;')
 
    card:tag('div')
        :attr('style', 'position: absolute; top: 0px; left: 0px;')
        :wikitext(string.format('[[File:bg_equipment_rarity_%s.png|150px|link=]]', rarity))
 
    card:tag('div')
        :attr('style', 'position: absolute; top: 43px; left: 13px;')
        :wikitext(string.format('[[File:%s|124px|link=]]', art))
 
    card:tag('div')
        :attr('style', 'position: absolute; bottom: 5px; left: 5px; width: 140px; height: 35px; background-color: rgba(0,0,0,0.5); border-radius: 0px 0px 8px 8px')
 
    card:tag('div')
        :attr('style', 'position: absolute; bottom: 10px; left: 20px; ')
        :wikitext(string.format('[[File:%s|link=]]', starIcon(level)))
 
    card:tag('div')
        :attr('style', 'position: absolute; top: 0px; left: 0px;')
        :wikitext('[[File:equipment_顶层蒙版.png|150px|link=]]')
 
    -- 弹窗容器(遮罩)
    local modalContainer = root:tag('div')
        :addClass('equip-modal-container')
        :attr('id', modalId)
 
    -- 弹窗内容
    local modal = modalContainer:tag('div')
        :addClass('equip-modal')
        :attr('style', 'position: relative; display: inline-block; width:368px; height: 335px; background-color: #343434; border-radius: 9px')
 
    modal:tag('div')
        :attr('style', 'position: absolute; top: 0px; left: 0px;')
        :wikitext(string.format('[[File:bg_collection_rarity_%s.png|link=]]', rarity))
 
    modal:tag('div')
        :attr('style', 'position: absolute; top: 40px; left: 128px;')
        :wikitext(string.format('[[File:%s|124px|link=]]', art))
 
    modal:tag('div')
        :attr('style', 'position: absolute; top: 167px; left: 0px; width: 368px; height: 35px; background-color: rgba(0,0,0,0.5); border-radius: 0px 0px 8px 8px')
 
    modal:tag('div')
        :attr('style', 'position: absolute; top: 173px; left: 128px; ')
        :wikitext(string.format('[[File:%s|link=]]', starIcon(level)))
 
    modal:tag('div')
        :attr('style', 'position: absolute; top: 205px; left: 5px; color: white')
        :wikitext(string.format('[[File:icon_equip_%s_%s.png|25px|link=]]', typ, rarity))
 
    modal:tag('div')
        :attr('style', 'position: absolute; top: 209px; left: 33px; color: white')
        :wikitext(name)
 
    modal:tag('div')
        :attr('style', 'position: absolute; top: 235px; left: 9px; width: 350px; height: 35px; background-color: rgba(255,255,255,0.3); border-radius: 2px')
 
    modal:tag('div')
        :attr('style', 'position: absolute; top: 242px; left: 14px; color: white')
        :wikitext(valueType)
 
    modal:tag('div')
        :attr('style', 'position: absolute; top: 242px; right: 14px; color: white')
        :wikitext(tostring(value))
 
    modal:tag('div')
        :attr('style', 'position: absolute; top: 277px; left: 10px; color: white')
        :wikitext(desc)
 
    -- 关闭按钮(锚点,回到无 hash)
    modal:tag('a')
        :addClass('equip-modal-close')
        :attr('href', '#')
        :attr('title', '关闭')
        :attr('style', 'position: absolute; top: 6px; right: 10px; color: white; font-size: 20px; line-height: 20px; cursor: pointer; text-decoration:none;')
        :wikitext('×')
 
    return tostring(root)
end
end


return p
return p

2025年11月1日 (六) 10:49的最新版本

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

local p = {}
local data = mw.loadData('模块:装备/data/S1')

-- 获取装备稀有度
local rarityMap = {
    ["蓝"] = "蓝",
    ["金"] = "金",
    ["彩"] = "彩"
}

-- 稀有度排序权重
local rarityOrder = {
    ["彩"] = 1,
    ["金"] = 2,
    ["蓝"] = 3
}

-- 类型排序权重
local typeOrder = {
    ["武器"] = 1,
    ["装甲"] = 2,
    ["戒指"] = 3
}

-- 辅助函数:记录数值
local function calculateValue(rarity, itemType, level)
    local BASE_VALUES = {
        ["蓝"] = {
            ["武器"] = { values = {25, 41, 56, 67, 74} },
            ["装甲"] = { values = {9, 15, 21, 24, 28} },
            ["戒指"] = { values = {20, 37, 54, 66, 75} },
        },
        ["金"] = {
            ["武器"] = { values = {28, 45, 62, 74, 82} },
            ["装甲"] = { values = {10, 17, 23, 27, 31} },
            ["戒指"] = { values = {22, 41, 60, 73, 83} },
        },
        ["彩"] = {
            ["武器"] = { values = {31, 50, 68, 81, 90} },
            ["装甲"] = { values = {11, 19, 25, 30, 34} },
            ["戒指"] = { values = {24, 45, 66, 80, 91} },
        },
    }
    
    local levelNum = tonumber(level) or 1
    if BASE_VALUES[rarity] and BASE_VALUES[rarity][itemType] then
        return BASE_VALUES[rarity][itemType].values[levelNum]
    end
    return 0
end

-- 辅助函数:获取属性类型
local function getValueType(itemType)
    local typeMap = {
        ["武器"] = "攻击力",
        ["装甲"] = "防御力",
        ["戒指"] = "HP"
    }
    return typeMap[itemType] or ""
end

-- 装备卡片筛选
function p.generateCards(frame)
    local html = mw.html.create()
    
    -- 创建排序数组
    local equipList = {}
    for equipName, equipData in pairs(data) do
        table.insert(equipList, {
            name = equipName,
            data = equipData,
            rarityOrder = rarityOrder[equipData.rarity] or 999,
            typeOrder = typeOrder[equipData.type] or 999
        })
    end
    
    -- 按照稀有度、类型排序
    table.sort(equipList, function(a, b)
        -- 先按稀有度排序(升序)
        if a.rarityOrder ~= b.rarityOrder then
            return a.rarityOrder < b.rarityOrder
        end
        -- 再按类型排序(升序)
        if a.typeOrder ~= b.typeOrder then
            return a.typeOrder < b.typeOrder
        end
        -- 最后按名称排序
        return a.name < b.name
    end)
    
    -- 遍历排序后的装备列表
    for _, item in ipairs(equipList) do
        local equipName = item.name
        local equipData = item.data
        
        -- 直接使用art字段作为图片文件名
        local artFile = equipData.art or "relic_0000.png"
        
        -- 处理地区数据,支持多个地区
        local areaData = equipData.area or ""
        
        -- 创建可筛选的卡片容器
        local cardWrapper = html:tag('div')
            :addClass('divsort equipment-wrapper')
            :attr('data-param1', equipData.rarity)
            :attr('data-param2', areaData)
            :attr('data-param3', equipData.type)
            :attr('data-sortrarity', rarityOrder[equipData.rarity] or 999)
            :attr('data-sorttype', typeOrder[equipData.type] or 999)
            :cssText('display: inline-block; margin: 5px; position: relative;')
        
        -- 创建卡片和名称的容器
        local cardContainer = cardWrapper:tag('div')
            :cssText('display: flex; flex-direction: column; align-items: center;')
        
        -- 生成卡片内容
        local cardDiv = cardContainer:tag('div')
            :addClass('equipment-card')
            :attr('data-equipment', equipName)
            :attr('data-level', '5')
            :cssText('position: relative; display: inline-block; width:150px; height: 230px; cursor: pointer;')
        
        -- 背景
        cardDiv:tag('div')
            :cssText('position: absolute; top: 0px; left: 0px;')
            :wikitext(string.format('[[File:bg_equipment_rarity_%s.png|150px|link=]]', equipData.rarity))
        
        -- 装备图片
        cardDiv:tag('div')
            :cssText('position: absolute; top: 43px; left: 13px;')
            :wikitext(string.format('[[File:%s|124px|link=]]', artFile))
        
        -- 底部背景
        cardDiv:tag('div')
            :cssText('position: absolute; bottom: 5px; left: 5px; width: 140px; height: 35px; background-color: rgba(0,0,0,0.5); border-radius: 0px 0px 8px 8px')
        
        -- 星级
        cardDiv:tag('div')
            :cssText('position: absolute; bottom: 10px; left: 20px;')
            :wikitext('[[File:icon_star_rating_5.png|link=]]')
        
        -- 顶层蒙版
        cardDiv:tag('div')
            :cssText('position: absolute; top: 0px; left: 0px;')
            :wikitext('[[File:equipment_顶层蒙版.png|150px|link=]]')
        
        -- 装备名称
        local nameDiv = cardContainer:tag('div')
            :addClass('equipment-name-link')
            :cssText('text-align: center; width: 150px;')
        
        -- 根据稀有度设置名称颜色
        local nameColor = '#34638c'  -- 蓝色
        if equipData.rarity == '金' then
            nameColor = '#ff9500'  -- 金色
        elseif equipData.rarity == '彩' then
            nameColor = '#a072d6'  -- 紫色
        end
        
        -- 统一使用普通颜色样式
        nameDiv:wikitext(string.format('[[%s|<span style="color:%s; font-size:14px; font-weight:bold;">%s</span>]]', 
            equipName, nameColor, equipName))
        
        -- 生成对应的弹窗
        local popupDiv = cardWrapper:tag('div')
            :addClass('equipment-popup')
            :attr('id', 'equipment-popup-' .. mw.uri.encode(equipName))
            :cssText('position: fixed; display: none; width:368px; height: 335px; background-color: #343434; border-radius: 9px; z-index: 10000;')
        
        -- 弹窗背景
        popupDiv:tag('div')
            :cssText('position: absolute; top: 0px; left: 0px;')
            :wikitext(string.format('[[File:bg_collection_rarity_%s.png|link=]]', equipData.rarity))
        
        -- 弹窗装备图片
        popupDiv:tag('div')
            :cssText('position: absolute; top: 40px; left: 128px;')
            :wikitext(string.format('[[File:%s|124px|link=]]', artFile))
        
        -- 星级背景
        popupDiv:tag('div')
            :cssText('position: absolute; top: 167px; left: 0px; width: 368px; height: 35px; background-color: rgba(0,0,0,0.5); border-radius: 0px 0px 10px 10px ')
        
        -- 星级
        popupDiv:tag('div')
            :cssText('position: absolute; top: 173px; left: 128px;')
            :wikitext('[[File:icon_star_rating_5.png|link=]]')
        
        -- 类型图标
        popupDiv:tag('div')
            :cssText('position: absolute; top: 205px; left: 5px; color: white')
            :wikitext(string.format('[[File:icon_equip_%s_%s.png|25px|link=]]', equipData.type, equipData.rarity))
        
        -- 装备名称
        popupDiv:tag('div')
            :cssText('position: absolute; top: 208px; left: 33px; color: white')
            :wikitext(equipName)
        
        -- 属性背景
        popupDiv:tag('div')
            :cssText('position: absolute; top: 235px; left: 9px; width: 350px; height: 35px; background-color: rgba(255,255,255,0.3); border-radius: 2px')
        
        -- 属性类型
        local valueType = getValueType(equipData.type)
        popupDiv:tag('div')
            :cssText('position: absolute; top: 242px; left: 14px; color: white')
            :wikitext(valueType)
        
        -- 属性值
        local value = calculateValue(equipData.rarity, equipData.type, "5")
        popupDiv:tag('div')
            :cssText('position: absolute; top: 242px; right: 14px; color: white')
            :wikitext(value)
        
        -- 描述(所有星级描述相同)
        local desc = equipData.desc or ""
        local processedDesc = frame:preprocess(desc)
        popupDiv:tag('div')
            :cssText('position: absolute; top: 277px; left: 10px; right: 10px; color: white; font-size: 14px;')
            :wikitext(processedDesc)
        
        -- 关闭按钮
        popupDiv:tag('div')
            :addClass('equipment-popup-close')
            :cssText('position: absolute; top: 10px; right: 10px; width: 24px; height: 24px; cursor: pointer; color: white; font-size: 20px;')
            :wikitext('×')
    end
    
    return tostring(html)
end

-- 单个装备卡片
function p.card(frame)
    local args = frame.args
    local name = args[1] or args.name
    local level = args[2] or args.level or "1"
    
    if not name or not data[name] then
        return "装备不存在: " .. (name or "未指定")
    end
    
    local equip = data[name]
    
    -- 直接使用art字段作为图片文件名
    local artFile = equip.art or "relic_0000.png"
    
    -- 生成HTML
    local html = mw.html.create('div')
        :addClass('equipment-card')
        :attr('data-equipment', name)
        :attr('data-level', level)
        :cssText('position: relative; display: inline-block; width:150px; height: 230px; cursor: pointer;')
    
    -- 背景
    html:tag('div')
        :cssText('position: absolute; top: 0px; left: 0px;')
        :wikitext(string.format('[[File:bg_equipment_rarity_%s.png|150px|link=]]', equip.rarity))
    
    -- 装备图片
    html:tag('div')
        :cssText('position: absolute; top: 43px; left: 13px;')
        :wikitext(string.format('[[File:%s|124px|link=]]', artFile))
    
    -- 底部背景
    html:tag('div')
        :cssText('position: absolute; bottom: 5px; left: 5px; width: 140px; height: 35px; background-color: rgba(0,0,0,0.5); border-radius: 0px 0px 8px 8px')
    
    -- 星级
    html:tag('div')
        :cssText('position: absolute; bottom: 10px; left: 20px;')
        :wikitext(string.format('[[File:icon_star_rating_%s.png|link=]]', level))
    
    -- 顶层蒙版
    html:tag('div')
        :cssText('position: absolute; top: 0px; left: 0px;')
        :wikitext('[[File:equipment_顶层蒙版.png|150px|link=]]')
    
    return tostring(html)
end

-- 显示弹窗内容
function p.displaypopup(frame)
    local args = frame.args
    local name = args[1] or args.name
    local level = args[2] or args.level or "5"
    
    if not name or not data[name] then
        return "装备不存在: " .. (name or "未指定")
    end
    
    local equipData = data[name]
    
    -- 直接使用art字段作为图片文件名
    local artFile = equipData.art or "relic_0000.png"
    
    -- 创建弹窗容器
    local html = mw.html.create('div')
        :cssText('position: relative; width:368px; height: 335px; background-color: #343434; border-radius: 9px;')
    
    -- 弹窗背景
    html:tag('div')
        :cssText('position: absolute; top: 0px; left: 0px;')
        :wikitext(string.format('[[File:bg_collection_rarity_%s.png|link=]]', equipData.rarity))
    
    -- 弹窗装备图片
    html:tag('div')
        :cssText('position: absolute; top: 40px; left: 128px;')
        :wikitext(string.format('[[File:%s|124px|link=]]', artFile))
    
    -- 星级背景
    html:tag('div')
        :cssText('position: absolute; top: 167px; left: 0px; width: 368px; height: 35px; background-color: rgba(0,0,0,0.5); border-radius: 0px 0px 10px 10px ')
    
    -- 星级
    html:tag('div')
        :cssText('position: absolute; top: 173px; left: 128px;')
        :wikitext(string.format('[[File:icon_star_rating_%s.png|link=]]', level))
    
    -- 类型图标
    html:tag('div')
        :cssText('position: absolute; top: 205px; left: 5px; color: white')
        :wikitext(string.format('[[File:icon_equip_%s_%s.png|25px|link=]]', equipData.type, equipData.rarity))
    
    -- 装备名称
    html:tag('div')
        :cssText('position: absolute; top: 208px; left: 33px; color: white')
        :wikitext(name)
    
    -- 属性背景
    html:tag('div')
        :cssText('position: absolute; top: 235px; left: 9px; width: 350px; height: 35px; background-color: rgba(255,255,255,0.3); border-radius: 2px')
    
    -- 属性类型
    local valueType = getValueType(equipData.type)
    html:tag('div')
        :cssText('position: absolute; top: 242px; left: 14px; color: white')
        :wikitext(valueType)
    
    -- 属性值
    local value = calculateValue(equipData.rarity, equipData.type, level)
    html:tag('div')
        :cssText('position: absolute; top: 242px; right: 14px; color: white')
        :wikitext(value)
    
    -- 描述(所有星级描述相同)
    local desc = equipData.desc or ""
    local processedDesc = frame:preprocess(desc)
    html:tag('div')
        :cssText('position: absolute; top: 277px; left: 10px; right: 10px; color: white; font-size: 14px;')
        :wikitext(processedDesc)
    
    return tostring(html)
end

-- 筛选表格
function p.generateTableRows(frame)
    local html = {}
    
    -- 创建排序数组
    local equipList = {}
    for equipName, equipData in pairs(data) do
        table.insert(equipList, {
            name = equipName,
            data = equipData,
            rarityOrder = rarityOrder[equipData.rarity] or 999,
            typeOrder = typeOrder[equipData.type] or 999
        })
    end
    
    -- 按照稀有度、类型排序
    table.sort(equipList, function(a, b)
        if a.rarityOrder ~= b.rarityOrder then
            return a.rarityOrder < b.rarityOrder
        end
        if a.typeOrder ~= b.typeOrder then
            return a.typeOrder < b.typeOrder
        end
        return a.name < b.name
    end)
    
    -- 遍历排序后的装备列表生成表格行
    for _, item in ipairs(equipList) do
        local equipName = item.name
        local equipData = item.data
        
        -- 直接使用art字段作为图片文件名
        local artFile = equipData.art or "relic_0000.png"
        
        -- 处理地区数据
        local areaData = equipData.area or ""
        local areaDisplay = areaData
        
        -- 如果地区为空或"0",显示为"全地区"
        if areaData == "" or areaData == "0" then
            areaDisplay = "全地区"
        else
            areaDisplay = areaData:gsub(",", "<br/>")
        end
        
        -- 稀有度文本映射
        local rarityText = {
            ["蓝"] = "普通",
            ["金"] = "稀有",
            ["彩"] = "传奇"
        }
        
        -- 稀有度颜色
        local rarityColor = {
            ["蓝"] = "#34638c",
            ["金"] = "#ff9500",
            ["彩"] = "#a072d6"
        }
        
        -- 获取属性类型和数值
        local valueType = getValueType(equipData.type)
        local value = calculateValue(equipData.rarity, equipData.type, "5")
        local valueDisplay = string.format("%s %d", valueType, value)
        
        -- 获取描述
        local desc = equipData.desc or ""
        local processedDesc = frame:preprocess(desc)
        
        -- 创建表格行
        local row = string.format(
            '<tr class="divsort" data-param1="%s" data-param2="%s" data-param3="%s" data-param4="%s" data-sortrarity="%s" data-sorttype="%s">' ..
            '<td style="text-align:left;">[[File:%s|50px|link=%s]] [[%s|<span style="color:%s;">%s</span>]]</td>' ..
            '<td><span style="color:%s;">%s</span></td>' ..
            '<td>%s</td>' ..
            '<td>%s</td>' ..
            '<td>%s</td>' ..
            '<td style="text-align:left;">%s</td>' ..
            '</tr>',
            equipData.rarity,
            areaData,
            equipData.type,
            equipData.tag or "",
            rarityOrder[equipData.rarity] or 999,
            typeOrder[equipData.type] or 999,
            artFile, equipName, equipName, rarityColor[equipData.rarity], equipName,
            rarityColor[equipData.rarity], rarityText[equipData.rarity] or equipData.rarity,
            equipData.type,
            valueDisplay,
            areaDisplay,
            processedDesc
        )
        
        table.insert(html, row)
    end
    
    return table.concat(html, '\n')
end

return p