ArtsData:修订间差异
来自蒙纳多研究本部
无编辑摘要 |
无编辑摘要 |
||
| (未显示同一用户的6个中间版本) | |||
| 第44行: | 第44行: | ||
end | end | ||
local ATK_TYPE = {[1] = "物理", [2] = "以太", [3] = "状态"} | -- atk_type=4/6 为梅莉亚元素系(召唤/释放),攻击本质是以太伤害,标"以太" | ||
-- (旧扩展无此映射故落"未知";sim 数据验证:4=元素发射+召X术 7 个,6=X元素发射 6 个) | |||
local ATK_TYPE = {[1] = "物理", [2] = "以太", [3] = "状态", [4] = "以太", [6] = "以太"} | |||
-- 灵气判定(方案 A,数据驱动):atk_type=3 且 st_type >= 206 → 自身系状态(灵气/增益) | |||
-- 低段 st_type(<206)是对敌减益(破防 18、睡眠 9 等) | |||
local function isAura(data) | |||
return num(data.atk_type) == 3 and num(data.st_type) >= 206 | |||
end | |||
-- 状态类颜色:灵气=橙、状态(对敌)=紫(MediaWiki 标准色板) | |||
local AURA_COLOR = "#e69138" | |||
local DEBUFF_COLOR = "#674ea7" | |||
-- 类型着色徽章:物理=红、以太=青、灵气=橙、状态=紫 | |||
local TYPE_COLOR = { | |||
["物理"] = "#cc0000", | |||
["以太"] = "#3d85c6", | |||
} | |||
local function typeBadge(atype, aura) | |||
local color = aura and AURA_COLOR or DEBUFF_COLOR | |||
if atype == "物理" then color = TYPE_COLOR["物理"] end | |||
if atype == "以太" then color = TYPE_COLOR["以太"] end | |||
return '<span style="color:' .. color .. ';font-weight:bold;">' .. atype .. "</span>" | |||
end | |||
-- 效果摘要:去标签、截断(概览表用) | |||
-- 注意:截断必须用 mw.ustring(按码点),string.sub/# 按字节会把汉字切成 | |||
-- 非法 UTF-8,导致下游 Html compress 的 gsub 报 "string is not UTF-8" | |||
local function descSummary(artId, limit) | |||
local d = descs[artId] or "" | |||
d = d:gsub("%[[^%]]*%]", "") -- 去掉 [ML:icon ...] 类标记 | |||
d = d:gsub("%s+", " ") | |||
if mw.ustring.len(d) > limit then | |||
d = mw.ustring.sub(d, 1, limit) .. "…" | |||
end | |||
return d | |||
end | |||
local function learnText(data) | local function learnText(data) | ||
| 第133行: | 第170行: | ||
local out = {} | local out = {} | ||
out[#out + 1] = | local aura = isAura(data) | ||
out[#out + 1] = "''' | -- 方向 1 改版:每技一个可折叠块(MediaWiki 原生 mw-collapsible,零 JS) | ||
-- 默认全展开(2026-10-12):站点折叠 JS 与锚点联动不可靠(Foreground 皮肤), | |||
-- 总览跳转后直接可见内容;保留 mw-collapsible 类,读者仍可手动折叠 | |||
-- 战技名不染色:颜色信息只由类型徽章传达 | |||
out[#out + 1] = '<table class="wikitable mw-collapsible" id="art-' .. | |||
artId .. '" style="width:100%;">' | |||
-- 折叠块头部:名 + 类型(元素小字缀)/习得/目标范围 | |||
-- 属性段已删(2026-10-12),元素仅攻击技且非"无"/"物理"时以小字缀在类型后 | |||
local elemText = source.elemName(data) | |||
local tgt = source.tgtName(data) | |||
local rng = source.rangeName(data) | |||
local tgtTxt = "" | |||
if tgt then | |||
tgtTxt = " · " .. tgt | |||
if rng then tgtTxt = tgtTxt .. rng end | |||
end | |||
local typeHtml = typeBadge(atype, aura) | |||
if elemText and elemText ~= "无" and elemText ~= "物理" then | |||
typeHtml = typeHtml .. '<small style="color:#777;">' .. elemText .. "</small>" | |||
end | |||
out[#out + 1] = '<tr><th style="text-align:left;">' .. name .. | |||
'<small> (' .. typeHtml .. | |||
" · " .. learn .. tgtTxt .. ")</small></th></tr>" | |||
out[#out + 1] = '<tr><td style="text-align:left;">' | |||
local head = {"<tr><th>等级</th>"} | local head = {"<tr><th>等级</th>"} | ||
| 第177行: | 第237行: | ||
out[#out + 1] = '<table class="wikitable" style="text-align:center;">' .. | out[#out + 1] = '<table class="wikitable" style="text-align:center;">' .. | ||
table.concat(head) .. table.concat(rows) .. "</table>" | table.concat(head) .. table.concat(rows) .. "</table>" | ||
out[#out + 1] = "</td></tr></table>" | |||
local maxRate | local maxRate | ||
| 第184行: | 第246行: | ||
maxRate = (r1 + 11 * num(data.grow_powl)) / 100 | maxRate = (r1 + 11 * num(data.grow_powl)) / 100 | ||
end | end | ||
mw.smw. | mw.smw.subobject({ | ||
artId = artId, | artId = artId, | ||
artName = name, | artName = name, | ||
| 第191行: | 第253行: | ||
artRate = maxRate, | artRate = maxRate, | ||
artRecast = num(data.recast), | artRecast = num(data.recast), | ||
artDesc = descs[artId] or "", | |||
artIsTalent = isTalent and "1" or "0", | |||
artIsAura = aura and "1" or "0", | |||
artElem = source.elemName(data) or "", | |||
artTarget = source.tgtName(data) or "", | |||
artRange = source.rangeName(data) or "", | |||
artHate = num(data.hate), | |||
artChain = source.chainName(data), | |||
}) | }) | ||
return table.concat(out, "\n") | return table.concat(out, "\n") | ||
end | |||
-- 总览表:一行一技,链接到下方折叠块的锚点(id = art-<id>) | |||
-- 列:战技名(着色+锚点)/ 类型(元素小字缀)/ 习得 / 目标 / 连锁 / 仇恨 / 效果摘要 | |||
-- 属性列已删(2026-10-12):带攻击元素的技基本只有梅莉亚/力奇,单独一列性价比低, | |||
-- 元素信息压缩进类型列小字(如 以太雷),状态技 elem 非攻击属性不显示 | |||
local function renderOverview(ids) | |||
local rows = {} | |||
for _, id in ipairs(ids) do | |||
local data = source.fetchArt(id) | |||
if data then | |||
local name = (data.name and data.name ~= "") and data.name | |||
or source.fetchDesc(id) or ("战技 " .. id) | |||
local atype = ATK_TYPE[num(data.atk_type)] or "未知" | |||
local aura = isAura(data) | |||
-- 类型列:徽章 + 元素小字缀(仅攻击技且元素非"无"时) | |||
local typeHtml = typeBadge(atype, aura) | |||
local elem = source.elemName(data) | |||
if elem and elem ~= "无" and elem ~= "物理" then | |||
typeHtml = typeHtml .. '<small style="color:#777;">' .. elem .. "</small>" | |||
end | |||
-- 目标 / 范围 / 连锁 / 仇恨 | |||
local tgt = source.tgtName(data) or "—" | |||
local rng = source.rangeName(data) | |||
if rng then tgt = tgt .. "·" .. rng end | |||
local chain = source.chainName(data) | |||
local hate = source.hateText(data) or "—" | |||
rows[#rows + 1] = "<tr>" | |||
.. '<td style="text-align:left;">[[' .. "#art-" .. id .. "|" .. name .. "]]</td>" | |||
.. "<td>" .. typeHtml .. "</td>" | |||
.. "<td>" .. learnText(data) .. "</td>" | |||
.. "<td>" .. tgt .. "</td>" | |||
.. "<td>" .. chain .. "</td>" | |||
.. "<td>" .. hate .. "</td>" | |||
.. '<td style="text-align:left;">' .. descSummary(id, 40) .. "</td>" | |||
.. "</tr>" | |||
end | |||
end | |||
if #rows == 0 then return "" end | |||
return '<table class="wikitable" style="text-align:center;">' | |||
.. "<tr><th>战技名</th><th>类型</th><th>习得</th><th>目标</th><th>连锁</th><th>仇恨</th><th>效果摘要</th></tr>" | |||
.. table.concat(rows) | |||
.. "</table>" | |||
end | end | ||
| 第204行: | 第317行: | ||
if role then | if role then | ||
out[#out + 1] = html.h2("总览") | |||
out[#out + 1] = renderOverview(role.ids) | |||
local talent, normal = {}, {} | local talent, normal = {}, {} | ||
for _, id in ipairs(role.ids) do | for _, id in ipairs(role.ids) do | ||
2026年10月13日 (二) 16:30的最新版本
此模块的文档可以在模块:ArtsData/doc创建
-- Module:ArtsData —— 战技模块 v2(主模块,XBDB 调用全部收敛于 source)
local p = {}
local source = require("Module:ArtsData/source")
local lv1 = require("Module:ArtsData/lv1")
local descs = require("Module:ArtsData/desc")
local getArgs = require("Module:Arguments").getArgs
local html = require("Module:Html")
local compress = html.compress
local ROMAN = {"I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX", "X", "XI", "XII"}
local MAX_RANK = 12
local function num(v)
if v == nil then return 0 end
return tonumber(v) or 0
end
local function fmt(v, digits)
digits = digits or 2
local factor = 10 ^ digits
local scaled = v * factor
local rounded
if scaled >= 0 then
rounded = math.floor(scaled + 0.5 + 1e-9)
else
rounded = -math.floor(-scaled + 0.5 + 1e-9)
end
if digits == 0 then
return tostring(rounded)
end
local intPart = math.floor(math.abs(rounded) / factor)
local fracPart = math.abs(rounded) % factor
local fracStr = string.format("%0" .. digits .. "d", fracPart)
fracStr = fracStr:gsub("0+$", "")
local sign = rounded < 0 and "-" or ""
if fracStr == "" then
return sign .. tostring(intPart)
end
return sign .. tostring(intPart) .. "." .. fracStr
end
-- atk_type=4/6 为梅莉亚元素系(召唤/释放),攻击本质是以太伤害,标"以太"
-- (旧扩展无此映射故落"未知";sim 数据验证:4=元素发射+召X术 7 个,6=X元素发射 6 个)
local ATK_TYPE = {[1] = "物理", [2] = "以太", [3] = "状态", [4] = "以太", [6] = "以太"}
-- 灵气判定(方案 A,数据驱动):atk_type=3 且 st_type >= 206 → 自身系状态(灵气/增益)
-- 低段 st_type(<206)是对敌减益(破防 18、睡眠 9 等)
local function isAura(data)
return num(data.atk_type) == 3 and num(data.st_type) >= 206
end
-- 状态类颜色:灵气=橙、状态(对敌)=紫(MediaWiki 标准色板)
local AURA_COLOR = "#e69138"
local DEBUFF_COLOR = "#674ea7"
-- 类型着色徽章:物理=红、以太=青、灵气=橙、状态=紫
local TYPE_COLOR = {
["物理"] = "#cc0000",
["以太"] = "#3d85c6",
}
local function typeBadge(atype, aura)
local color = aura and AURA_COLOR or DEBUFF_COLOR
if atype == "物理" then color = TYPE_COLOR["物理"] end
if atype == "以太" then color = TYPE_COLOR["以太"] end
return '<span style="color:' .. color .. ';font-weight:bold;">' .. atype .. "</span>"
end
-- 效果摘要:去标签、截断(概览表用)
-- 注意:截断必须用 mw.ustring(按码点),string.sub/# 按字节会把汉字切成
-- 非法 UTF-8,导致下游 Html compress 的 gsub 报 "string is not UTF-8"
local function descSummary(artId, limit)
local d = descs[artId] or ""
d = d:gsub("%[[^%]]*%]", "") -- 去掉 [ML:icon ...] 类标记
d = d:gsub("%s+", " ")
if mw.ustring.len(d) > limit then
d = mw.ustring.sub(d, 1, limit) .. "…"
end
return d
end
local function learnText(data)
if num(data.get_type) == 2 then
return "剧情习得"
end
local lv = num(data.get_lv)
if lv > 0 then
return "等级 " .. lv
end
return "初始拥有"
end
local function series(rank1, grow, digits, scale)
scale = scale or 1
local out = {}
for r = 1, MAX_RANK do
out[r] = fmt((num(rank1) + (r - 1) * num(grow)) / scale, digits)
end
return out
end
local function recastSeries(data)
local recast = num(data.recast)
if recast == 0 then return nil end
local glow = num(data.glow_recast)
local out = {}
for r = 1, MAX_RANK do
out[r] = fmt(recast * (1 - (r - 1) * glow / 100), 1)
end
return out
end
local function dexSeries(data)
local dex = num(data.dex)
local out = {}
for r = 1, MAX_RANK do
out[r] = "+" .. tostring(dex + 5 * (r - 1)) .. "%"
end
return out
end
local function apSeries(data)
local pc = num(data.pc)
local idx = num(data.idx) + 1
local rateRow = lv1.grow_arts_rate[pc]
if not rateRow or not rateRow[idx] then
return nil
end
local rate = rateRow[idx]
local out = {}
for r = 1, MAX_RANK do
out[r] = tostring(math.floor(lv1.grow_arts_base[r] * rate / 100 + 0.5))
end
return out
end
local function row12(label, cells)
local t = {"<tr><th>" .. label .. "</th>"}
for r = 1, MAX_RANK do
local v = cells and cells[r] or nil
t[#t + 1] = "<td>" .. (v or "—") .. "</td>"
end
t[#t + 1] = "</tr>"
return table.concat(t)
end
local function rowSpan(label, text)
if not text or text == "" then return "" end
return '<tr><th>' .. label .. '</th><td colspan="' .. MAX_RANK ..
'" style="text-align:left;">' .. text .. "</td></tr>"
end
function p.renderArt(artId)
if not source.isValidArtId(artId) then
return ""
end
local data = source.fetchArt(artId)
if not data then
return ""
end
local name = (data.name and data.name ~= "") and data.name
or source.fetchDesc(artId) or ("战技 " .. artId)
local atype = ATK_TYPE[num(data.atk_type)] or "未知"
local learn = learnText(data)
local isTalent = num(data.arts_type) == 1
local out = {}
local aura = isAura(data)
-- 方向 1 改版:每技一个可折叠块(MediaWiki 原生 mw-collapsible,零 JS)
-- 默认全展开(2026-10-12):站点折叠 JS 与锚点联动不可靠(Foreground 皮肤),
-- 总览跳转后直接可见内容;保留 mw-collapsible 类,读者仍可手动折叠
-- 战技名不染色:颜色信息只由类型徽章传达
out[#out + 1] = '<table class="wikitable mw-collapsible" id="art-' ..
artId .. '" style="width:100%;">'
-- 折叠块头部:名 + 类型(元素小字缀)/习得/目标范围
-- 属性段已删(2026-10-12),元素仅攻击技且非"无"/"物理"时以小字缀在类型后
local elemText = source.elemName(data)
local tgt = source.tgtName(data)
local rng = source.rangeName(data)
local tgtTxt = ""
if tgt then
tgtTxt = " · " .. tgt
if rng then tgtTxt = tgtTxt .. rng end
end
local typeHtml = typeBadge(atype, aura)
if elemText and elemText ~= "无" and elemText ~= "物理" then
typeHtml = typeHtml .. '<small style="color:#777;">' .. elemText .. "</small>"
end
out[#out + 1] = '<tr><th style="text-align:left;">' .. name ..
'<small> (' .. typeHtml ..
" · " .. learn .. tgtTxt .. ")</small></th></tr>"
out[#out + 1] = '<tr><td style="text-align:left;">'
local head = {"<tr><th>等级</th>"}
for r = 1, MAX_RANK do
head[#head + 1] = "<th>" .. ROMAN[r] .. "</th>"
end
head[#head + 1] = "</tr>"
local rows = {}
rows[#rows + 1] = rowSpan("效果", descs[artId] or "")
if not isTalent then
rows[#rows + 1] = row12("AP 消耗", apSeries(data))
end
local r1, r2 = num(data.rate1), num(data.rate2)
if r2 ~= r1 then
rows[#rows + 1] = row12("倍率(下限)", series(r1, data.grow_powl, 2, 100))
rows[#rows + 1] = row12("倍率(上限)", series(r2, data.grow_powh, 2, 100))
else
rows[#rows + 1] = row12("倍率", series(r1, data.grow_powl, 2, 100))
end
local rs = recastSeries(data)
if rs then
rows[#rows + 1] = row12("填充时间(秒)", rs)
else
rows[#rows + 1] = row12("填充时间(秒)", nil)
end
if num(data.st_time) ~= 0 or num(data.grow_st_time) ~= 0 then
rows[#rows + 1] = row12("效果时间(秒)", series(data.st_time, data.grow_st_time, 1, 10))
end
rows[#rows + 1] = row12("命中修正(决定版)", dexSeries(data))
if num(data.st_val) ~= 0 or num(data.grow_st_val) ~= 0 then
rows[#rows + 1] = row12("效果数值", series(data.st_val, data.grow_st_val, 0, 1))
end
out[#out + 1] = '<table class="wikitable" style="text-align:center;">' ..
table.concat(head) .. table.concat(rows) .. "</table>"
out[#out + 1] = "</td></tr></table>"
local maxRate
if r2 ~= r1 then
maxRate = (r2 + 11 * num(data.grow_powh)) / 100
else
maxRate = (r1 + 11 * num(data.grow_powl)) / 100
end
mw.smw.subobject({
artId = artId,
artName = name,
artType = atype,
artLearn = learn,
artRate = maxRate,
artRecast = num(data.recast),
artDesc = descs[artId] or "",
artIsTalent = isTalent and "1" or "0",
artIsAura = aura and "1" or "0",
artElem = source.elemName(data) or "",
artTarget = source.tgtName(data) or "",
artRange = source.rangeName(data) or "",
artHate = num(data.hate),
artChain = source.chainName(data),
})
return table.concat(out, "\n")
end
-- 总览表:一行一技,链接到下方折叠块的锚点(id = art-<id>)
-- 列:战技名(着色+锚点)/ 类型(元素小字缀)/ 习得 / 目标 / 连锁 / 仇恨 / 效果摘要
-- 属性列已删(2026-10-12):带攻击元素的技基本只有梅莉亚/力奇,单独一列性价比低,
-- 元素信息压缩进类型列小字(如 以太雷),状态技 elem 非攻击属性不显示
local function renderOverview(ids)
local rows = {}
for _, id in ipairs(ids) do
local data = source.fetchArt(id)
if data then
local name = (data.name and data.name ~= "") and data.name
or source.fetchDesc(id) or ("战技 " .. id)
local atype = ATK_TYPE[num(data.atk_type)] or "未知"
local aura = isAura(data)
-- 类型列:徽章 + 元素小字缀(仅攻击技且元素非"无"时)
local typeHtml = typeBadge(atype, aura)
local elem = source.elemName(data)
if elem and elem ~= "无" and elem ~= "物理" then
typeHtml = typeHtml .. '<small style="color:#777;">' .. elem .. "</small>"
end
-- 目标 / 范围 / 连锁 / 仇恨
local tgt = source.tgtName(data) or "—"
local rng = source.rangeName(data)
if rng then tgt = tgt .. "·" .. rng end
local chain = source.chainName(data)
local hate = source.hateText(data) or "—"
rows[#rows + 1] = "<tr>"
.. '<td style="text-align:left;">[[' .. "#art-" .. id .. "|" .. name .. "]]</td>"
.. "<td>" .. typeHtml .. "</td>"
.. "<td>" .. learnText(data) .. "</td>"
.. "<td>" .. tgt .. "</td>"
.. "<td>" .. chain .. "</td>"
.. "<td>" .. hate .. "</td>"
.. '<td style="text-align:left;">' .. descSummary(id, 40) .. "</td>"
.. "</tr>"
end
end
if #rows == 0 then return "" end
return '<table class="wikitable" style="text-align:center;">'
.. "<tr><th>战技名</th><th>类型</th><th>习得</th><th>目标</th><th>连锁</th><th>仇恨</th><th>效果摘要</th></tr>"
.. table.concat(rows)
.. "</table>"
end
function p.main(frame)
local args = getArgs(frame)
local out = {}
local first = args[1]
local role = first and lv1.roles[first] or nil
if role then
out[#out + 1] = html.h2("总览")
out[#out + 1] = renderOverview(role.ids)
local talent, normal = {}, {}
for _, id in ipairs(role.ids) do
local data = source.fetchArt(id)
local isTalent = data and num(data.arts_type) == 1
table.insert(isTalent and talent or normal, id)
end
if #talent > 0 then
out[#out + 1] = html.h2("天赋战技")
for _, id in ipairs(talent) do
out[#out + 1] = p.renderArt(id)
end
end
if #normal > 0 then
out[#out + 1] = html.h2("战技")
for _, id in ipairs(normal) do
out[#out + 1] = p.renderArt(id)
end
end
else
for _, v in ipairs(args) do
local id = tonumber(mw.text.trim(v))
if id then
out[#out + 1] = p.renderArt(id)
end
end
end
if #out == 0 then
return ""
end
return compress(table.concat(out, "\n"))
end
return p