卡牌:修订间差异
来自卡厄思梦境WIKI
无编辑摘要 |
小无编辑摘要 |
||
| 第1行: | 第1行: | ||
-- 模块:卡牌 | |||
local p = {} | local p = {} | ||
| 第72行: | 第73行: | ||
end | end | ||
-- | -- 从原始机制文本中提取机制名称列表(处理模板语法前) | ||
local function | local function extractMechanismNames(mechanismText) | ||
if not | if not mechanismText or mechanismText == "" or mechanismText == "无" then | ||
return | return {} | ||
end | end | ||
local mechanismList = {} | |||
-- 匹配所有 {{词典|xxx}} 模板 | |||
for mechName in mechanismText:gmatch("{{词典|([^}]+)}}") do | |||
mechName = mw.text.trim(mechName) | |||
if mechName ~= "" then | |||
if | table.insert(mechanismList, mechName) | ||
end | end | ||
end | end | ||
-- | -- 如果没有找到词典模板,尝试直接解析文本 | ||
if #mechanismList == 0 then | |||
-- 先按"、"分割 | |||
local parts1 = splitString(mechanismText, "、") | |||
for _, part in ipairs(parts1) do | |||
-- 再按"/"分割 | |||
local parts2 = splitString(part, "/") | |||
for _, p in ipairs(parts2) do | |||
table.insert(mechanismList, p) | |||
end | |||
end | |||
end | |||
-- | return mechanismList | ||
end | |||
-- 生成机制说明HTML | |||
local function generateMechanismHTML(frame, mechanism) | |||
if not mechanism or mechanism == "" or mechanism == "无" then | |||
return "" | |||
end | |||
-- | -- 提取机制名称列表(从原始模板语法中提取) | ||
local | local mechanismList = extractMechanismNames(mechanism) | ||
local htmlParts = {} | local htmlParts = {} | ||
| 第277行: | 第286行: | ||
local description = processDescription(frame, safeGet(cardData, "描述", "")) | local description = processDescription(frame, safeGet(cardData, "描述", "")) | ||
-- | -- 获取原始机制字段(用于生成右侧词条) | ||
local | local rawMechanism = safeGet(cardData, "机制", "") | ||
if | |||
-- 预处理机制字段中的模板(用于卡牌显示) | |||
elseif | local processedMechanism = rawMechanism | ||
if processedMechanism == "无" then | |||
processedMechanism = "" | |||
elseif processedMechanism ~= "" then | |||
processedMechanism = processDescription(frame, processedMechanism) | |||
end | end | ||
-- 更新 style 中的 mechanism | -- 更新 style 中的 mechanism | ||
style.mechanism = | style.mechanism = processedMechanism | ||
-- 获取衍生卡牌信息 | -- 获取衍生卡牌信息 | ||
| 第294行: | 第306行: | ||
-- 检查是否是自我意识技能 | -- 检查是否是自我意识技能 | ||
if deckType == "自我意识技能" then | if deckType == "自我意识技能" then | ||
-- | -- 生成机制HTML(传入原始机制字段) | ||
local mechanismHTML = generateMechanismHTML(frame, | local mechanismHTML = generateMechanismHTML(frame, rawMechanism) | ||
-- 生成数据属性 | -- 生成数据属性 | ||
local hasMechanism = ( | local hasMechanism = (rawMechanism ~= "" and rawMechanism ~= "无") and "true" or "false" | ||
local dataAttrs = string.format('data-card-name="%s" data-character="%s" data-deck-type="%s" data-derived-cards="%s" data-has-mechanism="%s"', | local dataAttrs = string.format('data-card-name="%s" data-character="%s" data-deck-type="%s" data-derived-cards="%s" data-has-mechanism="%s"', | ||
cardName or "", characterName or "", deckType or "", derivedCards or "", hasMechanism) | cardName or "", characterName or "", deckType or "", derivedCards or "", hasMechanism) | ||
| 第328行: | 第340行: | ||
-- 普通卡牌 | -- 普通卡牌 | ||
-- | -- 生成机制HTML(传入原始机制字段) | ||
local mechanismHTML = generateMechanismHTML(frame, | local mechanismHTML = generateMechanismHTML(frame, rawMechanism) | ||
-- 生成数据属性 | -- 生成数据属性 | ||
local hasMechanism = ( | local hasMechanism = (rawMechanism ~= "" and rawMechanism ~= "无") and "true" or "false" | ||
local dataAttrs = string.format('data-card-name="%s" data-character="%s" data-deck-type="%s" data-derived-cards="%s" data-has-mechanism="%s"', | local dataAttrs = string.format('data-card-name="%s" data-character="%s" data-deck-type="%s" data-derived-cards="%s" data-has-mechanism="%s"', | ||
cardName or "", characterName or "", deckType or "", derivedCards or "", hasMechanism) | cardName or "", characterName or "", deckType or "", derivedCards or "", hasMechanism) | ||
-- | -- 处理机制文本显示(使用处理后的机制文本) | ||
local mechanismDisplayHTML = "" | local mechanismDisplayHTML = "" | ||
if | if processedMechanism and processedMechanism ~= "" and processedMechanism ~= "无" then | ||
-- 从处理后的机制文本中提取纯文本用于显示 | -- 从处理后的机制文本中提取纯文本用于显示 | ||
local mechanismText = extractPlainText( | local mechanismText = extractPlainText(processedMechanism) | ||
if mechanismText ~= "" then | if mechanismText ~= "" then | ||
-- 如果是变体卡牌且主动指定了机制字段,显示为绿色;否则显示为橙色 | -- 如果是变体卡牌且主动指定了机制字段,显示为绿色;否则显示为橙色 | ||
2025年10月10日 (五) 09:44的版本
此模块的文档可以在模块:卡牌/doc创建
-- 模块:卡牌
local p = {}
-- 加载词典模块
local dictionaryData = require("模块:词典/data")
-- 颜色映射表
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 BORDER_COLOR_MAP = {
["白"] = "#ffffff",
["蓝"] = "#0099ff",
["红"] = "#ff3333",
["橙"] = "#f2ba02"
}
-- 安全获取数据字段
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 extractPlainText(text)
if not text then return "" end
-- 去除HTML标签
local plainText = text:gsub("<[^>]*>", "")
-- 去除多余的空白字符
plainText = mw.text.trim(plainText)
return plainText
end
-- 安全的字符串分割函数(使用 MediaWiki 函数处理 UTF-8)
local function splitString(str, delimiter)
if not str or str == "" then
return {}
end
-- 使用 mw.text.split 进行分割(UTF-8 安全)
local parts = mw.text.split(str, delimiter, true)
local result = {}
for _, part in ipairs(parts) do
-- 使用 mw.text.trim 去除空格(UTF-8 安全)
local trimmed = mw.text.trim(part)
if trimmed ~= "" then
table.insert(result, trimmed)
end
end
return result
end
-- 从原始机制文本中提取机制名称列表(处理模板语法前)
local function extractMechanismNames(mechanismText)
if not mechanismText or mechanismText == "" or mechanismText == "无" then
return {}
end
local mechanismList = {}
-- 匹配所有 {{词典|xxx}} 模板
for mechName in mechanismText:gmatch("{{词典|([^}]+)}}") do
mechName = mw.text.trim(mechName)
if mechName ~= "" then
table.insert(mechanismList, mechName)
end
end
-- 如果没有找到词典模板,尝试直接解析文本
if #mechanismList == 0 then
-- 先按"、"分割
local parts1 = splitString(mechanismText, "、")
for _, part in ipairs(parts1) do
-- 再按"/"分割
local parts2 = splitString(part, "/")
for _, p in ipairs(parts2) do
table.insert(mechanismList, p)
end
end
end
return mechanismList
end
-- 生成机制说明HTML
local function generateMechanismHTML(frame, mechanism)
if not mechanism or mechanism == "" or mechanism == "无" then
return ""
end
-- 提取机制名称列表(从原始模板语法中提取)
local mechanismList = extractMechanismNames(mechanism)
local htmlParts = {}
for _, mechName in ipairs(mechanismList) do
local entries = dictionaryData.dictionary[mechName]
if entries then
-- 找到"卡牌机制"类型的条目
local entry = nil
for _, e in ipairs(entries) do
if e["类型"] == "卡牌机制" then
entry = e
break
end
end
if entry then
local borderColor = BORDER_COLOR_MAP[entry["颜色"]] or BORDER_COLOR_MAP["白"]
local description = entry["描述"] or "暂无说明"
local icon = entry["icon"] or ""
-- 构建图标HTML
local iconHTML = ""
if icon ~= "" then
iconHTML = '[[File:' .. icon .. '|25px|link=]] '
end
-- 构建机制显示HTML
local mechHTML = string.format([[
<div class="mechanism-card" style="margin-bottom: 10px;">
<div style="width: 100%%; height: 2px; background-color: %s;"></div>
<div style="width: 100%%; background-color: #343434; color: white; padding: 8px; box-shadow: 0 2px 8px rgba(0,0,0,0.3); line-height: 1.6;">
<div style="margin-bottom: 5px; font-weight: bold;">%s%s</div>
<div>%s</div>
</div>
</div>
]], borderColor, iconHTML, mechName, description)
table.insert(htmlParts, mechHTML)
else
-- 没有找到对应类型的条目
table.insert(htmlParts, string.format([[
<div class="mechanism-card" style="margin-bottom: 10px;">
<div style="width: 100%%; height: 2px; background-color: #f2ba02;"></div>
<div style="width: 100%%; background-color: #343434; color: white; padding: 8px; box-shadow: 0 2px 8px rgba(0,0,0,0.3);">
<div style="margin-bottom: 5px; font-weight: bold;">%s</div>
<div style="color: #ccc;">暂无详细说明</div>
</div>
</div>
]], mechName))
end
else
-- 词典中没有该词条
table.insert(htmlParts, string.format([[
<div class="mechanism-card" style="margin-bottom: 10px;">
<div style="width: 100%%; height: 2px; background-color: #f2ba02;"></div>
<div style="width: 100%%; background-color: #343434; color: white; padding: 8px; box-shadow: 0 2px 8px rgba(0,0,0,0.3);">
<div style="margin-bottom: 5px; font-weight: bold;">%s</div>
<div style="color: #ccc;">暂无详细说明</div>
</div>
</div>
]], mechName))
end
end
if #htmlParts > 0 then
-- 添加标题和容器
return string.format([[
<div class="mechanism-container" style="display: none;">
%s
</div>
]], table.concat(htmlParts))
end
return ""
end
-- 生成卡牌HTML样式组件
local function buildStyleComponents(cardData, cardName, baseCardData, originalCardData)
local color = safeGet(cardData, "稀有度", "白")
local colorStyle = COLOR_MAP[color] or COLOR_MAP["白"]
local attribute = safeGet(cardData, "属性", "虚无")
local cardDeck = safeGet(cardData, "卡组", "起始卡牌")
local ap = safeGet(cardData, "AP", "")
local originalAP = baseCardData and safeGet(baseCardData, "AP", ap) or ap
-- 决定AP的发光颜色
local apGlowColor = "#4a90e2" -- 默认蓝色
if baseCardData and ap ~= originalAP then
if ap == "X" then
apGlowColor = "#4a90e2" -- X值保持默认蓝色
elseif tonumber(ap) and tonumber(originalAP) then
if tonumber(ap) < tonumber(originalAP) then
apGlowColor = "#51f651" -- 绿色(AP降低)
else
apGlowColor = "#f65151" -- 红色(AP增加)
end
end
end
-- 检查原始变体卡牌数据中是否指定了机制字段
local mechanism = safeGet(cardData, "机制", "")
local mechanismChanged = false
-- 判断机制是否发生了变化(变体卡牌主动指定了机制字段)
if baseCardData and originalCardData then
-- 检查原始变体卡牌数据中是否有"机制"字段
if originalCardData["机制"] ~= nil then
-- 变体卡牌主动指定了机制字段,无论内容是什么都标记为已更改
mechanismChanged = true
end
end
-- 将"无"视为空字符串
if mechanism == "无" then mechanism = "" end
return {
color = color,
colorStyle = colorStyle,
attribute = attribute,
ap = ap,
apGlowColor = apGlowColor,
cardType = safeGet(cardData, "类型", ""),
art = safeGet(cardData, "art", ""),
mechanism = mechanism,
mechanismChanged = mechanismChanged
}
end
-- 去除模板语法,计算纯文本字数
local function getPlainTextLength(text)
if not text or text == "" then
return 0
end
-- 去除所有模板 {{...}}(支持嵌套)
local plainText = text
local maxIterations = 10 -- 防止无限循环
local iteration = 0
while iteration < maxIterations do
local newText = plainText:gsub("{{[^{}]*}}", "")
if newText == plainText then
break -- 没有更多模板可以移除
end
plainText = newText
iteration = iteration + 1
end
-- 去除HTML标签
plainText = plainText:gsub("<[^>]*>", "")
-- 去除多余的空白字符
plainText = plainText:gsub("%s+", "")
-- 返回字符数(UTF-8字符计数)
local _, count = plainText:gsub("[%z\1-\127\194-\244][\128-\191]*", "")
return count
end
-- 构建卡牌HTML
local function buildCardHTML(frame, cardName, cardData, baseCardData, characterName, originalCardData)
if not cardData then
return string.format("找不到卡牌数据: %s", cardName or "未指定")
end
-- 获取显示名称,如果存在则使用,否则使用默认卡牌名称
local displayName = safeGet(cardData, "显示名称", cardName)
local style = buildStyleComponents(cardData, cardName, baseCardData, originalCardData)
local description = processDescription(frame, safeGet(cardData, "描述", ""))
-- 获取原始机制字段(用于生成右侧词条)
local rawMechanism = safeGet(cardData, "机制", "")
-- 预处理机制字段中的模板(用于卡牌显示)
local processedMechanism = rawMechanism
if processedMechanism == "无" then
processedMechanism = ""
elseif processedMechanism ~= "" then
processedMechanism = processDescription(frame, processedMechanism)
end
-- 更新 style 中的 mechanism
style.mechanism = processedMechanism
-- 获取衍生卡牌信息
local derivedCards = safeGet(cardData, "衍生卡牌", "")
local deckType = safeGet(cardData, "卡组", "")
-- 检查是否是自我意识技能
if deckType == "自我意识技能" then
-- 生成机制HTML(传入原始机制字段)
local mechanismHTML = generateMechanismHTML(frame, rawMechanism)
-- 生成数据属性
local hasMechanism = (rawMechanism ~= "" and rawMechanism ~= "无") and "true" or "false"
local dataAttrs = string.format('data-card-name="%s" data-character="%s" data-deck-type="%s" data-derived-cards="%s" data-has-mechanism="%s"',
cardName or "", characterName or "", deckType or "", derivedCards or "", hasMechanism)
-- 自我意识技能的特殊布局
local attribute = safeGet(cardData, "属性", "虚无")
local cost = safeGet(cardData, "AP", "1")
local art = safeGet(cardData, "art", "")
local htmlParts = {
string.format('<div class="game-card" %s style="display: inline-block; vertical-align: top; position: relative; width: 155px; height: 235px; overflow: hidden; margin: 0px; cursor: pointer;">', dataAttrs),
string.format('<div style="position: absolute; top: 0px; left: 4px; pointer-events: none;">[[File:%s|150px|link=]]</div>', art),
string.format('<div style="position: absolute; top: 0px; left: 0px; pointer-events: none;">[[File:tp_%s.png|154px|link=]]</div>', attribute),
string.format('<div style="position: absolute; top: 0px; left: 0px; pointer-events: none;">[[File:tp_cost_%s.png|154px|link=]]</div>', cost),
string.format('<div style="position: absolute; top: 105px; left: 17px; color: white; font-size: 13px; user-select: text; cursor: text;">%s</div>', displayName),
string.format('<div style="position: absolute; top: 138px; left: 17px; width: 135px; height: 90px; color: white; font-size: 13px; line-height: 14px; user-select: text; cursor: text;">%s</div>', description),
'<div style="position: absolute; top: 0px; left: 0px; pointer-events: none;">[[File:tp_顶层蒙版.png|154px|link=]]</div>',
'</div>'
}
-- 在卡牌div之后添加隐藏的机制说明
local result = table.concat(htmlParts)
if mechanismHTML ~= "" then
result = result .. mechanismHTML
end
return result
end
-- 普通卡牌
-- 生成机制HTML(传入原始机制字段)
local mechanismHTML = generateMechanismHTML(frame, rawMechanism)
-- 生成数据属性
local hasMechanism = (rawMechanism ~= "" and rawMechanism ~= "无") and "true" or "false"
local dataAttrs = string.format('data-card-name="%s" data-character="%s" data-deck-type="%s" data-derived-cards="%s" data-has-mechanism="%s"',
cardName or "", characterName or "", deckType or "", derivedCards or "", hasMechanism)
-- 处理机制文本显示(使用处理后的机制文本)
local mechanismDisplayHTML = ""
if processedMechanism and processedMechanism ~= "" and processedMechanism ~= "无" then
-- 从处理后的机制文本中提取纯文本用于显示
local mechanismText = extractPlainText(processedMechanism)
if mechanismText ~= "" then
-- 如果是变体卡牌且主动指定了机制字段,显示为绿色;否则显示为橙色
local mechanismColor = style.mechanismChanged and "#b4f352" or "#f6c478"
mechanismDisplayHTML = string.format('<div style="color: %s;">[%s]</div>',
mechanismColor, mechanismText:gsub("、", "/"))
end
end
-- 组合完整的描述内容
local fullDescription = mechanismDisplayHTML .. description
-- 检测是否需要滚动(去除模板后计算字数)
local plainTextLength = getPlainTextLength(fullDescription)
local needScroll = plainTextLength > 50 -- 超过50个字符才启用滚动
local scrollClass = needScroll and " card-description-scrollable" or ""
-- 使用字符串拼接优化HTML生成
local htmlParts = {
string.format('<div class="game-card%s" %s style="display: inline-block; vertical-align: top; position: relative; width: 168px; height: 230px; overflow: hidden; margin: 0px; cursor: pointer;">',
scrollClass, dataAttrs),
}
-- 根据类型判断使用哪种布局
if style.cardType == "状态异常" then
-- 状态异常卡牌的特殊布局
table.insert(htmlParts, string.format('<div style="position: absolute; top: 5px; left: 5px;">[[File:%s|150px|link=]]</div>', style.art))
table.insert(htmlParts, string.format('<div style="position: absolute; top: 0px; left: 0px;">[[File:card_状态异常_%s.png|159px|link=]]</div>', style.attribute))
-- AP值
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>',
style.apGlowColor, style.apGlowColor, style.apGlowColor, style.apGlowColor, style.ap))
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>',
style.apGlowColor, style.apGlowColor, style.apGlowColor, style.apGlowColor))
-- 卡牌名称和类型(使用显示名称)
table.insert(htmlParts, string.format('<div style="position: absolute; left: 50px; top: 13px; color: %s; font-size:16px">%s</div>',
style.colorStyle.textColor, displayName))
table.insert(htmlParts, string.format('<div style="position: absolute; left: 48px; top: 30px;">[[File:icon_card_%s.png|18px|link=]]</div>',
style.cardType))
table.insert(htmlParts, string.format('<div style="position: absolute; left: 68px; top: 33px; color: white; font-size:14px">%s</div>',
style.cardType))
-- 顶层蒙版
table.insert(htmlParts, '<div style="position: absolute; left: 0px; bottom: 0px;">[[File:card_顶层蒙版.png|168px|link=]]</div>')
else
-- 普通卡牌的布局
-- 背景图片层
table.insert(htmlParts, string.format('<div style="position: absolute; top: 1px; left: 12px;">[[File:%s|151px|link=]]</div>', style.art))
table.insert(htmlParts, '<div style="position: absolute; top: 1px; left: 12px;">[[File:card_黑色蒙版.png|151px|link=]]</div>')
-- 颜色条
table.insert(htmlParts, string.format('<div style="position: absolute; top: 21px; left: 10px; width: 148px; height: 8px; background-color: %s;"></div>',
style.colorStyle.bgColor))
-- AP值
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>',
style.apGlowColor, style.apGlowColor, style.apGlowColor, style.apGlowColor, style.ap))
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>',
style.apGlowColor, style.apGlowColor, style.apGlowColor, style.apGlowColor))
-- 卡牌名称和类型(使用显示名称)
table.insert(htmlParts, string.format('<div style="position: absolute; left: 50px; top: 13px; color: %s; font-size:16px">%s</div>',
style.colorStyle.textColor, displayName))
table.insert(htmlParts, string.format('<div style="position: absolute; left: 48px; top: 30px;">[[File:icon_card_%s.png|18px|link=]]</div>',
style.cardType))
table.insert(htmlParts, string.format('<div style="position: absolute; left: 68px; top: 33px; color: white; font-size:14px">%s</div>',
style.cardType))
-- 边框
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
-- 描述文本 - 根据是否需要滚动使用不同结构
table.insert(htmlParts, string.format([[
<div class="card-description-scroll">
<div class="card-description-scroll-inner">
<div class="card-description-text">%s</div>
</div>
</div>
]], fullDescription))
table.insert(htmlParts, '</div>')
-- 在卡牌div之后添加隐藏的机制说明
if mechanismHTML ~= "" then
table.insert(htmlParts, mechanismHTML)
end
return table.concat(htmlParts)
end
-- 合并卡牌数据
local function mergeCardData(baseData, overrideData)
local result = {}
-- 复制基础卡牌的所有属性
for k, v in pairs(baseData or {}) do
result[k] = v
end
-- 清空衍生卡牌属性
if overrideData and next(overrideData) ~= nil then
result["衍生卡牌"] = nil
end
-- 应用覆盖数据
for k, v in pairs(overrideData or {}) do
result[k] = v
end
return result
end
-- 获取并显示所有默认卡牌
local function displayAllDefaultCards(frame, characterModule, characterName)
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, nil, characterName, nil))
end
return table.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, nil)
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 originalCard = filteredCards[cardIndex] -- 保存原始变体卡牌数据
local mergedCard = mergeCardData(baseCard, originalCard)
return buildCardHTML(frame, cardName, mergedCard, baseCard, characterName, originalCard)
end
-- 否则返回该卡组的所有卡牌
local htmlParts = {}
for i, card in ipairs(filteredCards) do
local originalCard = card -- 保存原始变体卡牌数据
local mergedCard = mergeCardData(baseCard, originalCard)
table.insert(htmlParts, buildCardHTML(frame, cardName, mergedCard, baseCard, characterName, originalCard))
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, characterName)
end
-- 获取指定卡牌数据
local cardData = (characterModule.card or {})[cardName]
if not cardData then
return string.format("找不到卡牌: %s", 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