打开/关闭菜单
打开/关闭个人菜单
未登录
未登录用户的IP地址会在进行任意编辑后公开展示。
圈圈菌Q留言 | 贡献2024年12月21日 (六) 00:45的版本

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

-- FrameChart
local p = {}
local cargo = mw.ext.cargo
local framechart = require("Module:MetaFrameChart")

function p.drawFrameData( frame )
  -- 初始化chara和input变量用于存储角色和输入数据
  -- 检查frame参数中是否有chara和input字段,如有,则使用frame:preprocess方法预处理
  -- 如果chara为nil,则尝试从当前页面标题提取角色名(当前页面标题中最后一个斜杠后面的文本)
  -- 如果仍为nil,则报错;如input为nil,也报错
  local chara = nil
  if frame.args['chara'] ~= nil then
    chara = frame:preprocess(frame.args['chara'])
  end
  local input = nil
  if frame.args['input'] then
    input = frame:preprocess(frame.args['input'])
  end
  if chara == nil then
    chara = string.match(mw.title.getCurrentTitle().text, "/([^/]+)")  --[^/]+匹配1-n个非斜杠字符
  end
  if chara == nil then 
    return '<span class="error">failed to determine fighter. Please specify explicitly</span>'
  end
  if input == nil then
    return '<span class="error">input is not specified</span>'
  end

  -- 从Cargo扩展中查询数据,存储于framedata变量中
  local cargo_tables = 'MoveData'
  local fields = 'MoveData.startup, MoveData.active, MoveData.recovery'
  local cargo_args = {
    where = 'MoveData.fighter="' .. chara .. '" AND MoveData.input="' .. input .. '"'
  }
  local framedata = cargo.query(cargo_tables, fields, cargo_args);
  return framedata[1].startup
  end
  --[[ 如果查询返回了多个结果(fields),报错
  if framedata[2] ~= nil then
    return '<span class="error">cargo returned more than one move for that query somehow... This is a bug..</span>'
  end
  -- 将查询的第一个结果赋值给fd,若其为nil,则报错
  local fd = framedata[1]
  if fd == nil then
    return '<span class="error">No results</span>'
  end
  -- 开始循环,遍历包含{startup, active, recovery}的列表
  -- 对于每种帧类型,从fd中获取相应的帧数数据并存储在duration中
  -- 如果frame参数中有对应的帧类型字段,使用frame:preprocess方法处理该字段值
  -- _, frameKind表示,忽略迭代过程中的第一个返回值(即k,键),只关心第二个返回值(即v,值,循环变量命名为frameKind)
  -- inpairs保证以数组顺序(1-n)遍历数组,所以以下代码意为将frameKind依次赋值为s、a、r并进行循环体操作
  for _, frameKind in ipairs({"startup", "active", "recovery"}) do
    local duration = fd[frameKind]
    if frame.args[frameKind] ~= nil then  -- frame.args[frameKind]表示访问frame表中frameKind键对应的值
      duration = frame:preprocess(frame.args[frameKind])  -- frame:preprocess的参数中如有MW模板或变量(如{{Var}}),会自动展开
    end
    -- 如果duration为nil,则跳过这个帧类型
    if duration == nil then
    -- 如果duration可以直接转化为数字,则直接赋值给frame.args[frameKind]
    elseif tonumber(duration) ~= nil then
      frame.args[frameKind] = duration
    -- 如果不是数字,则使用对应的解析函数解析帧数字并存储于
    else
      local parsed = nil
      if frameKind == "active" then
        parsed = parseActive(duration)
      elseif frameKind == "startup" then
        parsed = parseStartup(duration)
      elseif frameKind == "recovery" then
        parsed = parseRecovery(duration)
      end
    -- 如果parsed为nil,表示解析失败,报错
      if parsed == nil then
        return string.format('<span class="error">The number of %s frames is not a simple number (%s). Please specify explicitly.</span>', frameKind, tostring(duration))
      end
    -- 如果解析成功,遍历解析后的表parsed,将每个字段值赋给frame.args[k]
      for k, v in pairs(parsed) do  -- parsed格式会是{startup = s, active = a, recovery = r}的数据格式
        frame.args[k] = v
      end
    end
  end

  -- 将此模块中p.drawFrameData的参数处理后输入给调用Module:MetaFrameChart的drawFrameData函数
  return framechart.drawFrameData(frame)
end--]]


-- 解析函数,类似MetaFrameChart模块中的功能
function parseActive(duration)
  -- simple number
  if tonumber(duration) ~= nil then
    return {active = tonumber(duration)}
  end

  if string.find(duration, "%d+%s*,") ~= nil then
    -- 1,2,3,4 format -- multihit with no gaps
    local totalActive = 0

    -- first match - just a number
    local firstval, pos = string.match(duration, "^(%d+)%s*()")
    if firstval == nil then
      return nil
    end
    -- subsequent matches - coma, then number. Might have spaces between them
    totalActive = totalActive + tonumber(firstval)
    for p1, dur, p2 in string.gmatch(duration, "(),%s*(%d+)%s*()") do
      if pos ~= p1 then
        return nil
      end
      pos = p2
      totalActive = totalActive + tonumber(dur)
    end
    if pos ~= string.len(duration)+1 then
      return nil -- trailing stuff at the end
    end
    -- Done.
    local out = {active = totalActive}
    return out 
  elseif mw.ustring.find(duration, "^%d+[x×]%d+$") ~= nil then
    -- 3x4 format -- also multihit with no gaps
    local a, b = mw.ustring.match(duration, "^(%d+)[x×](%d+)$")
    local out = { active = tonumber(a) * tonumber(b) }
    return out
  elseif string.find(duration, "^%d+%(%d+%)") ~= nil then
    -- 1(2)3(4)5 format -- multihit with gaps
    local out = {}
    -- special handling for the first number
    local firstval, pos = string.match(duration, "^(%d+)()")
    out['active'] = firstval

    local ordinal = 2
    -- then we just have a groups of "(inactive)active"
    for p1, d1, d2, p2 in string.gmatch(duration, "()%((%d+)%)(%d+)()") do
      if pos ~= p1 then
        return nil -- not directly following the previous match, so basically not what we expect
      end
      out['inactive' .. tostring(ordinal)] = d1
      out['active' .. tostring(ordinal+1)] = d2
      ordinal = ordinal + 2
      pos = p2
    end
    if pos ~= string.len(duration)+1 then
      return nil -- trailing stuff at the end
    end
    -- Done.
    return out
  end
  -- unrecognized format
  return nil
end

function parseStartup(duration)
  -- simple number
  if tonumber(duration) ~= nil then
    return {startup = tonumber(duration)}
  end

  -- 1+2 -- common for supers
  if string.find(duration, "^%d+%+%d+$") ~= nil then
    local first, second = string.match(duration, "^(%d+)%+(%d+)$")
    return {startup = tonumber(first) + tonumber(second) }
  end
  return nil
end

function parseRecovery(duration)
  -- simple number
  if tonumber(duration) ~= nil then
    return {startup = tonumber(duration)}
  end

  -- "Until L+10" -- aerial moves, such as grabs.
  if string.find(duration, "^Until L%+%d+$") ~= nil then
    local recovery = string.match(duration, "^Until L%+(%d+)$")
    return { recovery=0, specialRecovery=recovery }
  end
  return nil
end

return p