更多操作
小无编辑摘要 |
小无编辑摘要 |
||
第26行: | 第26行: | ||
-- query cargo for frame data | -- query cargo for frame data | ||
local cargo_tables = 'MoveData' | local cargo_tables = 'MoveData' | ||
local fields = MoveData.startup, MoveData.active, MoveData.recovery | local fields = 'MoveData.startup, MoveData.active, MoveData.recovery' | ||
local cargo_args = { | local cargo_args = { | ||
where = 'chara="' .. chara .. '" AND input="' .. input .. '"' | where = 'chara="' .. chara .. '" AND input="' .. input .. '"' |
2024年12月19日 (四) 23:24的版本
此模块的文档可以在模块:FrameChart/doc创建
-- FrameChart
local p = {}
local cargo = mw.ext.cargo
local framechart = require( "Module:MetaFrameChart" )
function p.drawFrameData( frame )
-- massage the inputs a tiny bit
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, "/([^/]+)")
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
-- query cargo for frame data
local cargo_tables = 'MoveData'
local fields = 'MoveData.startup, MoveData.active, MoveData.recovery'
local cargo_args = {
where = 'chara="' .. chara .. '" AND input="' .. input .. '"'
}
local framedata = cargo.query(cargo_tables, fields, cargo_args);
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
local fd = framedata[1]
if fd == nil then
return '<span class="error">No results</span>'
end
-- update the cargo's data with manual overrides if supplied
for _, frameKind in ipairs({"startup", "active", "recovery"}) do
local duration = fd[frameKind]
if frame.args[frameKind] ~= nil then
duration = frame:preprocess(frame.args[frameKind])
end
-- Try to be overly clever and deal with framedata that is not a simple number
-- This is totally optional.
if duration == nil then
-- no duration specified anywhere. Just skip it.
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
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
for k, v in pairs(parsed) do
frame.args[k] = v
end
end
end
-- and finally draw it
return framechart.drawFrameData(frame)
end
-- parses the passed in string to get the active/inactive frames for the move
-- returns nil when parsing failed, and a fancy table otherwise
function parseActive(duration)
-- The implementation is scary because lua doesn't have good regexes,
-- and also because I really would rather error than silently misinterpret the dat
-- 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