Here's a script for Gradius 3, heavily based on smetroid.lua.
You get differently colored hitboxes for the player, shields, missiles, projectiles, and enemies (killable or otherwise).
Enemies have HP counters.
Finally, some address at the bottom gives an indicator of progress through the auto-scrolling level (to estimate lag?) and the vertical size of the level (256 = 1 screenful).
I think it looks pretty awesome. :)
local playerX, playerY
local cameraX, cameraY
gui.transparency(0)
while true do
playerX = memory.readword(0x7e020a)
playerY = memory.readword(0x7e020e)
-- Camera abuse: This might be wrong, but it looks right.
cameraX = 0
cameraY = 16
local radiusX, radiusY = memory.readword(0x7e0228), memory.readword(0x7e022a)
-- Draw player's hitbox
do
-- Use of tables wastes some memory, but I don't really care.
local topleft = {playerX - cameraX - radiusX, playerY - cameraY - radiusY}
if topleft[1] < 0 then
topleft[1] = 0
elseif topleft[1] >= 256 then
topleft[1] = 255
end
if topleft[2] < 0 then
topleft[2] = 0
elseif topleft[2] >= 239 then
topleft[2] = 238
end
local bottomright = {playerX - cameraX + radiusX, playerY - cameraY + radiusY}
if bottomright[1] < 0 then
bottomright[1] = 0
elseif bottomright[1] >= 256 then
bottomright[1] = 255
end
if bottomright[2] < 0 then
bottomright[2] = 0
elseif bottomright[2] >= 239 then
bottomright[2] = 238
end
-- Render
gui.drawbox(topleft[1],topleft[2], bottomright[1],bottomright[2], "#808080")
end
-- Check out interesting hit-boxes
for i=0,58 do
-- Much to my annoyance, lua has no "continue" construct. So
-- I'm wrapping the whole thing in a "loop" which I can break out of
-- and force the for loop to start its next iteration
while true do
local boxColor
local monActive = memory.readword(0x7e0350 + 64*i)
local monHP = memory.readword(0x7e0346 + 64*i)
local monX, monY = memory.readword(0x7e034a + 64*i), memory.readword(0x7e034e + 64*i)
local monRadX, monRadY = memory.readword(0x7e0368 + 64*i), memory.readword(0x7e036a + 64*i)
-- Skip inactive monsters
if monActive == 0 then
break
end
if i < 2 then -- shield
boxColor = "#800080" -- purple
elseif i < 12 then -- projectile
if monHP <= 0 then
monRadX = 3
monRadY = 3
end
boxColor = "blue"
elseif i < 22 then -- missile
if monHP <= 0 then
monRadX = 3
monRadY = 3
end
boxColor = "#800080" -- maroon
elseif monHP == 0 or monHP >= 32767 then -- not alive
boxColor = "#808080" -- grey
elseif AND(memory.readword(0x7e036e + 64*i), 0x0100) ~= 0 then -- killable enemy
boxColor = "green"
elseif AND(memory.readword(0x7e036e + 64*i), 0x0040) ~= 0 then -- enemy fire
boxColor = "red"
else -- other enemy
boxColor = "#ffff00" -- yellow
end
-- Constrain coordinates to viewable area
local topleft = {monX - cameraX - monRadX, monY - cameraY - monRadY}
if topleft[1] < 0 then
topleft[1] = 0
elseif topleft[1] >= 256 then
topleft[1] = 255
end
if topleft[2] < 0 then
topleft[2] = 0
elseif topleft[2] >= 239 then
topleft[2] = 238
end
local bottomright = {monX - cameraX + monRadX, monY - cameraY + monRadY}
if bottomright[1] < 0 then
bottomright[1] = 0
elseif bottomright[1] >= 256 then
bottomright[1] = 255
end
if bottomright[2] < 0 then
bottomright[2] = 0
elseif bottomright[2] >= 239 then
bottomright[2] = 238
end
-- If we determine that it's off the screen, screw it.
if topleft[1] == bottomright[1] or topleft[2] == bottomright[2] then
break
end
-- Draw the hitbox
gui.drawbox(topleft[1],topleft[2], bottomright[1],bottomright[2], boxColor)
-- Render the monster's HP right there
if (boxColor == "green") then
local textX, textY = topleft[1] + (bottomright[1]-topleft[1])/2, bottomright[2]
if textY > (224-8) then
textY = 224-8
end
gui.text(textX, textY, tostring(monHP))
end
break -- out of fake while loop
end -- Of false fake loop
end
-- Lastly, player's progress
local progress = memory.readword(0x7e128a)
local height = memory.readword(0x7e0090) + 1
gui.text(0,215,string.format("Progress=%05d Height=%05d", progress, height))
-- Continue emulation
snes9x.frameadvance()
-- io.write(collectgarbage("count") io.write("\r") io.flush()
end