Module:FrameChart-GGST
is used to generate frame charts for characters in Guilty Gear: Strive semi-automatically.
It leverages Module:FrameChart under the hood, please see its documentation for further details.
Usage
Any page which uses the FrameChart module should include the template Template:FrameChartKey which explains each of the colored squares generated by the graph.
Creating the frame chart can be done by specifying the character and the input to use. For example:
{{#invoke:GGST-FrameChart|drawFrameData |chara=May |input=5P }}
Results in a neat:
However, sometimes the frame data is not represented by simple numbers, and in those cases one needs to override them explicitly - see Module:FrameChart documentation on specifics.
For example, Sol's Volcanic Viper
chara | input | name | startup | active | recovery |
---|---|---|---|---|---|
Sol Badguy | 623S | S Volcanic Viper | 9 | 14 | 18+10 Landing |
Naive version:
{{#invoke:GGST-FrameChart|drawFrameData |chara=Sol Badguy |input=623S }}
The number of recovery frames is not a simple number (18+10 Landing). Please specify explicitly.
Fixed version:
{{#invoke:GGST-FrameChart|drawFrameData |chara=Sol Badguy |input=623S |recovery=18 |specialRecovery=10 }}
local p = {} local cargo = mw.ext.cargo local framechart = require( "Module:FrameChart" ) 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 chara. 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_GGST' local fields = 'startup,active,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 -- tests that you might want to check when majorly touching the code: -- local f=mw.getCurrentFrame():newChild{args={chara="May", input="5P"}}; mw.log(p.drawFrameData(f)) -- {chara="Chipp Zanuff", input="j.H"} -- {chara="Giovanna", input="632146H"} -- {chara="Zato-1", input="j.P"} -- {chara="Zato-1", input="j.6D or j.4D"}