模块

卡牌:修订间差异

来自卡厄思梦境WIKI

律Rhyme留言 | 贡献
撤销律Rhyme讨论)的修订版本826
标签撤销
律Rhyme留言 | 贡献
无编辑摘要
标签已被回退
第1行: 第1行:
local p = {}
local p = {}


-- 颜色映射表
-- 颜色映射表(保持不变但添加快速查找)
local COLOR_MAP = {
local COLOR_MAP = {
     ["白"] = { bgColor = "rgba(249, 249, 249, 0.5)", textColor = "white" },
     ["白"] = { bgColor = "rgba(249, 249, 249, 0.5)", textColor = "white" },
第8行: 第8行:
     ["彩"] = { bgColor = "rgba(201, 88, 241, 0.5)", textColor = "#eba2fc" }
     ["彩"] = { bgColor = "rgba(201, 88, 241, 0.5)", textColor = "#eba2fc" }
}
}
local DEFAULT_COLOR = COLOR_MAP["白"]


-- 安全获取数据字段
-- 优化:减少函数调用,内联简单操作
local function safeGet(data, field, default)
local function safeGet(data, field, default)
     return data and data[field] or default
     local value = data and data[field]
    return (value ~= nil and value ~= "") and value or default
end
end


-- 处理描述文本中的模板
-- 优化:添加缓存避免重复处理
local descriptionCache = {}
local function processDescription(frame, description)
local function processDescription(frame, description)
     if not description or description == "" then
     if not description or description == "" then
         return description
         return ""
    end
   
    -- 检查缓存
    if descriptionCache[description] then
        return descriptionCache[description]
     end
     end
      
      
第24行: 第32行:
     end)
     end)
      
      
     return success and result or description
     local processed = success and result or description
    descriptionCache[description] = processed
    return processed
end
 
-- 优化:预构建HTML片段,减少字符串操作
local function buildImageTag(filename, size, extraStyle)
    extraStyle = extraStyle or ""
    return string.format('[[File:%s|%spx|link=]]', filename, size)
end
end


-- 生成卡牌HTML样式组件
-- 优化:合并样式计算,减少重复代码
local function buildStyleComponents(cardData, cardName, baseCardData)
local function calculateCardStyle(cardData, baseCardData)
     local color = safeGet(cardData, "稀有度", "白")
     local color = safeGet(cardData, "稀有度", "白")
     local colorStyle = COLOR_MAP[color] or COLOR_MAP["白"]
     local colorStyle = COLOR_MAP[color] or DEFAULT_COLOR
    local attribute = safeGet(cardData, "属性", "虚无")
    local cardDeck = safeGet(cardData, "卡组", "起始卡牌")
   
     local ap = safeGet(cardData, "AP", "")
     local ap = safeGet(cardData, "AP", "")
     local originalAP = baseCardData and safeGet(baseCardData, "AP", ap) or ap
     local originalAP = baseCardData and safeGet(baseCardData, "AP", ap) or ap
      
      
     -- 决定AP的发光颜色
     -- AP发光颜色计算
     local apGlowColor = "#4a90e2" -- 默认蓝色
     local apGlowColor = "#4a90e2"
     if baseCardData and ap ~= originalAP then
     if baseCardData and ap ~= originalAP and ap ~= "X" then
        if ap == "X" then
        local apNum, origNum = tonumber(ap), tonumber(originalAP)
            apGlowColor = "#4a90e2" -- X值保持默认蓝色
        if apNum and origNum then
        elseif tonumber(ap) and tonumber(originalAP) then
            apGlowColor = apNum < origNum and "#51f651" or "#f65151"
            if tonumber(ap) < tonumber(originalAP) then
                apGlowColor = "#51f651" -- 绿色(AP降低)
            else
                apGlowColor = "#f65151" -- 红色(AP增加)
            end
         end
         end
     end
     end
      
      
     -- 检查原卡牌与当前卡牌的机制变化
     -- 机制变化检测
     local mechanism = safeGet(cardData, "机制", "")
     local mechanism = safeGet(cardData, "机制", "")
     local originalMechanism = baseCardData and safeGet(baseCardData, "机制", "") or mechanism
     local originalMechanism = baseCardData and safeGet(baseCardData, "机制", "") or mechanism
      
     mechanism = mechanism == "无" and "" or mechanism
    -- 将"无"视为空字符串
     originalMechanism = originalMechanism == "无" and "" or originalMechanism
    if mechanism == "无" then mechanism = "" end
     if originalMechanism == "无" then originalMechanism = "" end
   
    local mechanismChanged = baseCardData and mechanism ~= "" and originalMechanism == ""
      
      
     return {
     return {
         color = color,
         color = color,
         colorStyle = colorStyle,
         colorStyle = colorStyle,
         attribute = attribute,
         attribute = safeGet(cardData, "属性", "虚无"),
        cardType = safeGet(cardData, "类型", ""),
        art = safeGet(cardData, "art", ""),
         ap = ap,
         ap = ap,
         apGlowColor = apGlowColor,
         apGlowColor = apGlowColor,
        cardType = safeGet(cardData, "类型", ""),
        art = safeGet(cardData, "art", ""),
         mechanism = mechanism,
         mechanism = mechanism,
         mechanismChanged = mechanismChanged
         mechanismChanged = baseCardData and mechanism ~= "" and originalMechanism == ""
     }
     }
end
end


-- 构建卡牌HTML
-- 优化:使用局部变量减少表查找
local format = string.format
local insert = table.insert
local concat = table.concat
 
-- 优化:模板化HTML生成
-- 修复后的 buildCardHTML 函数中的HTML生成部分
local function buildCardHTML(frame, cardName, cardData, baseCardData, characterName)
local function buildCardHTML(frame, cardName, cardData, baseCardData, characterName)
     if not cardData then
     if not cardData then
         return string.format("找不到卡牌数据: %s", cardName or "未指定")
         return format('<div style="color:red;">找不到卡牌: %s</div>', cardName or "未指定")
     end
     end
      
      
     local style = buildStyleComponents(cardData, cardName, baseCardData)
     local style = calculateCardStyle(cardData, baseCardData)
     local description = processDescription(frame, safeGet(cardData, "描述", ""))
     local description = processDescription(frame, safeGet(cardData, "描述", ""))
      
      
     -- 获取衍生卡牌信息
     -- 数据属性
     local derivedCards = safeGet(cardData, "衍生卡牌", "")
     local dataAttrs = format(
    local deckType = safeGet(cardData, "卡组", "")
        'data-card-name="%s" data-character="%s" data-deck-type="%s" data-derived-cards="%s"',
        cardName or "",
        characterName or "",
        safeGet(cardData, "卡组", ""),
        safeGet(cardData, "衍生卡牌", "")
    )
      
      
     -- 生成数据属性
     -- 机制HTML(优化:提前判断避免无用字符串生成)
    local dataAttrs = string.format('data-card-name="%s" data-character="%s" data-deck-type="%s" data-derived-cards="%s"',
        cardName or "", characterName or "", deckType or "", derivedCards or "")
   
    -- 处理机制文本(修改:当机制为"无"时不显示)
     local mechanismHTML = ""
     local mechanismHTML = ""
     if style.mechanism and style.mechanism ~= "" and style.mechanism ~= "无" then
     if style.mechanism ~= "" then
         local mechanismColor = style.mechanismChanged and "#b5f651" or "#f6c478"
         local mechanismColor = style.mechanismChanged and "#b5f651" or "#f6c478"
         mechanismHTML = string.format('<div style="color: %s; margin-bottom: 4px;">[%s]</div>',  
         mechanismHTML = format(
             mechanismColor, style.mechanism:gsub("、", "/"))
            '<div style="color: %s; margin-bottom: 4px;">[%s]</div>',  
             mechanismColor,  
            style.mechanism:gsub("、", "/")
        )
     end
     end
      
      
     -- 使用字符串拼接优化HTML生成
     -- AP显示(复用格式字符串)
     local htmlParts = {
     local apShadow = format(
         string.format('<div class="game-card" %s style="display: inline-block; vertical-align: top; position: relative; width: 168px; height: 230px; overflow: hidden; margin: 0px; cursor: pointer;">', dataAttrs),
        "0 0 10px %s,0 0 20px %s, 0 0 30px %s, 0 0 40px %s",
     }
         style.apGlowColor, style.apGlowColor, style.apGlowColor, style.apGlowColor
    )
   
    local html = {}
   
    -- 容器开始
    insert(html, format(
        '<div class="game-card" %s style="display: inline-block; vertical-align: top; position: relative; width: 168px; height: 230px; overflow: hidden; margin: 0px; cursor: pointer;">',
        dataAttrs
     ))
      
      
     -- 根据类型判断使用哪种布局
     -- 根据类型使用不同模板
     if style.cardType == "状态异常" then
     if style.cardType == "状态异常" then
         -- 状态异常卡牌的特殊布局
         -- 状态异常布局(使用 [=[ ]=] 避免冲突)
         table.insert(htmlParts, string.format('<div style="position: absolute; top: 5px; left: 5px;">[[File:%s|150px|link=]]</div>', style.art))
         insert(html, format([=[
        table.insert(htmlParts, string.format('<div style="position: absolute; top: 0px; left: 0px;">[[File:card_状态异常_%s.png|159px|link=]]</div>', style.attribute))
<div style="position: absolute; top: 5px; left: 5px;">%s</div>
       
<div style="position: absolute; top: 0px; left: 0px;">%s</div>
        -- AP值
<div style="position: absolute; left: 24px; top: 4px; color: white; font-weight: bold; text-shadow: %s; font-size: 32px;">%s</div>
        table.insert(htmlParts, string.format('<div style="position: absolute; left: 24px; top: 4px; color: white; font-weight: bold; text-shadow: 0 0 10px %s,0 0 20px %s, 0 0 30px %s, 0 0 40px %s; font-size: 32px;">%s</div>',
<div style="position: absolute; left: 25px; top: 34px; color: white; font-weight: bold; text-shadow: %s;">—</div>
            style.apGlowColor, style.apGlowColor, style.apGlowColor, style.apGlowColor, style.ap))
<div style="position: absolute; left: 50px; top: 13px; color: %s; font-size:16px">%s</div>
        table.insert(htmlParts, string.format('<div style="position: absolute; left: 25px; top: 34px; color: white; font-weight: bold; text-shadow: 0 0 10px %s,0 0 20px %s, 0 0 30px %s, 0 0 40px %s;">—</div>',
<div style="position: absolute; left: 48px; top: 30px;">%s</div>
            style.apGlowColor, style.apGlowColor, style.apGlowColor, style.apGlowColor))
<div style="position: absolute; left: 68px; top: 33px; color: white; font-size:14px">%s</div>
       
<div style="position: absolute; left: 0px; bottom: 0px;">[[File:card_顶层蒙版.png|168px|link=]]</div>]=],
        -- 卡牌名称和类型
            buildImageTag(style.art, 150),
        table.insert(htmlParts, string.format('<div style="position: absolute; left: 50px; top: 13px; color: %s; font-size:16px">%s</div>',
            buildImageTag(format("card_状态异常_%s.png", style.attribute), 159),
            style.colorStyle.textColor, cardName))
            apShadow, style.ap,
        table.insert(htmlParts, string.format('<div style="position: absolute; left: 48px; top: 30px;">[[File:icon_card_%s.png|18px|link=]]</div>',
            apShadow,
            style.cardType))
            style.colorStyle.textColor, cardName,
        table.insert(htmlParts, string.format('<div style="position: absolute; left: 68px; top: 33px; color: white; font-size:14px">%s</div>',
            buildImageTag(format("icon_card_%s.png", style.cardType), 18),
            style.cardType))
            style.cardType
       
         ))
        -- 顶层蒙版
        table.insert(htmlParts, '<div style="position: absolute; left: 0px; bottom: 0px;">[[File:card_顶层蒙版.png|168px|link=]]</div>')
          
     else
     else
         -- 普通卡牌的布局
         -- 普通卡牌布局(使用 [=[ ]=] 避免冲突)
         -- 背景图片层
         insert(html, format([=[
        table.insert(htmlParts, 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;">%s</div>
        table.insert(htmlParts, '<div style="position: absolute; top: 1px; left: 12px;">[[File:card_黑色蒙版.png|151px|link=]]</div>')
<div style="position: absolute; top: 1px; left: 12px;">[[File:card_黑色蒙版.png|151px|link=]]</div>
       
<div style="position: absolute; top: 21px; left: 10px; width: 148px; height: 8px; background-color: %s;"></div>
        -- 颜色条
<div style="position: absolute; left: 24px; top: 4px; color: white; font-weight: bold; text-shadow: %s; font-size: 32px;">%s</div>
        table.insert(htmlParts, string.format('<div style="position: absolute; top: 21px; left: 10px; width: 148px; height: 8px; background-color: %s;"></div>',
<div style="position: absolute; left: 25px; top: 34px; color: white; font-weight: bold; text-shadow: %s;">—</div>
            style.colorStyle.bgColor))
<div style="position: absolute; left: 50px; top: 13px; color: %s; font-size:16px">%s</div>
       
<div style="position: absolute; left: 48px; top: 30px;">%s</div>
        -- AP值
<div style="position: absolute; left: 68px; top: 33px; color: white; font-size:14px">%s</div>
        table.insert(htmlParts, string.format('<div style="position: absolute; left: 24px; top: 4px; color: white; font-weight: bold; text-shadow: 0 0 10px %s,0 0 20px %s, 0 0 30px %s, 0 0 40px %s; font-size: 32px;">%s</div>',
<div style="position: absolute; top: 0px; left: 1px;">%s</div>
            style.apGlowColor, style.apGlowColor, style.apGlowColor, style.apGlowColor, style.ap))
<div style="position: absolute; top: 10px; left: 0px;">%s</div>
        table.insert(htmlParts, string.format('<div style="position: absolute; left: 25px; top: 34px; color: white; font-weight: bold; text-shadow: 0 0 10px %s,0 0 20px %s, 0 0 30px %s, 0 0 40px %s;">—</div>',
<div style="position: absolute; top: 2px; right: 4px;">%s</div>
            style.apGlowColor, style.apGlowColor, style.apGlowColor, style.apGlowColor))
<div style="position: absolute; left: 0px; bottom: 0px;">[[File:card_顶层蒙版.png|168px|link=]]</div>]=],
       
            buildImageTag(style.art, 151),
        -- 卡牌名称和类型
            style.colorStyle.bgColor,
        table.insert(htmlParts, string.format('<div style="position: absolute; left: 50px; top: 13px; color: %s; font-size:16px">%s</div>',
            apShadow, style.ap,
            style.colorStyle.textColor, cardName))
            apShadow,
        table.insert(htmlParts, string.format('<div style="position: absolute; left: 48px; top: 30px;">[[File:icon_card_%s.png|18px|link=]]</div>',
            style.colorStyle.textColor, cardName,
            style.cardType))
            buildImageTag(format("icon_card_%s.png", style.cardType), 18),
        table.insert(htmlParts, string.format('<div style="position: absolute; left: 68px; top: 33px; color: white; font-size:14px">%s</div>',
            style.cardType,
            style.cardType))
            buildImageTag(format("card_属性边框_%s.png", style.attribute), 160),
       
            buildImageTag(format("card_稀有度_%s.png", style.color), 22),
        -- 边框
            buildImageTag(format("card_稀有度_边框_%s.png", style.color), 11)
        table.insert(htmlParts, string.format('<div style="position: absolute; top: 0px; left: 1px;">[[File:card_属性边框_%s.png|160px|link=]]</div>',
        ))
            style.attribute))
        -- 稀有度
        table.insert(htmlParts, string.format('<div style="position: absolute; top: 10px; left: 0px;">[[File:card_稀有度_%s.png|22px|link=]]</div>',
            style.color))
        table.insert(htmlParts, string.format('<div style="position: absolute; top: 2px; right: 4px;">[[File:card_稀有度_边框_%s.png|11px|link=]]</div>',
            style.color))
       
        -- 顶层蒙版
        table.insert(htmlParts, '<div style="position: absolute; left: 0px; bottom: 0px;">[[File:card_顶层蒙版.png|168px|link=]]</div>')
     end
     end
      
      
     -- 描述文本
     -- 描述区域(使用 [=[ ]=] 避免冲突)
     table.insert(htmlParts, '<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;">')
     insert(html, format([=[
    table.insert(htmlParts, '<div style="line-height: 13px;">')
<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;">
    table.insert(htmlParts, mechanismHTML)
<div style="line-height: 13px;">%s%s</div>
    table.insert(htmlParts, description)
</div>
    table.insert(htmlParts, '</div>')
</div>]=], mechanismHTML, description))
    table.insert(htmlParts, '</div>')
    table.insert(htmlParts, '</div>')
      
      
     return table.concat(htmlParts)
     return concat(html)
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
end


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


-- 处理特定卡牌请求
local function handleSpecificCard(frame, cardName, cardData, deckFilter, cardIndex, characterName)
local function handleSpecificCard(frame, cardName, cardData, deckFilter, cardIndex, characterName)
     local baseCard = cardData[1]
     local baseCard = cardData[1]
      
      
    -- 如果没有指定卡组筛选,返回基础卡牌
     if deckFilter == "" then
     if deckFilter == "" then
         return buildCardHTML(frame, cardName, baseCard, nil, characterName)
         return buildCardHTML(frame, cardName, baseCard, nil, characterName)
     end
     end
      
      
     -- 筛选指定卡组的卡牌
     -- 筛选卡组
     local filteredCards = {}
     local filteredCards = {}
     for _, card in ipairs(cardData) do
     for _, card in ipairs(cardData) do
         if card["卡组"] == deckFilter then
         if card["卡组"] == deckFilter then
             table.insert(filteredCards, card)
             insert(filteredCards, card)
         end
         end
     end
     end
      
      
     if #filteredCards == 0 then
     if #filteredCards == 0 then
         return string.format("找不到卡组 '%s' 的卡牌: %s", deckFilter, cardName)
         return format('<div style="color:orange;">找不到卡组 "%s" 的卡牌: %s</div>', deckFilter, cardName)
     end
     end
      
      
     -- 如果指定了索引,返回特定卡牌
     -- 合并数据函数
    local function mergeData(base, override)
        local result = {}
        for k, v in pairs(base) do result[k] = v end
        for k, v in pairs(override) do result[k] = v end
        return result
    end
   
    -- 特定索引
     if cardIndex > 0 and cardIndex <= #filteredCards then
     if cardIndex > 0 and cardIndex <= #filteredCards then
         local mergedCard = mergeCardData(baseCard, filteredCards[cardIndex])
         return buildCardHTML(frame, cardName, mergeData(baseCard, filteredCards[cardIndex]), baseCard, characterName)
        return buildCardHTML(frame, cardName, mergedCard, baseCard, characterName)
     end
     end
      
      
     -- 否则返回该卡组的所有卡牌
     -- 所有卡牌
     local htmlParts = {}
     local htmlParts = {}
     for i, card in ipairs(filteredCards) do
     for _, card in ipairs(filteredCards) do
         local mergedCard = mergeCardData(baseCard, card)
         insert(htmlParts, buildCardHTML(frame, cardName, mergeData(baseCard, card), baseCard, characterName))
        table.insert(htmlParts, buildCardHTML(frame, cardName, mergedCard, baseCard, characterName))
     end
     end
      
      
     return table.concat(htmlParts)
     return concat(htmlParts)
end
end


第261行: 第254行:
     local cardIndex = tonumber(args[4]) or 0
     local cardIndex = tonumber(args[4]) or 0
      
      
     -- 加载战斗员模块
     -- 失败
    if characterName == "" then
        return '<div style="color:red;">请指定战斗员名称</div>'
    end
   
    -- 加载模块
     local success, characterModule = pcall(require, "模块:卡牌/" .. characterName)
     local success, characterModule = pcall(require, "模块:卡牌/" .. characterName)
     if not success or not characterModule then
     if not success or not characterModule then
         return string.format("找不到战斗员卡牌数据模块: 模块:卡牌/%s", characterName)
         return format('<div style="color:red;">找不到战斗员: %s</div>', characterName)
     end
     end
      
      
     -- 如果没有指定卡牌名,显示所有默认卡牌
     -- 显示所有卡牌
     if cardName == "" then
     if cardName == "" then
         return displayAllDefaultCards(frame, characterModule, characterName)
         return displayAllDefaultCards(frame, characterModule, characterName)
     end
     end
      
      
     -- 获取指定卡牌数据
     -- 显示特定卡牌
     local cardData = (characterModule.card or {})[cardName]
     local cardData = (characterModule.card or {})[cardName]
     if not cardData then
     if not cardData then
         return string.format("找不到卡牌: %s", cardName)
         return format('<div style="color:red;">找不到卡牌: %s</div>', cardName)
     end
     end
      
      
第281行: 第279行:
end
end


-- 元表设置,支持直接调用战斗员名称作为方法
-- 元表设置
setmetatable(p, {
setmetatable(p, {
     __index = function(t, characterName)
     __index = function(t, characterName)

2025年10月1日 (三) 21:15的版本

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

local p = {}

-- 颜色映射表(保持不变但添加快速查找)
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 DEFAULT_COLOR = COLOR_MAP["白"]

-- 优化:减少函数调用,内联简单操作
local function safeGet(data, field, default)
    local value = data and data[field]
    return (value ~= nil and value ~= "") and value or default
end

-- 优化:添加缓存避免重复处理
local descriptionCache = {}
local function processDescription(frame, description)
    if not description or description == "" then
        return ""
    end
    
    -- 检查缓存
    if descriptionCache[description] then
        return descriptionCache[description]
    end
    
    local success, result = pcall(function()
        return frame:preprocess(description)
    end)
    
    local processed = success and result or description
    descriptionCache[description] = processed
    return processed
end

-- 优化:预构建HTML片段,减少字符串操作
local function buildImageTag(filename, size, extraStyle)
    extraStyle = extraStyle or ""
    return string.format('[[File:%s|%spx|link=]]', filename, size)
end

-- 优化:合并样式计算,减少重复代码
local function calculateCardStyle(cardData, baseCardData)
    local color = safeGet(cardData, "稀有度", "白")
    local colorStyle = COLOR_MAP[color] or DEFAULT_COLOR
    local ap = safeGet(cardData, "AP", "")
    local originalAP = baseCardData and safeGet(baseCardData, "AP", ap) or ap
    
    -- AP发光颜色计算
    local apGlowColor = "#4a90e2"
    if baseCardData and ap ~= originalAP and ap ~= "X" then
        local apNum, origNum = tonumber(ap), tonumber(originalAP)
        if apNum and origNum then
            apGlowColor = apNum < origNum and "#51f651" or "#f65151"
        end
    end
    
    -- 机制变化检测
    local mechanism = safeGet(cardData, "机制", "")
    local originalMechanism = baseCardData and safeGet(baseCardData, "机制", "") or mechanism
    mechanism = mechanism == "无" and "" or mechanism
    originalMechanism = originalMechanism == "无" and "" or originalMechanism
    
    return {
        color = color,
        colorStyle = colorStyle,
        attribute = safeGet(cardData, "属性", "虚无"),
        cardType = safeGet(cardData, "类型", ""),
        art = safeGet(cardData, "art", ""),
        ap = ap,
        apGlowColor = apGlowColor,
        mechanism = mechanism,
        mechanismChanged = baseCardData and mechanism ~= "" and originalMechanism == ""
    }
end

-- 优化:使用局部变量减少表查找
local format = string.format
local insert = table.insert
local concat = table.concat

-- 优化:模板化HTML生成
-- 修复后的 buildCardHTML 函数中的HTML生成部分
local function buildCardHTML(frame, cardName, cardData, baseCardData, characterName)
    if not cardData then
        return format('<div style="color:red;">找不到卡牌: %s</div>', cardName or "未指定")
    end
    
    local style = calculateCardStyle(cardData, baseCardData)
    local description = processDescription(frame, safeGet(cardData, "描述", ""))
    
    -- 数据属性
    local dataAttrs = format(
        'data-card-name="%s" data-character="%s" data-deck-type="%s" data-derived-cards="%s"',
        cardName or "", 
        characterName or "", 
        safeGet(cardData, "卡组", ""), 
        safeGet(cardData, "衍生卡牌", "")
    )
    
    -- 机制HTML(优化:提前判断避免无用字符串生成)
    local mechanismHTML = ""
    if style.mechanism ~= "" then
        local mechanismColor = style.mechanismChanged and "#b5f651" or "#f6c478"
        mechanismHTML = format(
            '<div style="color: %s; margin-bottom: 4px;">[%s]</div>', 
            mechanismColor, 
            style.mechanism:gsub("、", "/")
        )
    end
    
    -- AP显示(复用格式字符串)
    local apShadow = format(
        "0 0 10px %s,0 0 20px %s, 0 0 30px %s, 0 0 40px %s",
        style.apGlowColor, style.apGlowColor, style.apGlowColor, style.apGlowColor
    )
    
    local html = {}
    
    -- 容器开始
    insert(html, format(
        '<div class="game-card" %s style="display: inline-block; vertical-align: top; position: relative; width: 168px; height: 230px; overflow: hidden; margin: 0px; cursor: pointer;">',
        dataAttrs
    ))
    
    -- 根据类型使用不同模板
    if style.cardType == "状态异常" then
        -- 状态异常布局(使用 [=[ ]=] 避免冲突)
        insert(html, format([=[
<div style="position: absolute; top: 5px; left: 5px;">%s</div>
<div style="position: absolute; top: 0px; left: 0px;">%s</div>
<div style="position: absolute; left: 24px; top: 4px; color: white; font-weight: bold; text-shadow: %s; font-size: 32px;">%s</div>
<div style="position: absolute; left: 25px; top: 34px; color: white; font-weight: bold; text-shadow: %s;">—</div>
<div style="position: absolute; left: 50px; top: 13px; color: %s; font-size:16px">%s</div>
<div style="position: absolute; left: 48px; top: 30px;">%s</div>
<div style="position: absolute; left: 68px; top: 33px; color: white; font-size:14px">%s</div>
<div style="position: absolute; left: 0px; bottom: 0px;">[[File:card_顶层蒙版.png|168px|link=]]</div>]=],
            buildImageTag(style.art, 150),
            buildImageTag(format("card_状态异常_%s.png", style.attribute), 159),
            apShadow, style.ap,
            apShadow,
            style.colorStyle.textColor, cardName,
            buildImageTag(format("icon_card_%s.png", style.cardType), 18),
            style.cardType
        ))
    else
        -- 普通卡牌布局(使用 [=[ ]=] 避免冲突)
        insert(html, format([=[
<div style="position: absolute; top: 1px; left: 12px;">%s</div>
<div style="position: absolute; top: 1px; left: 12px;">[[File:card_黑色蒙版.png|151px|link=]]</div>
<div style="position: absolute; top: 21px; left: 10px; width: 148px; height: 8px; background-color: %s;"></div>
<div style="position: absolute; left: 24px; top: 4px; color: white; font-weight: bold; text-shadow: %s; font-size: 32px;">%s</div>
<div style="position: absolute; left: 25px; top: 34px; color: white; font-weight: bold; text-shadow: %s;">—</div>
<div style="position: absolute; left: 50px; top: 13px; color: %s; font-size:16px">%s</div>
<div style="position: absolute; left: 48px; top: 30px;">%s</div>
<div style="position: absolute; left: 68px; top: 33px; color: white; font-size:14px">%s</div>
<div style="position: absolute; top: 0px; left: 1px;">%s</div>
<div style="position: absolute; top: 10px; left: 0px;">%s</div>
<div style="position: absolute; top: 2px; right: 4px;">%s</div>
<div style="position: absolute; left: 0px; bottom: 0px;">[[File:card_顶层蒙版.png|168px|link=]]</div>]=],
            buildImageTag(style.art, 151),
            style.colorStyle.bgColor,
            apShadow, style.ap,
            apShadow,
            style.colorStyle.textColor, cardName,
            buildImageTag(format("icon_card_%s.png", style.cardType), 18),
            style.cardType,
            buildImageTag(format("card_属性边框_%s.png", style.attribute), 160),
            buildImageTag(format("card_稀有度_%s.png", style.color), 22),
            buildImageTag(format("card_稀有度_边框_%s.png", style.color), 11)
        ))
    end
    
    -- 描述区域(使用 [=[ ]=] 避免冲突)
    insert(html, format([=[
<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 style="line-height: 13px;">%s%s</div>
</div>
</div>]=], mechanismHTML, description))
    
    return concat(html)
end

-- 批量生成卡牌HTML
local function displayAllDefaultCards(frame, characterModule, characterName)
    local cards = characterModule.card or {}
    local cardOrder = characterModule.cardOrder or {}
    
    if #cardOrder == 0 then
        return "<div>没有找到卡牌顺序信息</div>"
    end
    
    local htmlParts = {}
    for _, name in ipairs(cardOrder) do
        local cardArray = cards[name]
        if cardArray and #cardArray > 0 then
            insert(htmlParts, buildCardHTML(frame, name, cardArray[1], nil, characterName))
        end
    end
    
    return concat(htmlParts)
end

local function handleSpecificCard(frame, cardName, cardData, deckFilter, cardIndex, characterName)
    local baseCard = cardData[1]
    
    if deckFilter == "" then
        return buildCardHTML(frame, cardName, baseCard, nil, characterName)
    end
    
    -- 筛选卡组
    local filteredCards = {}
    for _, card in ipairs(cardData) do
        if card["卡组"] == deckFilter then
            insert(filteredCards, card)
        end
    end
    
    if #filteredCards == 0 then
        return format('<div style="color:orange;">找不到卡组 "%s" 的卡牌: %s</div>', deckFilter, cardName)
    end
    
    -- 合并数据函数
    local function mergeData(base, override)
        local result = {}
        for k, v in pairs(base) do result[k] = v end
        for k, v in pairs(override) do result[k] = v end
        return result
    end
    
    -- 特定索引
    if cardIndex > 0 and cardIndex <= #filteredCards then
        return buildCardHTML(frame, cardName, mergeData(baseCard, filteredCards[cardIndex]), baseCard, characterName)
    end
    
    -- 所有卡牌
    local htmlParts = {}
    for _, card in ipairs(filteredCards) do
        insert(htmlParts, buildCardHTML(frame, cardName, mergeData(baseCard, card), baseCard, characterName))
    end
    
    return 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
    
    -- 失败
    if characterName == "" then
        return '<div style="color:red;">请指定战斗员名称</div>'
    end
    
    -- 加载模块
    local success, characterModule = pcall(require, "模块:卡牌/" .. characterName)
    if not success or not characterModule then
        return format('<div style="color:red;">找不到战斗员: %s</div>', characterName)
    end
    
    -- 显示所有卡牌
    if cardName == "" then
        return displayAllDefaultCards(frame, characterModule, characterName)
    end
    
    -- 显示特定卡牌
    local cardData = (characterModule.card or {})[cardName]
    if not cardData then
        return format('<div style="color:red;">找不到卡牌: %s</div>', cardName)
    end
    
    return handleSpecificCard(frame, cardName, cardData, deckFilter, cardIndex, characterName)
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