-- Super Metroid script for GGG Study [WIP] -- written by gocha, for snes9x-rr 1.43 svn. -- great thanks: http://drewseph.zophar.net/Kejardon/RAMMap.txt -- [ startup ] ----------------------------------------------------------------- if emu then error("Unknown SNES EmuLua host.") end emu = snes9x if not emu then error("Unknown SNES EmuLua host.") end -- require("bit") local bit = {} bit.band = AND bit.bor = OR bit.bxor = XOR function bit.lshift(num, shift) return SHIFT(num, -shift) end function bit.rshift(num, shift) return SHIFT(num, shift) end -- Instant ROM check function romCheck() if string.char(unpack(memory.readbyterange(0x80ffc0, 13))) ~= "Super Metroid" then return false end return true end if not romCheck() then error("Unsupported ROM: make sure if the current ROM is Super Metroid") end -- [ routines ] ---------------------------------------------------------------- local camera = {} local samus = {} local enemy = {} local projectile = {} local ingameFrame -- xx seconds => h:mm:ss.ss function formatseconds(seconds) local h, m, s s = seconds % 60 m = math.floor(seconds / 60) h = math.floor(m / 60) m = m % 60 return string.format("%d:%02d:%05.2f", h, m, s) end -- Lua version of win32 PtInRect function ptInRect(rect, pt) if pt.x >= rect.left and pt.x <= rect.right and pt.y >= rect.top and pt.y <= rect.bottom then return true else return false end end function readMemory() ingameFrame = memory.readword(0x7e09da) + (60*memory.readword(0x7e09dc)) + (60*60*memory.readword(0x7e09de)) + (60*60*60*memory.readword(0x7e09e0)) -- camera = {} camera.x = memory.readword(0x7e0911) camera.y = memory.readword(0x7e0915) camera.xsub = memory.readword(0x7e090f) camera.ysub = memory.readword(0x7e0913) -- samus = {} samus.x = memory.readword(0x7e0af6) samus.y = memory.readword(0x7e0afa) samus.xsub = memory.readword(0x7e0af8) samus.ysub = memory.readword(0x7e0afc) samus.width = memory.readword(0x7e0afe) * 2 samus.height = memory.readword(0x7e0b00) * 2 samus.speed = memory.readbyte(0x7e0b3f) samus.shineTimer = memory.readword(0x7e0a68) samus.left = samus.x - (samus.width/2) samus.top = samus.y - (samus.height/2) samus.right = samus.x + (samus.width/2) samus.bottom = samus.y + (samus.height/2) -- enemy = {} for id = 0, 31 do local i = id + 1 enemy[i] = { hp = memory.readword(0x7e0f8c + 64*id), x = memory.readword(0x7e0f7a + 64*id), y = memory.readword(0x7e0f7e + 64*id), xsub = memory.readword(0x7e0f7c + 64*id), ysub = memory.readword(0x7e0f80 + 64*id), width = memory.readword(0x7e0f82 + 64*id) * 2, height = memory.readword(0x7e0f84 + 64*id) * 2 } enemy[i].id = id enemy[i].left = enemy[i].x - (enemy[i].width/2) enemy[i].top = enemy[i].y - (enemy[i].height/2) enemy[i].right = enemy[i].x + (enemy[i].width/2) enemy[i].bottom = enemy[i].y + (enemy[i].height/2) enemy[i].active = (hp ~= 0) end -- projectile = {} for id = 0, 4 do local i = id + 1 projectile[i] = { x = memory.readword(0x7e0b64 + 2*id), y = memory.readword(0x7e0b78 + 2*id), width = memory.readword(0x7e0bb4 + 2*id) * 2, height = memory.readword(0x7e0bc8 + 2*id) * 2, type = memory.readword(0x7e0c18 + 2*id) } projectile[i].id = id projectile[i].left = projectile[i].x - (projectile[i].width/2) projectile[i].top = projectile[i].y - (projectile[i].height/2) projectile[i].right = projectile[i].x + (projectile[i].width/2) projectile[i].bottom = projectile[i].y + (projectile[i].height/2) projectile[i].active = (bit.band(projectile[i].type, 0x8000) ~= 0) end end readMemory() -- [ core ] ----------------------------------------------------------------- emu.registerbefore(function() end) emu.registerafter(function() readMemory() end) emu.registerexit(function() emu.registerbefore(nil) emu.registerafter(nil) emu.registerexit(nil) gui.register(nil) end) gui.register(function() gui.opacity(0.68) gui.box(samus.left - camera.x, samus.top - camera.y, samus.right - camera.x, samus.bottom - camera.y, "#808080") if samus.speed ~= 0 then gui.text(samus.x - camera.x - 5, samus.bottom - camera.y, string.format("%d/%d", samus.speed, samus.shineTimer)) end for i = 1, 32 do if enemy[i].active and enemy[i].width ~= 0 and enemy[i].height ~= 0 then gui.box(enemy[i].left - camera.x, enemy[i].top - camera.y, enemy[i].right - camera.x, enemy[i].bottom - camera.y, "red") gui.text(enemy[i].x - camera.x - 5, enemy[i].bottom - camera.y, string.format("#%02d", enemy[i].id)) end end for i = 1, 5 do if projectile[i].active and projectile[i].width ~= 0 and projectile[i].height ~= 0 then gui.box(projectile[i].left - camera.x, projectile[i].top - camera.y, projectile[i].right - camera.x, projectile[i].bottom - camera.y, "blue") gui.text(projectile[i].x - camera.x - 5, projectile[i].bottom - camera.y, string.format("#%02d", projectile[i].id)) end end gui.text(151, 1, string.format("CAMERA:%04X.%04X,%04X.%04X", camera.x, camera.xsub, camera.y, camera.ysub)) gui.text(151, 9, string.format(" SAMUS:%04X.%04X,%04X.%04X", samus.x, samus.xsub, samus.y, samus.ysub)) gui.text(147, 17, string.format("Frame #%07d - %s", ingameFrame, formatseconds(ingameFrame/60.0))) end) while true do if not romCheck() then emu.registerbefore(nil) emu.registerafter(nil) emu.registerexit(nil) gui.register(nil) --emu.message("Script closed.") break end emu.frameadvance() end