Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- --How many frames ahead of the "action" to start savestates
- preFrames = 45
- --Game-specific RAM addresses
- RAM = {
- words = {
- hour = 0x7e09e0,
- min = 0x7e09de,
- sec = 0x7e09dc,
- mil = 0x7e09da,
- missiles = 0x7e09c8,
- superMissiles = 0x7e09cc,
- powerBombs = 0x7e09d0,
- energyTanks = 0x7e09c4,
- reserveTanks = 0x7e09d4,
- items = 0x7e09a4,
- weapons = 0x7e09a8,
- health = 0x7e09c2,
- reserve = 0x7e09d6
- },
- bytes = {
- itemScene = 0x7e0009,
- doorScene = 0x7e05f5,
- elevatorScene = 0x7e0e18,
- transition = 0x7e0925,
- inGame = 0x7e0054 --128 if in game
- }
- }
- --Game-specific information that needs to be monitored
- gameInfo = {
- time = {
- hour = 0,
- min = 0,
- sec = 0,
- mil = 0
- },
- pct = 0,
- scene = {
- item = 0,
- door = 0,
- elevator = 0,
- transition = 0,
- transitionStarted = false,
- },
- health = 0,
- reserve = 0
- }
- --Locations to output text
- output = {
- time = {
- x = 0,
- y = 190
- },
- gameInfo = {
- x = 0,
- y = 200
- }
- }
- --Tells the script when to do nothing regarding savestates
- function DoNothing()
- UpdateGameInfo()
- if not GameActive() or memory.readbyte(RAM.bytes.inGame) ~= 128 then
- return true
- end
- return false
- end
- --Sets game information at the beginning of an attempt
- function SetGameInfo()
- --set in-game time
- gameInfo.hour = memory.readword(RAM.words.hour)
- gameInfo.min = memory.readword(RAM.words.min)
- gameInfo.sec = memory.readword(RAM.words.sec)
- gameInfo.mil = math.floor(memory.readword(RAM.words.mil) * 100 / 60)
- gameInfo.scene.item = memory.readbyte(RAM.bytes.itemScene)
- gameInfo.scene.door = memory.readbyte(RAM.bytes.doorScene)
- gameInfo.scene.elevator = memory.readbyte(RAM.bytes.elevatorScene)
- gameInfo.scene.transition = memory.readbyte(RAM.bytes.transition)
- gameInfo.health = memory.readword(RAM.words.health)
- gameInfo.reserve = memory.readword(RAM.words.reserve)
- --set percentage
- local missiles = math.floor(memory.readbyte(RAM.words.missiles) / 5)
- local superMissiles = math.floor(memory.readbyte(RAM.words.superMissiles) / 5)
- local powerBombs = math.floor(memory.readbyte(RAM.words.powerBombs) / 5)
- local energyTanks = math.floor((memory.readword(RAM.words.energyTanks) - 99) / 100)
- local reserveTanks = math.floor(memory.readword(RAM.words.reserveTanks) / 100)
- local items = memory.readword(RAM.words.items)
- local variaSuit = items % 2
- local springBall = math.floor((items % 4) / 2)
- local morphBall = math.floor((items % 8) / 4)
- local screwAttack = math.floor((items % 16) / 8)
- local gravitySuit = math.floor((items % 64) / 32)
- local hiJumpBoots = math.floor((items % 512) / 256)
- local spaceJump = math.floor((items % 1024) / 512)
- local bomb = math.floor((items % 8192) / 4096)
- local speedBooster = math.floor((items % 16384) / 8192)
- local grappleBeam = math.floor((items % 32768) / 16384)
- local xRayScope = math.floor(items / 32768)
- local weapons = memory.readword(RAM.words.weapons)
- local waveBeam = weapons % 2
- local iceBeam = math.floor((weapons % 4) / 2)
- local spazerBeam = math.floor((weapons % 8) / 4)
- local plasmaBeam = math.floor((weapons % 16) / 8)
- local chargeBeam = math.floor((weapons % 8192) / 4096)
- gameInfo.pct = missiles + superMissiles + powerBombs + energyTanks + reserveTanks + variaSuit + springBall + morphBall + screwAttack + gravitySuit + hiJumpBoots + spaceJump + bomb + speedBooster + grappleBeam + xRayScope + waveBeam + iceBeam + spazerBeam + plasmaBeam + chargeBeam
- end
- function CalculateRtaTime()
- frames = snes9x.framecount()
- hours = math.floor(frames / 216000)
- minutes = math.floor((frames - hours * 216000) / 3600)
- seconds = math.floor((frames - hours * 216000 - minutes * 3600) / 60)
- milliseconds = math.floor((frames - hours * 216000 - minutes * 3600 - seconds * 60) * 100 / 60)
- end
- --Outputs relevant game information
- function OutputGameInfo()
- CalculateRtaTime()
- gui.text(output.gameInfo.x, output.gameInfo.y, "Pct: " .. gameInfo.pct .. "%")
- gui.text(output.gameInfo.x, output.gameInfo.y + 10, "In-Game Time: " .. gameInfo.hour .. ":" .. string.format("%02d",gameInfo.min) .. ":" .. string.format("%02d",gameInfo.sec) .. "." .. string.format("%02d",gameInfo.mil) .. " RTA Time: " .. hours .. ":" .. string.format("%02d",minutes) .. ":" .. string.format("%02d",seconds) .. "." .. string.format("%02d",milliseconds))
- end
- function InScene()
- if gameInfo.scene.transition == 10 then
- gameInfo.scene.transitionStarted = true
- end
- if ((gameInfo.scene.item + gameInfo.scene.elevator > 0) or (gameInfo.scene.door > 0 and gameInfo.scene.transition >= 10 and gameInfo.scene.transitionStarted)) then
- if (gameInfo.scene.item + gameInfo.scene.door + gameInfo.scene.elevator ~= 111) then
- return true
- end
- end
- gameInfo.scene.transitionStarted = false
- return false
- end
- function GameActive()
- if (gameInfo.health > 0 or gameInfo.reserve > 0) and (not InScene()) then
- return true
- end
- return false
- end
- --Tells the script that the attempt should continue
- function ContinueAttempt()
- if GameActive() 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()
- --set in-game time
- gameInfo.hour = memory.readword(RAM.words.hour)
- gameInfo.min = memory.readword(RAM.words.min)
- gameInfo.sec = memory.readword(RAM.words.sec)
- gameInfo.mil = math.floor(memory.readword(RAM.words.mil) * 100 / 60)
- gameInfo.scene.item = memory.readbyte(RAM.bytes.itemScene)
- gameInfo.scene.door = memory.readbyte(RAM.bytes.doorScene)
- gameInfo.scene.elevator = memory.readbyte(RAM.bytes.elevatorScene)
- gameInfo.scene.transition = memory.readbyte(RAM.bytes.transition)
- gameInfo.health = memory.readword(RAM.words.health)
- gameInfo.reserve = memory.readword(RAM.words.reserve)
- end
- --Tells the script that the last segment was okay (i.e. you didn't die)
- function SegmentOk()
- if gameInfo.health > 0 or gameInfo.reserve > 0 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
- segment.bestInGameTime = 999999
- end
- if press('B') then
- segment.done = true
- segment.rollback = true
- end
- last_keys = keys
- end
- --Nothing below this point should have to change between games (though it might anyway)
- segment = {
- prevStart = savestate.create(),
- prevBest = savestate.create(),
- start = savestate.create(),
- best = savestate.create(),
- bestTime = 999999,
- lastTime = 0,
- curTime = 0,
- prevCurTime = 0,
- bestInGameTime = 999999,
- lastInGameTime = 0,
- curInGameTime = 0,
- prevCurInGameTime = 0,
- done = false,
- actionStart = 0,
- failed = false,
- rollback = false
- }
- firstSegment = true
- segment.curTime = 0
- function press(button)
- if keys[button] and not last_keys[button] then
- return true
- end
- return false
- end
- function StartSegment()
- if firstSegment then
- savestate.save(segment.prevStart)
- firstSegment = false
- end
- savestate.save(segment.start)
- segment.done = false
- segment.curTime = movie.framecount()
- segment.curInGameTime = gameInfo.hour * 216000 + gameInfo.min * 3600 + gameInfo.sec * 60 + memory.readword(RAM.words.mil)
- if segment.rollback then
- segment.curTime = segment.prevCurTime
- segment.curInGameTime = segment.prevCurInGameTime
- end
- segment.rollback = false
- segment.bestTime = 999999
- segment.bestInGameTime = 999999
- segment.lastTime = 0
- segment.lastInGameTime = 0
- end
- function OutputTime()
- gui.text(output.time.x,output.time.y,string.format("Last: %d (%d) Best: %d (%d)", segment.lastTime, segment.lastInGameTime, segment.bestTime, segment.bestInGameTime))
- end
- while true do
- SetGameInfo()
- 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()
- snes9x.frameadvance()
- OutputGameInfo()
- --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
- snes9x.frameadvance()
- UpdateGameInfo()
- OutputGameInfo()
- OutputTime()
- HandleKeys()
- end
- segment.lastTime = (movie.framecount() - segment.curTime)
- segment.lastInGameTime = gameInfo.hour * 216000 + gameInfo.min * 3600 + gameInfo.sec * 60 + memory.readword(RAM.words.mil) - segment.curInGameTime
- if ((segment.bestTime > segment.lastTime) or (segment.bestTime == segment.lastTime and segment.bestInGameTime >= segment.lastInGameTime)) and (segment.lastTime > 10) and not segment.failed and not segment.done and SegmentOk() then
- segment.bestTime = segment.lastTime
- segment.bestInGameTime = segment.lastInGameTime
- savestate.save(segment.best)
- end
- end
- if not segment.rollback then
- segment.prevCurTime = segment.curTime
- segment.prevCurInGameTime = segment.curInGameTime
- savestate.save(segment.prevBest)
- savestate.load(segment.best)
- savestate.save(segment.prevStart)
- segment.prevStart, segment.start = segment.start, segment.prevStart
- else
- savestate.load(segment.prevBest)
- savestate.save(segment.best)
- savestate.load(segment.prevStart)
- savestate.save(segment.start)
- end
- end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement