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

模块:FrameChart:修订间差异

来自骷髅女孩Wiki
无编辑摘要
标签手工回退
无编辑摘要
第3行: 第3行:
local cargo = require('mw.ext.cargo')
local cargo = require('mw.ext.cargo')
local framechart = require("Module:MetaFrameChart")
local framechart = require("Module:MetaFrameChart")
local html
local frameChartDataHtml


function p.drawFrameData( frame )
function p.drawFrameData( frame )
第81行: 第83行:


   -- 将此模块中p.drawFrameData的参数处理后输入给调用Module:MetaFrameChart的drawFrameData函数
   -- 将此模块中p.drawFrameData的参数处理后输入给调用Module:MetaFrameChart的drawFrameData函数
   return framechart.drawFrameData(frame)
   return metaFrameData(frame)
end
 
function p.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 activeData = parseActive(active)
    local frameAll = parseStartup(startup).startup + parseActive(active).active + parseRecovery(recovery).recovery
    if inactive2 ~= 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-surface-1) 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)
local activeType = 0
--if = ""
-- 如果传入的某值为摔则画""
    drawFrame(active, "strike", 1)
-- 检查是否存在更多的非活跃帧,遍历处理,逻辑类似于上文的取消窗口
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)
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)
--[[ 显示总帧数,创建包含总帧数的div标签,类为frame-data-total
-- 其中有2个span,一个类为frame-data-total-label的文本,显示“Total:”
-- 另一个类为frame-data-total-value,显示当前遍历后的帧数(即为总帧数)数值
html:tag('div'):addClass('frame-data-total')
:tag('span'):addClass('frame-data-total-label'):wikitext('Total:'):done()
:tag('span'):addClass('frame-data-total-value'):wikitext(currentFrame):done()
--]]
    -- 将生成的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)  --为其添加类frame-data和类frame-data-frameType
frameDataHtml:done()
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
end


第176行: 第287行:
end
end


p.drawFrame = drawFrame
return p
return p

2024年12月24日 (二) 23:26的版本

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

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

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'
  local cargo_args = {
    where = 'MoveData.fighter="' .. chara .. '" AND MoveData.input="' .. input .. '"'
  }
  local framedata = cargo.query(cargo_tables, fields, cargo_args);
  -- 如果查询返回了多个结果(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 metaFrameData(frame)
end

function p.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 activeData = parseActive(active)
    local frameAll = parseStartup(startup).startup + parseActive(active).active + parseRecovery(recovery).recovery
    if inactive2 ~= 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-surface-1) 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)
	local activeType = 0
	--if = ""
	-- 如果传入的某值为摔则画""
    drawFrame(active, "strike", 1)
	-- 检查是否存在更多的非活跃帧,遍历处理,逻辑类似于上文的取消窗口
	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)
	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)
	--[[ 显示总帧数,创建包含总帧数的div标签,类为frame-data-total
	-- 其中有2个span,一个类为frame-data-total-label的文本,显示“Total:”
	-- 另一个类为frame-data-total-value,显示当前遍历后的帧数(即为总帧数)数值
	html:tag('div'):addClass('frame-data-total')
		:tag('span'):addClass('frame-data-total-label'):wikitext('Total:'):done()
		:tag('span'):addClass('frame-data-total-value'):wikitext(currentFrame):done()
		--]]
    -- 将生成的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)  --为其添加类frame-data和类frame-data-frameType
			frameDataHtml:done()
			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

p.drawFrame = drawFrame
return p