打开/关闭菜单
打开/关闭个人菜单
未登录
未登录用户的IP地址会在进行任意编辑后公开展示。

模块:FrameChart:修订间差异

来自骷髅女孩Wiki
无编辑摘要
无编辑摘要
第4行: 第4行:
local frameChartDataHtml
local frameChartDataHtml


function p.drawFrameData( frame )
function p.drawFrameData(frame)
   -- 开始循环,遍历包含{startup, active, recovery}的列表
   -- 开始循环,遍历包含{startup, active, recovery}的列表
   -- 对于每种帧类型,从fd中获取相应的帧数数据并存储在duration中
   -- 对于每种帧类型,从fd中获取相应的帧数数据并存储在duration中
第10行: 第10行:
   -- _, frameKind表示,忽略迭代过程中的第一个返回值(即k,键),只关心第二个返回值(即v,值,循环变量命名为frameKind)
   -- _, frameKind表示,忽略迭代过程中的第一个返回值(即k,键),只关心第二个返回值(即v,值,循环变量命名为frameKind)
   -- inpairs保证以数组顺序(1-n)遍历数组,所以以下代码意为将frameKind依次赋值为s、a、r并进行循环体操作
   -- inpairs保证以数组顺序(1-n)遍历数组,所以以下代码意为将frameKind依次赋值为s、a、r并进行循环体操作
   for _, frameKind in ipairs({"startup", "active", "recovery", "nsc", "linefour"}) do
   for _, frameKind in ipairs({ "startup", "active", "recovery", "nsc", "linefour" }) do
     local duration
     local duration
     if frame.args[frameKind] ~= nil then -- frame.args[frameKind]表示访问frame表中frameKind键对应的值
     if frame.args[frameKind] ~= nil then                 -- frame.args[frameKind]表示访问frame表中frameKind键对应的值
       duration = frame:preprocess(frame.args[frameKind]) -- frame:preprocess的参数中如有MW模板或变量(如{{Var}}),会自动展开
       duration = frame:preprocess(frame.args[frameKind]) -- frame:preprocess的参数中如有MW模板或变量(如{{Var}}),会自动展开
     end
     end
     -- 如果duration为nil,则跳过这个帧类型
     -- 如果duration为nil,则跳过这个帧类型
     if duration == nil then
     if duration == nil then
    -- 如果duration可以直接转化为数字,则直接赋值给frame.args[frameKind]
      -- 如果duration可以直接转化为数字,则直接赋值给frame.args[frameKind]
     elseif tonumber(duration) ~= nil then
     elseif tonumber(duration) ~= nil then
       frame.args[frameKind] = duration
       frame.args[frameKind] = duration
    -- 如果不是数字,则使用对应的解析函数解析帧数字并存储于
      -- 如果不是数字,则使用对应的解析函数解析帧数字并存储于
     else
     else
       local parsed = nil
       local parsed = nil
第34行: 第34行:
         parsed = parseLineFour(duration)
         parsed = parseLineFour(duration)
       end
       end
    -- 如果parsed为nil,表示解析失败,报错
      -- 如果parsed为nil,表示解析失败,报错
       if parsed == nil then
       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))
         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
       end
    -- 如果解析成功,遍历解析后的表parsed,将每个字段值赋给frame.args[k]
      -- 如果解析成功,遍历解析后的表parsed,将每个字段值赋给frame.args[k]
       for k, v in pairs(parsed) do -- parsed格式会是{startup = s, active = a, recovery = r}的数据格式
       for k, v in pairs(parsed) do -- parsed格式会是{startup = s, active = a, recovery = r}的数据格式
         frame.args[k] = v
         frame.args[k] = v
       end
       end
第49行: 第51行:


function metaFrameData(frame)
function metaFrameData(frame)
currentFrame = 0 --跟踪当前帧数的变量
  currentFrame = 0           --跟踪当前帧数的变量
html = mw.html.create('div') --mw的html方法,创造一个div标签
  html = mw.html.create('div') --mw的html方法,创造一个div标签
html:addClass('frameChart')   --给这个div标签添加frameChart类
  html:addClass('frameChart') --给这个div标签添加frameChart类
-- 如果传递的框架frame中有title参数,则将其值赋给title临时变量
  -- 如果传递的框架frame中有title参数,则将其值赋给title临时变量
local title
  local title
if frame.args['title'] ~= nil then
  if frame.args['title'] ~= nil then
title = frame.args['title']
    title = frame.args['title']
end
  end
-- 从传递的框架frame中获取startup、active、recovery值并赋值给同名变量
  -- 从传递的框架frame中获取startup、active、recovery值并赋值给同名变量
local startup = frame.args['startup']
  local startup = frame.args['startup']
local active = frame.args['active']
  local active = frame.args['active']
   local inactive = frame.args['inactive2']
   local inactive = frame.args['inactive2']
local recovery = frame.args['recovery']
  local recovery = frame.args['recovery']
local nsc = frame.args['nsc']
  local nsc = frame.args['nsc']
   local spe = frame.args['spe']
   local spe = frame.args['spe']
    local activeData = parseActive(active)
  local activeData = parseActive(active)
    local frameAll = parseStartup(startup).startup + parseActive(active).active + parseRecovery(recovery).recovery
  local frameAll = parseStartup(startup).startup + parseActive(active).active + parseRecovery(recovery).recovery
    if inactive ~= nil then
  if inactive ~= nil then
     local i = 2
     local i = 2
     while (frame.args['inactive' .. tostring(i)] ~= nil) do
     while (frame.args['inactive' .. tostring(i)] ~= nil) do
       frameAll = frameAll + frame.args['inactive' .. tostring(i)] + frame.args['active' .. tostring(i+1)]
       frameAll = frameAll + frame.args['inactive' .. tostring(i)] + frame.args['active' .. tostring(i + 1)]
       i = i + 2
       i = i + 2
      end
     end
     end
    local backWidth = 22 + 12 * frameAll
  end
    local backWidthArg = 'width: ' .. (math.ceil((12 * frameAll - 60) / 60) * 60 + 82) .. 'px'
  local backWidth = 22 + 12 * frameAll
    local backBlockN = math.ceil((backWidth - 82) / 60 )
  local backWidthArg = 'width: ' .. (math.ceil((12 * frameAll - 60) / 60) * 60 + 82) .. 'px'
    local scrollbarArg = 'scrollbar-color: var(--color-base) var(--color-surface-3); scrollbar-width: thin;'
  local backBlockN = math.ceil((backWidth - 82) / 60)
    -- 如果提供title变量,则创建一个包含title的div标签,并添加到HTML结构中,添加frameChart-title类
  local scrollbarArg = 'scrollbar-color: var(--color-base) var(--color-surface-3); scrollbar-width: thin;'
if title ~= nil then
  -- 如果提供title变量,则创建一个包含title的div标签,并添加到HTML结构中,添加frameChart-title类
html:tag('div'):addClass('frameChart-title'):wikitext(title):done()
  if title ~= nil then
end
    html:tag('div'):addClass('frameChart-title'):wikitext(title):done()
-- 创建div标签并添加类frameChart-data,将此帧数数据容器添加到HTML主结构中
  end
    frameChartContainer = mw.html.create('div'):addClass('frameChart-back'):attr('style', scrollbarArg .. backWidthArg):done()
  -- 创建div标签并添加类frameChart-data,将此帧数数据容器添加到HTML主结构中
    html:node(frameChartContainer)
  frameChartContainer = mw.html.create('div'):addClass('frameChart-back'):attr('style', scrollbarArg .. backWidthArg)
    frameChartStrap = {frameChartStrap1, frameChartStrap2, frameChartStrap3, frameChartStrap4, frameChartStrap5, frameChartStrap6}
  :done()
    local frameChartStrapIndex = 1
  html:node(frameChartContainer)
    while frameChartStrapIndex < 7 do
  frameChartStrap = { frameChartStrap1, frameChartStrap2, frameChartStrap3, frameChartStrap4, frameChartStrap5,
    frameChartContainer:node(mw.html.create('div'):addClass('frameChart-back-strap'):addClass('frameChart-back-strap-pos-' .. frameChartStrapIndex):attr('style', backWidthArg))
    frameChartStrap6 }
frameChartStrapIndex = frameChartStrapIndex +1
  local frameChartStrapIndex = 1
    end
  while frameChartStrapIndex < 7 do
    frameChartContainer:node(mw.html.create('div'):addClass('frameChart-back-block-first'):done())
    frameChartContainer:node(mw.html.create('div'):addClass('frameChart-back-strap'):addClass(
    local frameChartBlockIndex = 1
    'frameChart-back-strap-pos-' .. frameChartStrapIndex):attr('style', backWidthArg))
    while frameChartBlockIndex < (backBlockN + 1) do
    frameChartStrapIndex = frameChartStrapIndex + 1
    local leftArg = 'left: ' .. (80 + 60 * (frameChartBlockIndex - 1) + 2) .. 'px'
  end
    frameChartContainer:node(mw.html.create('div'):addClass('frameChart-back-block'):attr('style', leftArg))
  frameChartContainer:node(mw.html.create('div'):addClass('frameChart-back-block-first'):done())
    frameChartBlockIndex = frameChartBlockIndex + 1
  local frameChartBlockIndex = 1
    end
  while frameChartBlockIndex < (backBlockN + 1) do
    frameChartContainer:node(mw.html.create('div'):addClass('frameChart-startline'):done())
    local leftArg = 'left: ' .. (80 + 60 * (frameChartBlockIndex - 1) + 2) .. 'px'
    frameChartBody = mw.html.create('div'):addClass('frameChart-body'):done()
    frameChartContainer:node(mw.html.create('div'):addClass('frameChart-back-block'):attr('style', leftArg))
frameChartContainer:node(frameChartBody)
    frameChartBlockIndex = frameChartBlockIndex + 1
frameChartDataHtml1 = mw.html.create('div'):addClass('frameChart-data'):done()
  end
frameChartBody:node(frameChartDataHtml1)
  frameChartContainer:node(mw.html.create('div'):addClass('frameChart-startline'):done())
    -- 调用drawFrame函数,绘制第一行启动帧占位
  frameChartBody = mw.html.create('div'):addClass('frameChart-body'):done()
drawFrame(startup, "placeholder", 1)
  frameChartContainer:node(frameChartBody)
if isThrow(frame.args['properties']) then
  frameChartDataHtml1 = mw.html.create('div'):addClass('frameChart-data'):done()
  frameChartBody:node(frameChartDataHtml1)
  -- 调用drawFrame函数,绘制第一行启动帧占位
  drawFrame(startup, "placeholder", 1)
  if isThrow(frame.args['properties']) then
     drawFrame(active, "throw", 1)
     drawFrame(active, "throw", 1)
   else
   else
     drawFrame(active, "strike", 1)
     drawFrame(active, "strike", 1)
   end
   end
-- 检查是否存在更多的非活跃帧,遍历处理,逻辑类似于上文的取消窗口
  -- 检查是否存在更多的非活跃帧,遍历处理,逻辑类似于上文的取消窗口
index = 2
  index = 2
while tonumber(frame.args['active' .. index]) ~= nil or tonumber(frame.args['inactive' .. index]) ~= nil do
  while tonumber(frame.args['active' .. index]) ~= nil or tonumber(frame.args['inactive' .. index]) ~= nil do
drawFrame(frame.args['active' .. index], "strike", 1)
    drawFrame(frame.args['active' .. index], "strike", 1)
drawFrame(frame.args['inactive' .. index], "placeholder", 1)
    drawFrame(frame.args['inactive' .. index], "placeholder", 1)
index = index + 1
    index = index + 1
end
  end


frameChartDataHtml2 = mw.html.create('div'):addClass('frameChart-data'):done()
  frameChartDataHtml2 = mw.html.create('div'):addClass('frameChart-data'):done()
frameChartBody:node(frameChartDataHtml2)
  frameChartBody:node(frameChartDataHtml2)
   if isInvul(frame.args['properties']) == false and frame.args['vul'] == nil then
   if isInvul(frame.args['properties']) == false and frame.args['vul'] == nil then
     drawFrame(startup, "vuln", 2)
     drawFrame(startup, "vuln", 2)
第133行: 第138行:
   end
   end


frameChartDataHtml3 = mw.html.create('div'):addClass('frameChart-data'):done()
  frameChartDataHtml3 = mw.html.create('div'):addClass('frameChart-data'):done()
frameChartBody:node(frameChartDataHtml3)
  frameChartBody:node(frameChartDataHtml3)
    -- 调用drawFrame函数,绘制第一行启动帧占位
  -- 调用drawFrame函数,绘制第一行启动帧占位
drawFrame(nsc, "placeholder", 3)
  drawFrame(nsc, "placeholder", 3)
-- 检查是否存在更多的非活跃帧,遍历处理,逻辑类似于上文的取消窗口
  -- 检查是否存在更多的非活跃帧,遍历处理,逻辑类似于上文的取消窗口
index = 2
  index = 2
while tonumber(frame.args['nsc' .. index]) ~= nil do
  while tonumber(frame.args['nsc' .. index]) ~= nil do
drawFrame(frame.args['nsc' .. index], "nsc", 3)
    drawFrame(frame.args['nsc' .. index], "nsc", 3)
drawFrame(frame.args['nnsc' .. index], "placeholder", 3)
    drawFrame(frame.args['nnsc' .. index], "placeholder", 3)
index = index + 1
    index = index + 1
end
  end


   if spe ~= nil then
   frameChartDataHtml4 = mw.html.create('div'):addClass('frameChart-data'):done()
    frameChartDataHtml4 = mw.html.create('div'):addClass('frameChart-data'):done()
  frameChartBody:node(frameChartDataHtml4)
    frameChartBody:node(frameChartDataHtml4)
  drawFrame(spe, tostring(frame.args['spetype']), 4)
    if frame.args['spetype'] == nil then
  local i = 2
      drawFrame(spe, "placeholder", 4)
  while frame.args['spe' .. tostring(i)] do
    else
    drawFrame(frame.args['spe' .. tostring(i)], tostring(frame.args['spetype' .. tostring(i)]), 4)
      drawFrame(spe, tostring(frame.args['spetype']), 4)
   end
    end
    local i = 2
    while frame.args['spe' .. tostring(i)] do
      drawFrame(frame.args['spe' .. tostring(i)], tostring(frame.args['spetype' .. tostring(i)]), 4)
    end
   end
   -- 将生成的HTML结构转换为字符串,并使用定义在Module:FrameChart/styles.css中的样式渲染
   -- 将生成的HTML结构转换为字符串,并使用定义在Module:FrameChart/styles.css中的样式渲染
return tostring(html) .. mw.getCurrentFrame():extensionTag{
  return tostring(html) .. mw.getCurrentFrame():extensionTag {
name = 'templatestyles', args = { src = 'Module:FrameChart/styles.css' }
    name = 'templatestyles', args = { src = 'Module:FrameChart/styles.css' }
}
  }
end
end


function drawFrame(frames, frameType, line) -- frames为绘制的帧数,是数字;frameType表示帧类型,如active等
function drawFrame(frames, frameType, line)                                         -- frames为绘制的帧数,是数字;frameType表示帧类型,如active等
if tonumber(frames) ~= nil then   -- 将frames转化为数字,如果转化成功说明其为一个有效的数字字符串
  if tonumber(frames) ~= nil then                                                   -- 将frames转化为数字,如果转化成功说明其为一个有效的数字字符串
for i=1, tonumber(frames) do   -- 循环从1到frames(帧数)次
    for i = 1, tonumber(frames) do                                                 -- 循环从1到frames(帧数)次
--currentFrame = currentFrame + 1  -- 每次循环时更新currentFrame数
      --currentFrame = currentFrame + 1  -- 每次循环时更新currentFrame数
local frameDataHtml = mw.html.create('div') --创建新div标签表示单个帧(小方块)
      local frameDataHtml = mw.html.create('div')                                   --创建新div标签表示单个帧(小方块)
frameDataHtml:addClass('frame-data'):addClass('frame-data-' .. frameType):done() --为其添加类frame-data和类frame-data-frameType
      frameDataHtml:addClass('frame-data'):addClass('frame-data-' .. frameType):done() --为其添加类frame-data和类frame-data-frameType
if tonumber(line) == 1 then
      if tonumber(line) == 1 then
frameChartDataHtml1:node(frameDataHtml) --完成div标签列的构建并添加到frameChartDataHtml1结构中
        frameChartDataHtml1:node(frameDataHtml)                                     --完成div标签列的构建并添加到frameChartDataHtml1结构中
elseif tonumber(line) == 2 then
      elseif tonumber(line) == 2 then
frameChartDataHtml2:node(frameDataHtml)
        frameChartDataHtml2:node(frameDataHtml)
elseif tonumber(line) == 3 then
      elseif tonumber(line) == 3 then
frameChartDataHtml3:node(frameDataHtml)
        frameChartDataHtml3:node(frameDataHtml)
elseif tonumber(line) == 4 then
      elseif tonumber(line) == 4 then
frameChartDataHtml4:node(frameDataHtml)
        frameChartDataHtml4:node(frameDataHtml)
end
      end
end
    end
end
  end
end
end


第187行: 第186行:
   -- simple number
   -- simple number
   if tonumber(duration) ~= nil then
   if tonumber(duration) ~= nil then
     return {active = tonumber(duration)}
     return { active = tonumber(duration) }
   end
   end


第208行: 第207行:
       totalActive = totalActive + tonumber(dur)
       totalActive = totalActive + tonumber(dur)
     end
     end
     if pos ~= string.len(duration)+1 then
     if pos ~= string.len(duration) + 1 then
       return nil -- trailing stuff at the end
       return nil -- trailing stuff at the end
     end
     end
     -- Done.
     -- Done.
     local out = {active = totalActive}
     local out = { active = totalActive }
     return out  
     return out
   elseif mw.ustring.find(duration, "^%d+[x×]%d+$") ~= nil then
   elseif mw.ustring.find(duration, "^%d+[x×]%d+$") ~= nil then
     -- 3x4 format -- also multihit with no gaps
     -- 3x4 format -- also multihit with no gaps
第233行: 第232行:
       end
       end
       out['inactive' .. tostring(ordinal)] = d1
       out['inactive' .. tostring(ordinal)] = d1
       out['active' .. tostring(ordinal+1)] = d2
       out['active' .. tostring(ordinal + 1)] = d2
       ordinal = ordinal + 2
       ordinal = ordinal + 2
       pos = p2
       pos = p2
第250行: 第249行:
   -- simple number
   -- simple number
   if tonumber(duration) ~= nil then
   if tonumber(duration) ~= nil then
     return {startup = tonumber(duration)}
     return { startup = tonumber(duration) }
   end
   end


第256行: 第255行:
   if string.find(duration, "^%d+%+%d+$") ~= nil then
   if string.find(duration, "^%d+%+%d+$") ~= nil then
     local first, second = string.match(duration, "^(%d+)%+(%d+)$")
     local first, second = string.match(duration, "^(%d+)%+(%d+)$")
     return {startup = tonumber(first) + tonumber(second) }
     return { startup = tonumber(first) + tonumber(second) }
   end
   end
   return nil
   return nil
第264行: 第263行:
   -- simple number
   -- simple number
   if tonumber(duration) ~= nil then
   if tonumber(duration) ~= nil then
     return {recovery = tonumber(duration)}
     return { recovery = tonumber(duration) }
   end
   end


第270行: 第269行:
   if string.find(duration, "^Until L%+%d+$") ~= nil then
   if string.find(duration, "^Until L%+%d+$") ~= nil then
     local recovery = string.match(duration, "^Until L%+(%d+)$")
     local recovery = string.match(duration, "^Until L%+(%d+)$")
     return {recovery=0, specialRecovery=recovery }
     return { recovery = 0, specialRecovery = recovery }
   end
   end
   return nil
   return nil
第303行: 第302行:
function parseNSC(duration)
function parseNSC(duration)
   if tonumber(duration) ~= nil then
   if tonumber(duration) ~= nil then
     return {nsc = tonumber(duration)}
     return { nsc = tonumber(duration) }
   end
   end
   if string.find(duration, "^%d+%(%d+%)") ~= nil then
   if string.find(duration, "^%d+%(%d+%)") ~= nil then
第330行: 第329行:
   local out = {}
   local out = {}
   local firsttype, firstval, pos = string.match(duration, "^(%a+)(%d+)()")
   local firsttype, firstval, pos = string.match(duration, "^(%a+)(%d+)()")
     if firstval == nil then
  if firstval == nil then
     return nil
  end
  out['spe'] = firstval
  out['spetype'] = firsttype
  local ordinal = 2
  for p1, type, dur, p2 in string.gmatch(duration, "(),%s*(%a+)(%d+)%s*()") do
    if pos ~= p1 then
      return nil
    end
    out['spe' .. tostring(ordinal)] = dur
    out['spetype' .. tostring(ordinal)] = type
    ordinal = ordinal + 1
    pos = p2
    if pos ~= string.len(duration) + 1 then
       return nil
       return nil
     end
     end
    out['spe'] = firstval
  end
     out['spetype'] = firsttype
  if out['spetype'] ~= nil then
     local ordinal = 2
     if string.match(out['spetype'], "ph") ~= nil then
     for p1, type, dur, p2 in string.gmatch(duration, "(),%s*(%a+)(%d+)%s*()") do
      string.gsub(out['spetype'], "ph", "placeholder")
       if pos ~= p1 then
     end
        return nil
     if string.match(out['spetype'], "arm") ~= nil then
       end
      string.gsub(out['spetype'], "arm", "armor")
      out['spe' .. tostring(ordinal)] = dur
    end
       out['spetype' .. tostring(ordinal)] = type
    if string.match(out['spetype'], "hyp") ~= nil then
       ordinal = ordinal + 1
      string.gsub(out['spetype'], "hyp", "hyperarmor")
      pos = p2
    end
      if pos ~= string.len(duration) + 1 then
    if string.match(out['spetype'], "pro") ~= nil then
        return nil
      string.gsub(out['spetype'], "pro", "hyperarmor-proj")
       end
    end
    if string.match(out['spetype'], "hat") ~= nil then
      string.gsub(out['spetype'], "hat", "hatredguard")
    end
    if string.match(out['spetype'], "noc") ~= nil then
       string.gsub(out['spetype'], "noc", "nocollision")
    end
    if string.match(out['spetype'], "nocwh") ~= nil then
      string.gsub(out['spetype'], "nocwh", "nocollision-when-hit")
    end
  end
  local i = 2
  while out['spetype' .. tostring(i)] do
    if string.match(out['spetype'] .. tostring(i), "ph") ~= nil then
       string.gsub(out['spetype'] .. tostring(i), "ph", "placeholder")
    end
    if string.match(out['spetype' .. tostring(i)], "arm") ~= nil then
       string.gsub(out['spetype' .. tostring(i)], "arm", "armor")
    end
    if string.match(out['spetype' .. tostring(i)], "hyp") ~= nil then
       string.gsub(out['spetype' .. tostring(i)], "hyp", "hyperarmor")
    end
    if string.match(out['spetype' .. tostring(i)], "pro") ~= nil then
      string.gsub(out['spetype' .. tostring(i)], "pro", "hyperarmor-proj")
    end
    if string.match(out['spetype' .. tostring(i)], "hat") ~= nil then
       string.gsub(out['spetype' .. tostring(i)], "hat", "hatredguard")
     end
     end
     if out['spetype'] ~= nil then
     if string.match(out['spetype' .. tostring(i)], "noc") ~= nil then
      if string.match(out['spetype'], "ph") ~= nil then
       string.gsub(out['spetype' .. tostring(i)], "noc", "nocollision")
        string.gsub(out['spetype'], "ph", "placeholder")
      end
      if string.match(out['spetype'], "arm") ~= nil then
        string.gsub(out['spetype'], "arm", "armor")
      end
      if string.match(out['spetype'], "hyp") ~= nil then
        string.gsub(out['spetype'], "hyp", "hyperarmor")
      end
       if string.match(out['spetype'], "pro") ~= nil then
        string.gsub(out['spetype'], "pro", "hyperarmor-proj")
      end
      if string.match(out['spetype'], "hat") ~= nil then
        string.gsub(out['spetype'], "hat", "hatredguard")
      end
      if string.match(out['spetype'], "noc") ~= nil then
        string.gsub(out['spetype'], "noc", "nocollision")
      end
      if string.match(out['spetype'], "nocwh") ~= nil then
        string.gsub(out['spetype'], "nocwh", "nocollision-when-hit")
      end
     end
     end
     local i = 2
     if string.match(out['spetype' .. tostring(i)], "nocwh") ~= nil then
    while out['spetype' .. tostring(i)] do
       string.gsub(out['spetype' .. tostring(i)], "nocwh", "nocollision-when-hit")
      if string.match(out['spetype'] .. tostring(i), "ph") ~= nil then
        string.gsub(out['spetype'] .. tostring(i), "ph", "placeholder")
      end
      if string.match(out['spetype' .. tostring(i)], "arm") ~= nil then
        string.gsub(out['spetype' .. tostring(i)], "arm", "armor")
       end
      if string.match(out['spetype' .. tostring(i)], "hyp") ~= nil then
        string.gsub(out['spetype' .. tostring(i)], "hyp", "hyperarmor")
      end
      if string.match(out['spetype' .. tostring(i)], "pro") ~= nil then
        string.gsub(out['spetype' .. tostring(i)], "pro", "hyperarmor-proj")
      end
      if string.match(out['spetype' .. tostring(i)], "hat") ~= nil then
        string.gsub(out['spetype' .. tostring(i)], "hat", "hatredguard")
      end
      if string.match(out['spetype' .. tostring(i)], "noc") ~= nil then
        string.gsub(out['spetype' .. tostring(i)], "noc", "nocollision")
      end
      if string.match(out['spetype' .. tostring(i)], "nocwh") ~= nil then
        string.gsub(out['spetype' .. tostring(i)], "nocwh", "nocollision-when-hit")
      end
      i = i + 1
     end
     end
     return out
     i = i + 1
  end
  return out
end
end


p.drawFrame = drawFrame
p.drawFrame = drawFrame
return p
return p

2025年1月1日 (三) 23:12的版本

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

-- FrameChart
local p = {}
local html
local frameChartDataHtml

function p.drawFrameData(frame)
  -- 开始循环,遍历包含{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", "nsc", "linefour" }) do
    local duration
    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)
      elseif frameKind == "nsc" then
        parsed = parseNSC(duration)
      elseif frameKind == "linefour" then
        parsed = parseLineFour(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 metaFrameData(frame)
end

function metaFrameData(frame)
  currentFrame = 0            --跟踪当前帧数的变量
  html = mw.html.create('div') --mw的html方法,创造一个div标签
  html:addClass('frameChart') --给这个div标签添加frameChart类
  -- 如果传递的框架frame中有title参数,则将其值赋给title临时变量
  local title
  if frame.args['title'] ~= nil then
    title = frame.args['title']
  end
  -- 从传递的框架frame中获取startup、active、recovery值并赋值给同名变量
  local startup = frame.args['startup']
  local active = frame.args['active']
  local inactive = frame.args['inactive2']
  local recovery = frame.args['recovery']
  local nsc = frame.args['nsc']
  local spe = frame.args['spe']
  local activeData = parseActive(active)
  local frameAll = parseStartup(startup).startup + parseActive(active).active + parseRecovery(recovery).recovery
  if inactive ~= nil then
    local i = 2
    while (frame.args['inactive' .. tostring(i)] ~= nil) do
      frameAll = frameAll + frame.args['inactive' .. tostring(i)] + frame.args['active' .. tostring(i + 1)]
      i = i + 2
    end
  end
  local backWidth = 22 + 12 * frameAll
  local backWidthArg = 'width: ' .. (math.ceil((12 * frameAll - 60) / 60) * 60 + 82) .. 'px'
  local backBlockN = math.ceil((backWidth - 82) / 60)
  local scrollbarArg = 'scrollbar-color: var(--color-base) var(--color-surface-3); scrollbar-width: thin;'
  -- 如果提供title变量,则创建一个包含title的div标签,并添加到HTML结构中,添加frameChart-title类
  if title ~= nil then
    html:tag('div'):addClass('frameChart-title'):wikitext(title):done()
  end
  -- 创建div标签并添加类frameChart-data,将此帧数数据容器添加到HTML主结构中
  frameChartContainer = mw.html.create('div'):addClass('frameChart-back'):attr('style', scrollbarArg .. backWidthArg)
  :done()
  html:node(frameChartContainer)
  frameChartStrap = { frameChartStrap1, frameChartStrap2, frameChartStrap3, frameChartStrap4, frameChartStrap5,
    frameChartStrap6 }
  local frameChartStrapIndex = 1
  while frameChartStrapIndex < 7 do
    frameChartContainer:node(mw.html.create('div'):addClass('frameChart-back-strap'):addClass(
    'frameChart-back-strap-pos-' .. frameChartStrapIndex):attr('style', backWidthArg))
    frameChartStrapIndex = frameChartStrapIndex + 1
  end
  frameChartContainer:node(mw.html.create('div'):addClass('frameChart-back-block-first'):done())
  local frameChartBlockIndex = 1
  while frameChartBlockIndex < (backBlockN + 1) do
    local leftArg = 'left: ' .. (80 + 60 * (frameChartBlockIndex - 1) + 2) .. 'px'
    frameChartContainer:node(mw.html.create('div'):addClass('frameChart-back-block'):attr('style', leftArg))
    frameChartBlockIndex = frameChartBlockIndex + 1
  end
  frameChartContainer:node(mw.html.create('div'):addClass('frameChart-startline'):done())
  frameChartBody = mw.html.create('div'):addClass('frameChart-body'):done()
  frameChartContainer:node(frameChartBody)
  frameChartDataHtml1 = mw.html.create('div'):addClass('frameChart-data'):done()
  frameChartBody:node(frameChartDataHtml1)
  -- 调用drawFrame函数,绘制第一行启动帧占位
  drawFrame(startup, "placeholder", 1)
  if isThrow(frame.args['properties']) then
    drawFrame(active, "throw", 1)
  else
    drawFrame(active, "strike", 1)
  end
  -- 检查是否存在更多的非活跃帧,遍历处理,逻辑类似于上文的取消窗口
  index = 2
  while tonumber(frame.args['active' .. index]) ~= nil or tonumber(frame.args['inactive' .. index]) ~= nil do
    drawFrame(frame.args['active' .. index], "strike", 1)
    drawFrame(frame.args['inactive' .. index], "placeholder", 1)
    index = index + 1
  end

  frameChartDataHtml2 = mw.html.create('div'):addClass('frameChart-data'):done()
  frameChartBody:node(frameChartDataHtml2)
  if isInvul(frame.args['properties']) == false and frame.args['vul'] == nil then
    drawFrame(startup, "vuln", 2)
    drawFrame(active, "vuln", 2)
    index = 2
    while tonumber(frame.args['active' .. index]) ~= nil or tonumber(frame.args['inactive' .. index]) ~= nil do
      drawFrame(frame.args['active' .. index], "vuln", 2)
      drawFrame(frame.args['inactive' .. index], "vuln", 2)
      index = index + 1
    end
    drawFrame(recovery, "vuln", 2)
  else
    drawFrame(startup, "strike", 2)
  end

  frameChartDataHtml3 = mw.html.create('div'):addClass('frameChart-data'):done()
  frameChartBody:node(frameChartDataHtml3)
  -- 调用drawFrame函数,绘制第一行启动帧占位
  drawFrame(nsc, "placeholder", 3)
  -- 检查是否存在更多的非活跃帧,遍历处理,逻辑类似于上文的取消窗口
  index = 2
  while tonumber(frame.args['nsc' .. index]) ~= nil do
    drawFrame(frame.args['nsc' .. index], "nsc", 3)
    drawFrame(frame.args['nnsc' .. index], "placeholder", 3)
    index = index + 1
  end

  frameChartDataHtml4 = mw.html.create('div'):addClass('frameChart-data'):done()
  frameChartBody:node(frameChartDataHtml4)
  drawFrame(spe, tostring(frame.args['spetype']), 4)
  local i = 2
  while frame.args['spe' .. tostring(i)] do
    drawFrame(frame.args['spe' .. tostring(i)], tostring(frame.args['spetype' .. tostring(i)]), 4)
  end
  -- 将生成的HTML结构转换为字符串,并使用定义在Module:FrameChart/styles.css中的样式渲染
  return tostring(html) .. mw.getCurrentFrame():extensionTag {
    name = 'templatestyles', args = { src = 'Module:FrameChart/styles.css' }
  }
end

function drawFrame(frames, frameType, line)                                         -- frames为绘制的帧数,是数字;frameType表示帧类型,如active等
  if tonumber(frames) ~= nil then                                                   -- 将frames转化为数字,如果转化成功说明其为一个有效的数字字符串
    for i = 1, tonumber(frames) do                                                  -- 循环从1到frames(帧数)次
      --currentFrame = currentFrame + 1  -- 每次循环时更新currentFrame数
      local frameDataHtml = mw.html.create('div')                                   --创建新div标签表示单个帧(小方块)
      frameDataHtml:addClass('frame-data'):addClass('frame-data-' .. frameType):done() --为其添加类frame-data和类frame-data-frameType
      if tonumber(line) == 1 then
        frameChartDataHtml1:node(frameDataHtml)                                     --完成div标签列的构建并添加到frameChartDataHtml1结构中
      elseif tonumber(line) == 2 then
        frameChartDataHtml2:node(frameDataHtml)
      elseif tonumber(line) == 3 then
        frameChartDataHtml3:node(frameDataHtml)
      elseif tonumber(line) == 4 then
        frameChartDataHtml4:node(frameDataHtml)
      end
    end
  end
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 { recovery = 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

function isThrow(str)
  if str ~= nil then
    if string.find(str, "投") then
      if string.find(str, "对空投") then
        return false
      elseif string.find(str, "打击投") then
        return false
      else
        return true
      end
    else
      return false
    end
  end
end

function isInvul(str)
  if str ~= nil then
    if string.find(str, "无敌") then
      return true
    else
      return false
    end
  end
end

function parseNSC(duration)
  if tonumber(duration) ~= nil then
    return { nsc = tonumber(duration) }
  end
  if string.find(duration, "^%d+%(%d+%)") ~= nil then
    local out = {}
    local firstval, pos = string.match(duration, "^(%d+)()")
    out['nsc'] = firstval
    local ordinal = 2
    for p1, d1, d2, p2 in string.gmatch(duration, "()%((%d+)%)(%d+)()") do
      if pos ~= p1 then
        return nil
      end
      out['nsc' .. tostring(ordinal)] = d1
      out['nnsc' .. tostring(ordinal)] = d2
      ordinal = ordinal + 1
      pos = p2
    end
    if pos ~= string.len(duration) + 1 then
      return nil -- trailing stuff at the end
    end
    return out
  end
  return nil
end

function parseLineFour(duration)
  local out = {}
  local firsttype, firstval, pos = string.match(duration, "^(%a+)(%d+)()")
  if firstval == nil then
    return nil
  end
  out['spe'] = firstval
  out['spetype'] = firsttype
  local ordinal = 2
  for p1, type, dur, p2 in string.gmatch(duration, "(),%s*(%a+)(%d+)%s*()") do
    if pos ~= p1 then
      return nil
    end
    out['spe' .. tostring(ordinal)] = dur
    out['spetype' .. tostring(ordinal)] = type
    ordinal = ordinal + 1
    pos = p2
    if pos ~= string.len(duration) + 1 then
      return nil
    end
  end
  if out['spetype'] ~= nil then
    if string.match(out['spetype'], "ph") ~= nil then
      string.gsub(out['spetype'], "ph", "placeholder")
    end
    if string.match(out['spetype'], "arm") ~= nil then
      string.gsub(out['spetype'], "arm", "armor")
    end
    if string.match(out['spetype'], "hyp") ~= nil then
      string.gsub(out['spetype'], "hyp", "hyperarmor")
    end
    if string.match(out['spetype'], "pro") ~= nil then
      string.gsub(out['spetype'], "pro", "hyperarmor-proj")
    end
    if string.match(out['spetype'], "hat") ~= nil then
      string.gsub(out['spetype'], "hat", "hatredguard")
    end
    if string.match(out['spetype'], "noc") ~= nil then
      string.gsub(out['spetype'], "noc", "nocollision")
    end
    if string.match(out['spetype'], "nocwh") ~= nil then
      string.gsub(out['spetype'], "nocwh", "nocollision-when-hit")
    end
  end
  local i = 2
  while out['spetype' .. tostring(i)] do
    if string.match(out['spetype'] .. tostring(i), "ph") ~= nil then
      string.gsub(out['spetype'] .. tostring(i), "ph", "placeholder")
    end
    if string.match(out['spetype' .. tostring(i)], "arm") ~= nil then
      string.gsub(out['spetype' .. tostring(i)], "arm", "armor")
    end
    if string.match(out['spetype' .. tostring(i)], "hyp") ~= nil then
      string.gsub(out['spetype' .. tostring(i)], "hyp", "hyperarmor")
    end
    if string.match(out['spetype' .. tostring(i)], "pro") ~= nil then
      string.gsub(out['spetype' .. tostring(i)], "pro", "hyperarmor-proj")
    end
    if string.match(out['spetype' .. tostring(i)], "hat") ~= nil then
      string.gsub(out['spetype' .. tostring(i)], "hat", "hatredguard")
    end
    if string.match(out['spetype' .. tostring(i)], "noc") ~= nil then
      string.gsub(out['spetype' .. tostring(i)], "noc", "nocollision")
    end
    if string.match(out['spetype' .. tostring(i)], "nocwh") ~= nil then
      string.gsub(out['spetype' .. tostring(i)], "nocwh", "nocollision-when-hit")
    end
    i = i + 1
  end
  return out
end

p.drawFrame = drawFrame
return p