-As you'll recall, the script has 3 methods of keeping track of input:
--1. Tracking the button counts in real time. This took some minor adjustments, but seems to work fine.
--2. Parsing the button presses from a loaded, read-only TAS file when starting the script, if possible.
---This works well enough after a good amount of refactoring, but I only have it rigged to work for NES.
---As always, note that this method is very slow for big movies, which is why we only use it once.
--3. Caching the counts when saving a state and loading them when loading a state.
---savestate.registerload and savestate.registersave are not currently supported by BizHawk, so this is not functioning at all.
-I propose that a function called movie.getframe(frame) be added that gets status of all of the buttons, just like joypad.get(), for a given frame of a movie.
--This makes the would make method 2 trivial and fast.
--It would allow me to generalize the function for all platforms easily.
---Certainly there might be some discrepancies about which buttons should be disallowed, if any (Is Reset a button press?), but still. 
--If this method could somehow work for non-readonly movies, then I'd be able to use the movie to get the counts when I load a state that doesn't have cached data.
---Trust me when I tell you that this would be immensely useful for minimum button TASing. The process would be seamless, and all of these methods combined would provide perfect accuracy while being fairly efficient and only using intensive routines when absolutely necessary.

Note: Earlier, I came up with the idea for a function that lets you set what frame of the movie you are on, which would be useful for endless TASes like we've already discussed, adelikat. Do you still think this is worth having?
This commit is contained in:
brandman211 2012-03-27 06:44:47 +00:00
parent 36c4dee7b8
commit d1b00e6d4d
1 changed files with 145 additions and 0 deletions

View File

@ -0,0 +1,145 @@
--Written by Brandon Evans
--You can change the position of the text here.
local x = 0
local y = 36
local holds = 0
local pressed = {}
local presses = 0
local states = {}
function table.copy(t)
local t2 = {}
for k, v in pairs(t) do
t2[k] = v
end
return t2
end
function counts()
--Display the counts of the holds and the presses.
gui.text(x, y, 'Holds: ' .. holds)
gui.text(x, y + 14, 'Presses: ' .. presses)
end
function load(slot)
--As Lua starts counting from 1, and there may be a slot 0, increment.
slot = slot + 1
if not states[slot] or not states[slot].holds then
gui.text(x, y + 28, 'No data loaded from slot ' .. tostring(slot - 1))
counts()
return
end
--Load the data if there is any available for this slot.
holds = states[slot].holds
pressed = table.copy(states[slot].pressed)
presses = states[slot].presses
gui.text(x, y + 28, 'Data loaded from slot ' .. tostring(slot - 1))
counts()
end
function parse()
--If there is an open, read-only TAS file, parse it for the initial data.
if not movie.isloaded() then
return false
end
local fh = io.open(movie.filename())
if not fh or movie.mode() == 'record' or movie.filename():match(
'.%.(%w+)$'
) ~= 'tas' then
return false
end
local frame = -1
local last = {}
local match = {
'Up', 'Down', 'Left', 'Right', 'Start', 'Select', 'B', 'A'
}
--Parse up until two frames before the current one.
while frame ~= emu.framecount() - 2 do
line = fh:read()
if not line then
break
end
--This is only a frame if it starts with a vertical bar.
if string.sub(line, 0, 1) == '|' then
frame = frame + 1
local player = -1
--Split up the sections by a vertical bar.
for section in string.gmatch(line, '[^|]+') do
player = player + 1
--Only deal with actual players.
if player ~= 0 then
local button = 0
--Run through all the buttons.
for text in string.gmatch(section, '.') do
button = button + 1
local name = 'P' .. player .. ' ' .. match[button]
local pressed = false
--Check if this button is pressed.
if text ~= ' ' and text ~= '.' then
holds = holds + 1
--If the button was not previously pressed,
--increment.
if not last[name] then
presses = presses + 1
end
pressed = true
end
----Mark this button as pressed or not pressed.
last[name] = pressed
end
end
end
end
end
return true
end
function save(slot)
--As Lua starts counting from 1, and there may be a slot 0, increment.
slot = slot + 1
while table.maxn(states) < slot do
table.insert(states, {})
end
--Mark the current data as the data for this slot.
states[slot].holds = holds
states[slot].buttons = table.copy(buttons)
states[slot].presses = presses
gui.text(x, y + 28, 'Data saved to slot ' .. tostring(slot - 1))
counts()
end
if parse() then
gui.text(x, y + 28, 'Movie parsed for data')
else
gui.text(x, y + 28, 'No movie parsed for data')
end
if savestate.registerload then
savestate.registerload(load)
savestate.registersave(save)
end
while true do
--If this is the first frame, reset the data.
if emu.framecount() == 0 then
holds = 0
pressed = {}
presses = 0
end
local buttons = joypad.get()
--Run through all of the pressed buttons.
for button, value in pairs(buttons) do
if value then
holds = holds + 1
--If in the previous frame the button was not pressed, increment.
if not pressed[button] then
presses = presses + 1
end
end
--Mark this button as pressed or not pressed.
pressed[button] = value
end
counts()
emu.frameadvance()
end