模块

ArtsData:修订间差异

来自蒙纳多研究本部

头号云​(留言 | 贡献)
清空全部内容
标签:清空
头号云​(留言 | 贡献)
无编辑摘要
第1行: 第1行:
-- 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 acquire = require("Module:ArtsData/acquire")
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
local ATK_TYPE = {[1] = "物理", [2] = "以太", [3] = "状态"}
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 = {}
  out[#out + 1] = html.h3(name)
  out[#out + 1] = "'''类型''':" .. atype .. "  '''习得''':" .. learn
  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>"
  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.set({
    artId = artId,
    artName = name,
    artType = atype,
    artLearn = learn,
    artRate = maxRate,
    artRecast = num(data.recast),
  })
  return table.concat(out, "\n")
end
local ACQ_HEADER = {"战技名", "等级", "地点", "掉落", "商店", "出售", "备注"}
local function renderAcquire(roleKey)
  local rows = acquire[roleKey]
  if not rows or #rows == 0 then
    return ""
  end
  local out = {html.h2("获取")}
  out[#out + 1] = '<table class="wikitable sortable">'
  out[#out + 1] = "<tr>"
  for _, h in ipairs(ACQ_HEADER) do
    out[#out + 1] = "<th>" .. h .. "</th>"
  end
  out[#out + 1] = "</tr>"
  for _, r in ipairs(rows) do
    out[#out + 1] = "<tr>"
    out[#out + 1] = "<td>" .. (r.art or "") .. "</td>"
    out[#out + 1] = "<td>" .. (r.level or "") .. "</td>"
    out[#out + 1] = "<td>" .. (r.place or "") .. "</td>"
    out[#out + 1] = "<td>" .. (r.drop or "") .. "</td>"
    out[#out + 1] = "<td>" .. (r.shop or "") .. "</td>"
    out[#out + 1] = "<td>" .. (r.sell or "") .. "</td>"
    out[#out + 1] = "<td>" .. (r.note or "") .. "</td>"
    out[#out + 1] = "</tr>"
  end
  out[#out + 1] = "</table>"
  return table.concat(out)
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] = "== 战技 =="
    for _, id in ipairs(role.ids) do
      out[#out + 1] = p.renderArt(id)
    end
    if args.noacquire ~= "1" then
      out[#out + 1] = renderAcquire(first)
    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

2026年10月8日 (四) 18:43的版本

此模块的文档可以在模块: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 acquire = require("Module:ArtsData/acquire")
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

local ATK_TYPE = {[1] = "物理", [2] = "以太", [3] = "状态"}

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 = {}
  out[#out + 1] = html.h3(name)
  out[#out + 1] = "'''类型''':" .. atype .. "  '''习得''':" .. learn

  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>"

  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.set({
    artId = artId,
    artName = name,
    artType = atype,
    artLearn = learn,
    artRate = maxRate,
    artRecast = num(data.recast),
  })

  return table.concat(out, "\n")
end

local ACQ_HEADER = {"战技名", "等级", "地点", "掉落", "商店", "出售", "备注"}

local function renderAcquire(roleKey)
  local rows = acquire[roleKey]
  if not rows or #rows == 0 then
    return ""
  end

  local out = {html.h2("获取")}
  out[#out + 1] = '<table class="wikitable sortable">'
  out[#out + 1] = "<tr>"
  for _, h in ipairs(ACQ_HEADER) do
    out[#out + 1] = "<th>" .. h .. "</th>"
  end
  out[#out + 1] = "</tr>"

  for _, r in ipairs(rows) do
    out[#out + 1] = "<tr>"
    out[#out + 1] = "<td>" .. (r.art or "") .. "</td>"
    out[#out + 1] = "<td>" .. (r.level or "") .. "</td>"
    out[#out + 1] = "<td>" .. (r.place or "") .. "</td>"
    out[#out + 1] = "<td>" .. (r.drop or "") .. "</td>"
    out[#out + 1] = "<td>" .. (r.shop or "") .. "</td>"
    out[#out + 1] = "<td>" .. (r.sell or "") .. "</td>"
    out[#out + 1] = "<td>" .. (r.note or "") .. "</td>"
    out[#out + 1] = "</tr>"
  end
  out[#out + 1] = "</table>"
  return table.concat(out)
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] = "== 战技 =="
    for _, id in ipairs(role.ids) do
      out[#out + 1] = p.renderArt(id)
    end
    if args.noacquire ~= "1" then
      out[#out + 1] = renderAcquire(first)
    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