更多操作
小无编辑摘要 |
小无编辑摘要 |
||
第34行: | 第34行: | ||
} | } | ||
local framedata = cargo.query(cargo_tables, fields, cargo_args); | local framedata = cargo.query(cargo_tables, fields, cargo_args); | ||
return framedata | return framedata[2] | ||
end | end | ||
--[[ 如果查询返回了多个结果(fields),报错 | --[[ 如果查询返回了多个结果(fields),报错 |
2024年12月21日 (六) 00:42的版本
此模块的文档可以在模块: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[2]
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