--How many frames ahead of the "action" to start savestates preFrames = 45 --Game-specific RAM addresses RAM = { bytes = { inGame = 0x01FF, --129 if in game curPart = 0x0038, --RoomNumber lives = 0x00A8 } } --Game-specific information that needs to be monitored gameInfo = { lives = 0, curPart = 0 } --Locations to output text output = { time = { x = 10, y = 210 } } --Tells the script when to do nothing regarding savestates function DoNothing() if (memory.readbyte(RAM.bytes.inGame) ~= 129) then return true end return false end --Sets game information at the beginning of an attempt function SetGameInfo() gameInfo.curPart = memory.readbyte(RAM.bytes.curPart); gameInfo.Lives = memory.readbyte(RAM.bytes.lives); end --Outputs relevant game information function OutputGameInfo() end --Tells the script that the attempt should continue function ContinueAttempt() if gameInfo.curPart == memory.readbyte(RAM.bytes.curPart) and (memory.readbyte(RAM.bytes.inGame) == 129) then return true end return false end --Use this function to update info that may be checked later (for example, if you gain a life) function UpdateGameInfo() if (memory.readbyte(RAM.bytes.lives) > gameInfo.Lives) then gameInfo.Lives = memory.readbyte(RAM.bytes.lives); end end --Tells the script that the last segment was okay (i.e. you didn't die) function SegmentOk() if gameInfo.Lives <= memory.readbyte(RAM.bytes.lives) and gameInfo.curPart ~= memory.readbyte(RAM.bytes.curPart) then return true end return false end --Handles all the hotkey stuff function HandleKeys() keys = input.get() if press('Q') then segment.done = true end if press('R') then segment.failed = true end if press('C') then segment.failed = true segment.bestTime = 999999 end last_keys = keys end --Nothing below this point should have to change between games (though it might anyway) segment = { start = savestate.create(), best = savestate.create(), bestTime = 999999, lastTime = 0, curTime = 0, done = false, actionStart = 0, failed = false } segment.curTime = 0 function press(button) if keys[button] and not last_keys[button] then return true end return false end function StartSegment() savestate.save(segment.start) segment.done = false segment.bestTime = 999999 segment.lastTime = 0 segment.curTime = movie.framecount() end function OutputTime() gui.text(output.time.x,output.time.y,string.format("Last: %d Best: %d", segment.lastTime, segment.bestTime)) end while true do StartSegment() local closerStart = false while not segment.done do segment.failed = false savestate.load(segment.start) while not segment.done and not segment.failed and (DoNothing()) do HandleKeys() emu.frameadvance() --get a save state that's still in the transition, but close to the action for player control if movie.framecount() == segment.actionStart - preFrames then savestate.save(segment.start) closerStart = true end end SetGameInfo() if not closerStart then segment.actionStart = movie.framecount() end while not segment.done and not segment.failed and ContinueAttempt() do emu.frameadvance() UpdateGameInfo() OutputGameInfo() OutputTime() HandleKeys() end segment.lastTime = (movie.framecount() - segment.curTime) if (segment.bestTime > segment.lastTime) and (segment.lastTime > 10) and not segment.failed and not segment.done and SegmentOk() then segment.bestTime = segment.lastTime savestate.save(segment.best) end end savestate.load(segment.best) end