模块

卡牌:修订间差异

来自卡厄思梦境WIKI

律Rhyme留言 | 贡献
无编辑摘要
律Rhyme留言 | 贡献
无编辑摘要
第1行: 第1行:
local p = {}
local p = {}
-- 配置常量
local CONFIG = {
    DEFAULT_ART = "start_1041_01.png",
    DEFAULT_COLOR = "白",
    DEFAULT_ATTRIBUTE = "虚无",
    DEFAULT_DECK = "起始卡牌",
    CARD_WIDTH = 168,
    CARD_HEIGHT = 230,
}


-- 颜色映射表
-- 颜色映射表
local colorMap = {
local COLOR_MAP = {
     ["白"] = {
     ["白"] = { bgColor = "rgba(249, 249, 249, 0.5)", textColor = "white" },
        bgColor = "rgba(249, 249, 249, 0.5)",
     ["蓝"] = { bgColor = "rgba(115, 236, 254, 0.5)", textColor = "#7de5ff" },
        textColor = "white"
     ["橙"] = { bgColor = "rgba(254, 199, 109, 0.5)", textColor = "#ffee75" },
    },
     ["彩"] = { bgColor = "rgba(201, 88, 241, 0.5)", textColor = "#eba2fc" }
     ["蓝"] = {
        bgColor = "rgba(115, 236, 254, 0.5)",
        textColor = "#7de5ff"
    },
     ["橙"] = {
        bgColor = "rgba(254, 199, 109, 0.5)",
        textColor = "#ffee75"
    },
     ["彩"] = {
        bgColor = "rgba(201, 88, 241, 0.5)",
        textColor = "#eba2fc"
    }
}
}


-- 获取卡牌HTML
-- 安全获取数据字段
local function getCardHTML(frame, cardName, cardData)
local function safeGet(data, field, default)
     if not cardData then
    return data and data[field] or default
         return "找不到卡牌数据: " .. (cardName or "未指定")
end
 
-- 处理描述文本中的模板
local function processDescription(frame, description)
     if not description or description == "" then
         return description
     end
     end
      
      
    -- 使用指定的数据条目
     local success, result = pcall(function()
    local data = cardData
        return frame:preprocess(description)
    local color = data["稀有度"] or "白"
     end)
    local colorStyle = colorMap[color] or colorMap["白"]
     local ap = data["AP"] or ""
    local cardType = data["类型"] or ""
    local description = data["描述"] or ""
     local attribute = data["属性"] or "虚无"
    local cardDeck = data["卡组"] or "起始卡牌"
    local art = data["art"] or "start_1041_01.png"  -- 获取art字段,如果没有则使用默认值
      
      
     -- 根据卡组类型决定边框样式
     return success and result or description
     local borderStyle = "normal"
end
     if cardDeck ~= "起始卡牌" then
 
        borderStyle = "unique"
-- 生成卡牌HTML样式组件
    end
local function buildStyleComponents(cardData, cardName)
     local color = safeGet(cardData, "稀有度", CONFIG.DEFAULT_COLOR)
    local colorStyle = COLOR_MAP[color] or COLOR_MAP[CONFIG.DEFAULT_COLOR]
    local attribute = safeGet(cardData, "属性", CONFIG.DEFAULT_ATTRIBUTE)
     local cardDeck = safeGet(cardData, "卡组", CONFIG.DEFAULT_DECK)
    local borderStyle = cardDeck == "起始卡牌" and "normal" or "unique"
      
      
     -- 解析描述中的模板
     return {
    if description ~= "" then
        color = color,
         -- 检查frame对象是否有preprocess方法并安全调用
        colorStyle = colorStyle,
         if frame and type(frame) == "table" and frame.preprocess then
        attribute = attribute,
            -- 创建一个包装函数来确保正确的调用方式
         borderStyle = borderStyle,
            local success, result = pcall(function()
         ap = safeGet(cardData, "AP", ""),
                return frame:preprocess(description)
        cardType = safeGet(cardData, "类型", ""),
            end)
        art = safeGet(cardData, "art", CONFIG.DEFAULT_ART)
            if success then
    }
                description = result
end
            end
 
         end
-- 构建卡牌HTML
local function buildCardHTML(frame, cardName, cardData)
    if not cardData then
         return string.format("找不到卡牌数据: %s", cardName or "未指定")
     end
     end
      
      
    -- 构建卡牌HTML,使用art变量
     local style = buildStyleComponents(cardData, cardName)
     local html = '<div style="position: relative; width: 168px; height: 230px; overflow: hidden;">'
     local description = processDescription(frame, safeGet(cardData, "描述", ""))
     .. '<div style="position: absolute; top: 1px; left: 12px;">[[File:' .. art .. '|151px|link=]]</div>'
    .. '<div style="position: absolute; top: 1px; left: 12px;">[[File:card_黑色蒙版.png|151px|link=]]</div>'
    .. '<div style="position: absolute; top: 20px; left: 10px; width: 148px; height: 10px; background-color: ' .. colorStyle.bgColor .. ';"></div>'
    .. '<div style="position: absolute; left: 23px; top: 4px; color: white; font-weight: bold; text-shadow: 0 0 10px #4a90e2,0 0 20px #4a90e2, 0 0 30px #4a90e2, 0 0 40px #4a90e2; font-size: 32px;">' .. ap .. '</div>'
    .. '<div style="position: absolute; left: 25px; top: 34px; color: white; font-weight: bold; text-shadow: 0 0 10px #4a90e2,0 0 20px #4a90e2, 0 0 30px #4a90e2, 0 0 40px #4a90e2;">—</div>'
    .. '<div style="position: absolute; left: 50px; top: 13px; color: ' .. colorStyle.textColor .. '; font-size:16px">' .. cardName .. '</div>'
    .. '<div style="position: absolute; left: 48px; top: 30px; ">[[File:icon_card_' .. cardType .. '.png|18px|link=]]</div>'
    .. '<div style="position: absolute; left: 68px; top: 33px; color: white; font-size:14px">' .. cardType .. '</div>'
    .. '<div style="position: absolute; top: 0px; left: 1px;">[[File:card_属性边框_' .. attribute .. '_' .. borderStyle .. '.png|160px|link=]]</div>'
    .. '<div style="position: absolute; top: 10px; left: 0px;">[[File:card_稀有度_' .. color .. '.png|22px|link=]]</div>'
    .. '<div style="position: absolute; top: 2px; right: 4px;">[[File:card_稀有度_边框_' .. color .. '.png|11px|link=]]</div>'
    .. '<div style="position: absolute; bottom: 7px; left: 15px; width: 144px; height: 100px; font-size: 12px; color: white; line-height: 13px; display: flex; justify-content: center; align-items: center; text-align: center;">'
    .. '<div>' .. description .. '</div>'
    .. '</div>'
    .. '</div>'
      
      
     return html
    -- 使用字符串拼接优化HTML生成
    local htmlParts = {
        string.format('<div style="position: relative; width: %dpx; height: %dpx; overflow: hidden;">',
            CONFIG.CARD_WIDTH, CONFIG.CARD_HEIGHT),
       
        -- 背景图片层
        string.format('<div style="position: absolute; top: 1px; left: 12px;">[[File:%s|151px|link=]]</div>', style.art),
        '<div style="position: absolute; top: 1px; left: 12px;">[[File:card_黑色蒙版.png|151px|link=]]</div>',
       
        -- 颜色条
        string.format('<div style="position: absolute; top: 20px; left: 10px; width: 148px; height: 10px; background-color: %s;"></div>',
            style.colorStyle.bgColor),
       
        -- AP值
        string.format('<div style="position: absolute; left: 23px; top: 4px; color: white; font-weight: bold; text-shadow: 0 0 10px #4a90e2,0 0 20px #4a90e2, 0 0 30px #4a90e2, 0 0 40px #4a90e2; font-size: 32px;">%s</div>',
            style.ap),
        '<div style="position: absolute; left: 25px; top: 34px; color: white; font-weight: bold; text-shadow: 0 0 10px #4a90e2,0 0 20px #4a90e2, 0 0 30px #4a90e2, 0 0 40px #4a90e2;">—</div>',
       
        -- 卡牌名称和类型
        string.format('<div style="position: absolute; left: 50px; top: 13px; color: %s; font-size:16px">%s</div>',
            style.colorStyle.textColor, cardName),
        string.format('<div style="position: absolute; left: 48px; top: 30px;">[[File:icon_card_%s.png|18px|link=]]</div>',
            style.cardType),
        string.format('<div style="position: absolute; left: 68px; top: 33px; color: white; font-size:14px">%s</div>',
            style.cardType),
       
        -- 边框和稀有度
        string.format('<div style="position: absolute; top: 0px; left: 1px;">[[File:card_属性边框_%s_%s.png|160px|link=]]</div>',
            style.attribute, style.borderStyle),
        string.format('<div style="position: absolute; top: 10px; left: 0px;">[[File:card_稀有度_%s.png|22px|link=]]</div>',
            style.color),
        string.format('<div style="position: absolute; top: 2px; right: 4px;">[[File:card_稀有度_边框_%s.png|11px|link=]]</div>',
            style.color),
       
        -- 描述文本
        '<div style="position: absolute; bottom: 7px; left: 15px; width: 144px; height: 100px; font-size: 12px; color: white; line-height: 13px; display: flex; justify-content: center; align-items: center; text-align: center;">',
        string.format('<div>%s</div>', description),
        '</div>',
        '</div>'
    }
   
     return table.concat(htmlParts)
end
end


第82行: 第112行:
local function mergeCardData(baseData, overrideData)
local function mergeCardData(baseData, overrideData)
     local result = {}
     local result = {}
     for k, v in pairs(baseData) do
     for k, v in pairs(baseData or {}) do
         result[k] = v
         result[k] = v
     end
     end
     for k, v in pairs(overrideData) do
     for k, v in pairs(overrideData or {}) do
         result[k] = v
         result[k] = v
     end
     end
第91行: 第121行:
end
end


-- 获取有序的卡牌名称列表
-- 获取并显示所有默认卡牌
local function getOrderedCardNames(characterModule)
local function displayAllDefaultCards(frame, characterModule)
     -- 如果模块定义了顺序列表,使用它
    local cards = characterModule.card or {}
     if characterModule.cardOrder then
    local cardOrder = characterModule.cardOrder or {}
         return characterModule.cardOrder
    local displayedCards = {}
   
    -- 按cardOrder顺序遍历
    for orderIndex, name in ipairs(cardOrder) do
        local cardArray = cards[name]
        if cardArray and #cardArray > 0 then
            -- 只显示第一张卡牌
            table.insert(displayedCards, {
                name = name,
                data = cardArray[1],
                order = orderIndex
            })
        end
    end
   
    -- 生成HTML
    local htmlParts = {}
    for i, cardInfo in ipairs(displayedCards) do
        table.insert(htmlParts, buildCardHTML(frame, cardInfo.name, cardInfo.data))
        if i < #displayedCards then
            table.insert(htmlParts, "<br><br>")
        end
    end
   
    return table.concat(htmlParts)
end
 
-- 处理特定卡牌请求
local function handleSpecificCard(frame, cardName, cardData, deckFilter, cardIndex)
    local baseCard = cardData[1]
   
     -- 如果没有指定卡组筛选,返回基础卡牌
     if deckFilter == "" then
        return buildCardHTML(frame, cardName, baseCard)
    end
   
    -- 筛选指定卡组的卡牌
    local filteredCards = {}
    for _, card in ipairs(cardData) do
        if card["卡组"] == deckFilter then
            table.insert(filteredCards, card)
        end
    end
   
    if #filteredCards == 0 then
         return string.format("找不到卡组 '%s' 的卡牌: %s", deckFilter, cardName)
    end
   
    -- 如果指定了索引,返回特定卡牌
    if cardIndex > 0 and cardIndex <= #filteredCards then
        local mergedCard = mergeCardData(baseCard, filteredCards[cardIndex])
        return buildCardHTML(frame, cardName, mergedCard)
     end
     end
      
      
     -- 否则尝试从card表中获取顺序
     -- 否则返回该卡组的所有卡牌
     local orderedNames = {}
     local htmlParts = {}
     for name, _ in pairs(characterModule.card or {}) do
     for i, card in ipairs(filteredCards) do
         table.insert(orderedNames, name)
        local mergedCard = mergeCardData(baseCard, card)
        table.insert(htmlParts, buildCardHTML(frame, cardName, mergedCard))
         if i < #filteredCards then
            table.insert(htmlParts, "<br><br>")
        end
     end
     end
      
      
     return orderedNames
     return table.concat(htmlParts)
end
end


-- 主函数,用于处理模板调用
-- 主函数
function p.main(frame)
function p.main(frame)
     local args = frame.args
     local args = frame.args
第115行: 第200行:
     local cardIndex = tonumber(args[4]) or 0
     local cardIndex = tonumber(args[4]) or 0
      
      
     -- 动态加载战斗员模块
     -- 加载战斗员模块
     local characterModule = nil
     local success, characterModule = pcall(require, "模块:卡牌/" .. characterName)
    local success = pcall(function()
        characterModule = require("模块:卡牌/" .. characterName)
    end)
   
     if not success or not characterModule then
     if not success or not characterModule then
         return "找不到战斗员卡牌数据模块: 模块:卡牌/" .. characterName
         return string.format("找不到战斗员卡牌数据模块: 模块:卡牌/%s", characterName)
     end
     end
      
      
     -- 获取卡牌数据
     -- 如果没有指定卡牌名,显示所有默认卡牌
    local cards = characterModule.card or {}
   
    -- 如果没有指定卡牌名,显示所有起始卡牌和每个独特卡牌的第一张
     if cardName == "" then
     if cardName == "" then
         local html = ""
         return displayAllDefaultCards(frame, characterModule)
        local displayedCards = {}
       
        -- 获取有序的卡牌名称列表
        local orderedNames = getOrderedCardNames(characterModule)
       
        -- 按顺序遍历卡牌
        for orderIndex, name in ipairs(orderedNames) do
            local cardArray = cards[name]
            if cardArray then
                for i, card in ipairs(cardArray) do
                    if card["卡组"] == "起始卡牌" then
                        -- 起始卡牌全部显示
                        table.insert(displayedCards, {
                            name = name,
                            data = card,
                            order = orderIndex,
                            subOrder = i
                        })
                    elseif card["卡组"] == "独特卡牌" and i == 1 then
                        -- 独特卡牌只显示第一张
                        table.insert(displayedCards, {
                            name = name,
                            data = card,
                            order = orderIndex,
                            subOrder = 1
                        })
                    end
                end
            end
        end
       
        -- 按原始顺序排序(已经是按顺序的了,但为了保险起见)
        table.sort(displayedCards, function(a, b)
            if a.order == b.order then
                return a.subOrder < b.subOrder
            end
            return a.order < b.order
        end)
       
        -- 显示所有收集到的卡牌
        for i, cardInfo in ipairs(displayedCards) do
            html = html .. getCardHTML(frame, cardInfo.name, cardInfo.data)
            if i < #displayedCards then
                html = html .. "<br><br>"
            end
        end
       
        return html
     end
     end
      
      
     local cardData = cards[cardName]
    -- 获取指定卡牌数据
     local cardData = (characterModule.card or {})[cardName]
     if not cardData then
     if not cardData then
         return "找不到卡牌: " .. cardName
         return string.format("找不到卡牌: %s", cardName)
     end
     end
      
      
     -- 获取基础卡牌数据(第一个条目)
     return handleSpecificCard(frame, cardName, cardData, deckFilter, cardIndex)
    local baseCard = cardData[1]
   
    -- 如果指定了卡组筛选
    if deckFilter ~= "" then
        local filteredCards = {}
        for _, card in ipairs(cardData) do
            if card["卡组"] == deckFilter then
                table.insert(filteredCards, card)
            end
        end
       
        -- 如果没有找到符合条件的卡牌
        if #filteredCards == 0 then
            return "找不到卡组 '" .. deckFilter .. "' 的卡牌: " .. cardName
        end
       
        -- 如果指定了索引
        if cardIndex > 0 and cardIndex <= #filteredCards then
            local mergedCard = mergeCardData(baseCard, filteredCards[cardIndex])
            return getCardHTML(frame, cardName, mergedCard)
        else
            -- 显示该卡组的所有卡牌
            local html = ""
            for i, card in ipairs(filteredCards) do
                local mergedCard = mergeCardData(baseCard, card)
                html = html .. getCardHTML(frame, cardName, mergedCard)
                if i < #filteredCards then
                    html = html .. "<br><br>"
                end
            end
            return html
        end
    else
        -- 如果没有指定卡组,就返回基础卡牌
        return getCardHTML(frame, cardName, baseCard)
    end
end
end


-- 为每个战斗员创建一个直接调用方法
-- 元表设置,支持直接调用战斗员名称作为方法
setmetatable(p, {
setmetatable(p, {
     __index = function(t, characterName)
     __index = function(t, characterName)
         return function(frame)
         return function(frame)
             local args = frame.args
             frame.args = {
            local cardName = args[1] or ""
            local deckFilter = args[2] or ""
            local cardIndex = tonumber(args[3]) or 0
           
            -- 创建新的参数表来传递给 main 函数
            local newArgs = {
                 [1] = characterName,
                 [1] = characterName,
                 [2] = cardName,
                 [2] = frame.args[1] or "",
                 [3] = deckFilter,
                 [3] = frame.args[2] or "",
                 [4] = cardIndex
                 [4] = frame.args[3] or 0
             }
             }
           
            -- 将其他参数也传递过去
            for k, v in pairs(args) do
                if not newArgs[k] then
                    newArgs[k] = v
                end
            end
           
            -- 直接传递原始frame对象,而不是创建新的
            frame.args = newArgs
           
             return p.main(frame)
             return p.main(frame)
         end
         end

2025年9月27日 (六) 17:32的版本

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

local p = {}

-- 配置常量
local CONFIG = {
    DEFAULT_ART = "start_1041_01.png",
    DEFAULT_COLOR = "白",
    DEFAULT_ATTRIBUTE = "虚无",
    DEFAULT_DECK = "起始卡牌",
    CARD_WIDTH = 168,
    CARD_HEIGHT = 230,
}

-- 颜色映射表
local COLOR_MAP = {
    ["白"] = { bgColor = "rgba(249, 249, 249, 0.5)", textColor = "white" },
    ["蓝"] = { bgColor = "rgba(115, 236, 254, 0.5)", textColor = "#7de5ff" },
    ["橙"] = { bgColor = "rgba(254, 199, 109, 0.5)", textColor = "#ffee75" },
    ["彩"] = { bgColor = "rgba(201, 88, 241, 0.5)", textColor = "#eba2fc" }
}

-- 安全获取数据字段
local function safeGet(data, field, default)
    return data and data[field] or default
end

-- 处理描述文本中的模板
local function processDescription(frame, description)
    if not description or description == "" then
        return description
    end
    
    local success, result = pcall(function()
        return frame:preprocess(description)
    end)
    
    return success and result or description
end

-- 生成卡牌HTML样式组件
local function buildStyleComponents(cardData, cardName)
    local color = safeGet(cardData, "稀有度", CONFIG.DEFAULT_COLOR)
    local colorStyle = COLOR_MAP[color] or COLOR_MAP[CONFIG.DEFAULT_COLOR]
    local attribute = safeGet(cardData, "属性", CONFIG.DEFAULT_ATTRIBUTE)
    local cardDeck = safeGet(cardData, "卡组", CONFIG.DEFAULT_DECK)
    local borderStyle = cardDeck == "起始卡牌" and "normal" or "unique"
    
    return {
        color = color,
        colorStyle = colorStyle,
        attribute = attribute,
        borderStyle = borderStyle,
        ap = safeGet(cardData, "AP", ""),
        cardType = safeGet(cardData, "类型", ""),
        art = safeGet(cardData, "art", CONFIG.DEFAULT_ART)
    }
end

-- 构建卡牌HTML
local function buildCardHTML(frame, cardName, cardData)
    if not cardData then
        return string.format("找不到卡牌数据: %s", cardName or "未指定")
    end
    
    local style = buildStyleComponents(cardData, cardName)
    local description = processDescription(frame, safeGet(cardData, "描述", ""))
    
    -- 使用字符串拼接优化HTML生成
    local htmlParts = {
        string.format('<div style="position: relative; width: %dpx; height: %dpx; overflow: hidden;">', 
            CONFIG.CARD_WIDTH, CONFIG.CARD_HEIGHT),
        
        -- 背景图片层
        string.format('<div style="position: absolute; top: 1px; left: 12px;">[[File:%s|151px|link=]]</div>', style.art),
        '<div style="position: absolute; top: 1px; left: 12px;">[[File:card_黑色蒙版.png|151px|link=]]</div>',
        
        -- 颜色条
        string.format('<div style="position: absolute; top: 20px; left: 10px; width: 148px; height: 10px; background-color: %s;"></div>', 
            style.colorStyle.bgColor),
        
        -- AP值
        string.format('<div style="position: absolute; left: 23px; top: 4px; color: white; font-weight: bold; text-shadow: 0 0 10px #4a90e2,0 0 20px #4a90e2, 0 0 30px #4a90e2, 0 0 40px #4a90e2; font-size: 32px;">%s</div>', 
            style.ap),
        '<div style="position: absolute; left: 25px; top: 34px; color: white; font-weight: bold; text-shadow: 0 0 10px #4a90e2,0 0 20px #4a90e2, 0 0 30px #4a90e2, 0 0 40px #4a90e2;">—</div>',
        
        -- 卡牌名称和类型
        string.format('<div style="position: absolute; left: 50px; top: 13px; color: %s; font-size:16px">%s</div>', 
            style.colorStyle.textColor, cardName),
        string.format('<div style="position: absolute; left: 48px; top: 30px;">[[File:icon_card_%s.png|18px|link=]]</div>', 
            style.cardType),
        string.format('<div style="position: absolute; left: 68px; top: 33px; color: white; font-size:14px">%s</div>', 
            style.cardType),
        
        -- 边框和稀有度
        string.format('<div style="position: absolute; top: 0px; left: 1px;">[[File:card_属性边框_%s_%s.png|160px|link=]]</div>', 
            style.attribute, style.borderStyle),
        string.format('<div style="position: absolute; top: 10px; left: 0px;">[[File:card_稀有度_%s.png|22px|link=]]</div>', 
            style.color),
        string.format('<div style="position: absolute; top: 2px; right: 4px;">[[File:card_稀有度_边框_%s.png|11px|link=]]</div>', 
            style.color),
        
        -- 描述文本
        '<div style="position: absolute; bottom: 7px; left: 15px; width: 144px; height: 100px; font-size: 12px; color: white; line-height: 13px; display: flex; justify-content: center; align-items: center; text-align: center;">',
        string.format('<div>%s</div>', description),
        '</div>',
        '</div>'
    }
    
    return table.concat(htmlParts)
end

-- 合并卡牌数据
local function mergeCardData(baseData, overrideData)
    local result = {}
    for k, v in pairs(baseData or {}) do
        result[k] = v
    end
    for k, v in pairs(overrideData or {}) do
        result[k] = v
    end
    return result
end

-- 获取并显示所有默认卡牌
local function displayAllDefaultCards(frame, characterModule)
    local cards = characterModule.card or {}
    local cardOrder = characterModule.cardOrder or {}
    local displayedCards = {}
    
    -- 按cardOrder顺序遍历
    for orderIndex, name in ipairs(cardOrder) do
        local cardArray = cards[name]
        if cardArray and #cardArray > 0 then
            -- 只显示第一张卡牌
            table.insert(displayedCards, {
                name = name,
                data = cardArray[1],
                order = orderIndex
            })
        end
    end
    
    -- 生成HTML
    local htmlParts = {}
    for i, cardInfo in ipairs(displayedCards) do
        table.insert(htmlParts, buildCardHTML(frame, cardInfo.name, cardInfo.data))
        if i < #displayedCards then
            table.insert(htmlParts, "<br><br>")
        end
    end
    
    return table.concat(htmlParts)
end

-- 处理特定卡牌请求
local function handleSpecificCard(frame, cardName, cardData, deckFilter, cardIndex)
    local baseCard = cardData[1]
    
    -- 如果没有指定卡组筛选,返回基础卡牌
    if deckFilter == "" then
        return buildCardHTML(frame, cardName, baseCard)
    end
    
    -- 筛选指定卡组的卡牌
    local filteredCards = {}
    for _, card in ipairs(cardData) do
        if card["卡组"] == deckFilter then
            table.insert(filteredCards, card)
        end
    end
    
    if #filteredCards == 0 then
        return string.format("找不到卡组 '%s' 的卡牌: %s", deckFilter, cardName)
    end
    
    -- 如果指定了索引,返回特定卡牌
    if cardIndex > 0 and cardIndex <= #filteredCards then
        local mergedCard = mergeCardData(baseCard, filteredCards[cardIndex])
        return buildCardHTML(frame, cardName, mergedCard)
    end
    
    -- 否则返回该卡组的所有卡牌
    local htmlParts = {}
    for i, card in ipairs(filteredCards) do
        local mergedCard = mergeCardData(baseCard, card)
        table.insert(htmlParts, buildCardHTML(frame, cardName, mergedCard))
        if i < #filteredCards then
            table.insert(htmlParts, "<br><br>")
        end
    end
    
    return table.concat(htmlParts)
end

-- 主函数
function p.main(frame)
    local args = frame.args
    local characterName = args[1] or ""
    local cardName = args[2] or ""
    local deckFilter = args[3] or ""
    local cardIndex = tonumber(args[4]) or 0
    
    -- 加载战斗员模块
    local success, characterModule = pcall(require, "模块:卡牌/" .. characterName)
    if not success or not characterModule then
        return string.format("找不到战斗员卡牌数据模块: 模块:卡牌/%s", characterName)
    end
    
    -- 如果没有指定卡牌名,显示所有默认卡牌
    if cardName == "" then
        return displayAllDefaultCards(frame, characterModule)
    end
    
    -- 获取指定卡牌数据
    local cardData = (characterModule.card or {})[cardName]
    if not cardData then
        return string.format("找不到卡牌: %s", cardName)
    end
    
    return handleSpecificCard(frame, cardName, cardData, deckFilter, cardIndex)
end

-- 元表设置,支持直接调用战斗员名称作为方法
setmetatable(p, {
    __index = function(t, characterName)
        return function(frame)
            frame.args = {
                [1] = characterName,
                [2] = frame.args[1] or "",
                [3] = frame.args[2] or "",
                [4] = frame.args[3] or 0
            }
            return p.main(frame)
        end
    end
})

return p