Here are a few scripts I've made for Ninja Gaiden along with a few questions! After reloading a script a few times emulation slows down, getting progressively worse with successive reloads. Is there something I should be doing differently to prevent this?
This one just shows some basic position and speed info and was mainly made as a learning tool, I never actually need to see any of this crap on the game screen.
local xpix = 0x0086; xsub = 0x0085; ypix = 0x008A; ysub = 0x0087; yspd = 0x0089; screen = 0x00A3; scrnsub = 0x00A2
local xpos, ypos, scrnpos, yspdd
local function show_coords()
yspdd = memory.readbytesigned(yspd)
xpos = memory.readbyte(xpix) + (memory.readbyte(xsub)/256)
ypos = memory.readbyte(ypix) + (memory.readbyte(ysub)/256)
scrnpos = memory.readbyte(screen) + (memory.readbyte(scrnsub)/256)
gui.text(2,10,"Ryu:" .. xpos)
gui.text(49,10,"," .. ypos)
gui.text(205,24,"Y-speed:" .. yspdd)
gui.text(192,10,"Screen:" .. scrnpos)
end
emu.frameadvance()
gui.register(show_coords)
This is for macro'd 30hz wall-climbing. It could be a bit smarter: interrupting the 'jump, grab, jump...' pattern throws it off, and it doesn't account the different values for which direction Ryu is facing during damage flicker. But it does what it's supposed do to nicely enough.
local qpress,ryuface,ysub
while true do
qpress=input.get()
ryuface=memory.readbyte(0x0084)
ysub=memory.readbyte(0x0087)
if qpress.Q then
if ysub == 0 and ryuface == 68 then
joypad.set(1, {left=1, right=1})
end
if ysub == 0 and ryuface == 4 then
joypad.set(1, {up=1, down=1, left=1})
end
if ysub > 0 and ryuface == 68 then
joypad.set(1, {left=1, A=1})
end
if ysub > 0 and ryuface == 0 then
joypad.set(1, {left=1, A=1})
end
if ysub > 0 and ryuface == 4 then
joypad.set(1, {right=1, A=1})
end
if ysub > 0 and ryuface == 64 then
joypad.set(1, {right=1, A=1})
end
end
emu.frameadvance()
end
This is where the speed thing becomes an issue, since I've been modifying and reloading stuff like this a lot.
(in this example i was cycling a not-really-RNG to see which values resulted in ryu getting hit by a tossed ax if he followed a specific path, then writing the value to a .txt file if he did get hit(yeah i know 'attempt' is totally redundant here, but this is just an easily-edited template for the general approach i've been taking to finding if some particular desired outcome is even possible before attempting to manipulate anything))
local attempt = 0
local globtim = 0
local frame = 1
local gothit
results = io.open("NGresults.txt", "w")
NGtest = savestate.create()
savestate.save(NGtest)
while attempt <= 256 do
attempt=attempt+1
memory.writebyte(0x00BF, globtim)
frame=emu.framecount()
while frame < 20919 do
frame=emu.framecount()
gothit=memory.readbyte(0x0095)
if gothit == 60 then
results:write(globtim,",")
end
emu.frameadvance()
end
globtim=globtim+1
savestate.load(NGtest)
gui.text(4,10,"" .. attempt)
gui.text(4,20,"" .. globtim)
end
results:close()
And finally, this grotesquery... It's supposed to, in a pretty basic manner, do what I described in
this post. One thing I'm not clear on is why it doesn't update like the show_coords example above.
local bg_obj1 = 0x0300; bg_obj2 = 0x0301; bg_obj3 = 0x0302; bg_obj4 = 0x0303; bg_obj5 = 0x0304; bg_obj6 = 0x0305
local xpos=0; cycle=0
local function view_bg()
while cycle < 22 do
Column01A = memory.readbyte(bg_obj1); Column01B = memory.readbyte(bg_obj2); Column01C = memory.readbyte(bg_obj3); Column01D = memory.readbyte(bg_obj4); Column01E = memory.readbyte(bg_obj5); Column01F = memory.readbyte(bg_obj6)
gui.text(xpos,8,"" .. Column01A); gui.text(xpos,16,"" .. Column01B); gui.text(xpos,24,"" .. Column01C); gui.text(xpos,32,"" .. Column01D); gui.text(xpos,40,"" .. Column01E); gui.text(xpos,48,"" .. Column01F); xpos=xpos+12
bg_obj1=bg_obj1+6;bg_obj2=bg_obj2+6;bg_obj3=bg_obj3+6;bg_obj4=bg_obj4+6;bg_obj5=bg_obj5+6;bg_obj6=bg_obj6+6;cycle=cycle+1
end
end
emu.frameadvance()
gui.register(view_bg)
I started writing it with .readbyterange and tables in mind, but then I realized I had no idea what I was doing. Also, displaying it in hexadecimal and with zeroes with the single-digit values would have been ideal, but as someone whose only prior programming experience is some pretty basic BASIC from over a decade ago I'm finding the Lua documentation to be somewhat esoteric.
Edit: on IRC amaurea kindly explained string.format, field widths, and how to get zero padding (and some other stuff!), which leaves my only remaining real question about the slowdown issue with multiple reloads.
Edit2: It occurred to me that declaring the variables outside the function and then counting them to infinity was kind of moronic, so here's my glorified hex-viewer fixed:
local function view_bg()
local bg_obj1 = 0x0300; bg_obj2 = 0x0301; bg_obj3 = 0x0302; bg_obj4 = 0x0303; bg_obj5 = 0x0304; bg_obj6 = 0x0305
local xpos=0; cycle=0
while cycle < 21 do
Column01A = memory.readbyte(bg_obj1); Column01B = memory.readbyte(bg_obj2); Column01C = memory.readbyte(bg_obj3)
Column01D = memory.readbyte(bg_obj4); Column01E = memory.readbyte(bg_obj5); Column01F = memory.readbyte(bg_obj6)
gui.text(xpos,8,string.format("%02x",Column01A)); gui.text(xpos,16,string.format("%02x",Column01B)); gui.text(xpos,24,string.format("%02x",Column01C))
gui.text(xpos,32,string.format("%02x",Column01D)); gui.text(xpos,40,string.format("%02x",Column01E)); gui.text(xpos,48,string.format("%02x",Column01F))
bg_obj1=bg_obj1+6;bg_obj2=bg_obj2+6;bg_obj3=bg_obj3+6;bg_obj4=bg_obj4+6;bg_obj5=bg_obj5+6;bg_obj6=bg_obj6+6
cycle=cycle+1; xpos=xpos+12
end
end
emu.frameadvance()
gui.register(view_bg)