Joined: 3/18/2006
Posts: 971
Location: Great Britain
I need to calculate number of steps taken in each field so far in FF7.
Could anyone kindly assist in making a lua script for me to accomplish this?
I'll try to explain:
0009C540 (1 byte) = StepID (This changes on each step)
0007173C (2 bytes) = Danger (This increases on each step)
0009C6D8 (1 byte) = Fraction (This changes on each fraction of a step)
0009AD2C (2 bytes) = Offset
0009A05C (2 bytes) = FieldID (This changes upon exit/entrance to a field)
0009D264 (2 bytes) = Timer (seconds)
I would like the script to show the StepID, Danger, Fraction, Offset, and Timer values each time FieldID changes.
Also, I would like it to show 'Total steps in field' by adding up each time StepID changes for a given FieldID.
And all of this should be dumped into a text file.
I'm not sure where to begin to do this myself. So I hope someone can help!
Joined: 4/20/2005
Posts: 2161
Location: Norrköping, Sweden
Maybe I'm not the best person to answer this (in particular because I haven't used lua in a PSX emulator), but I'll try to give some help:
Note that since I'm not familiar with PSX lua scripting, you might need to tweak my syntax a bit to get it to work.
Do you mean that you want to update the displayed values only when they change, but display them every frame? If so, we can construct new variables, called stepid_disp, danger_disp, ..., that only update each time fieldid changes.
I think this can be accomplished by a counter that checks if StepID changes on each frame, and if so increase this counter by 1. This counter could then be reset each time FieldID changes.
This is at least possible in lua scripting for FCEUX, BizHawk and SNES9X, and I've used this command before. If it's the same syntax here, I can help out.
So, here's my quick attempt at making a complete lua script that does all the above. I have added comments here and there to help you understand what's going on. As I said before, you'll probably need to tweak a few things to get the syntax right.
--create the "display" variables. These will be used to display values when FieldID changes
stepid_disp=memory.read_u8(0x0009C540)
danger_disp=memory.read_u16_le(0x0007173C)
fraction_disp=memory.read_u8(0009C6D8)
offset_disp=memory.read_u16_le(0009AD2C)
timer_disp=memory.read_u16_le(0009D264)
--previous fieldId value
fieldid_old=memory.read_u16_le(0009A05C)
--open up text file results will be dumped to. this text file should appear in your emulator folder
myfile1 = io.open("ff7_results.txt", "w")
--write text file header (tab separated)
myfile1:write("FieldID")
myfile1:write("\t")
myfile1:write("StepID")
myfile1:write("\t")
myfile1:write("Danger")
myfile1:write("\t")
myfile1:write("Fraction")
myfile1:write("\t")
myfile1:write("Offset")
myfile1:write("\t")
myfile1:write("Timer")
myfile1:write("\n") --do not forget newline!
--text coordinates for displaying values on screen
x0=10 --x coordinate
y0=40 --y coordinate
dy=16 --pixels between each line
stepid_changes=0 --counter for stepID changes
stepid_old=memory.read_u8(0x0009C540) --stepID value the previous frame
while true do --main loop, executed once per frame
--read in the values for this frame
stepid=memory.read_u8(0x0009C540)
danger=memory.read_u16_le(0x0007173C)
fraction=memory.read_u8(0009C6D8)
offset=memory.read_u16_le(0009AD2C)
fieldid=memory.read_u16_le(0009A05C)
timer=memory.read_u16_le(0009D264)
if fieldid ~= fieldid_old then --when FieldID is not equal to its value the previous frame
--reset stepid_changes, because we are in a new fieldID
stepid_changes=0
--update the "disp"-variables
stepid_disp=stepid
danger_disp=danger
fraction_disp=fraction
offset_disp=offset_disp
timer_disp=timer_disp
--also, dump to text file
myfile1:write(fieldid)
myfile1:write("\t")
myfile1:write(stepid)
myfile1:write("\t")
myfile1:write(danger)
myfile1:write("\t")
myfile1:write(fraction)
myfile1:write("\t")
myfile1:write(offset)
myfile1:write("\t")
myfile1:write(timer)
myfile1:write("\n") --do not forget newline!
end
--display the disp variables
gui.text(x0,y0+0*dy,"FieldID: " .. fieldid)
gui.text(x0,y0+1*dy,"StepID: " .. stepid_disp)
gui.text(x0,y0+2*dy,"Danger: " .. danger_disp)
gui.text(x0,y0+3*dy,"Fraction: " .. fraction_disp)
gui.text(x0,y0+4*dy,"Offset: " .. offset_disp)
gui.text(x0,y0+5*dy,"Timer: " .. timer_disp)
if stepid~=stepid_old then --if stepid has changed, increase counter by 1
stepid_changes=stepid_changes+1
end
gui.text(x0,y0+7*dy,"StepID changes: " .. stepid_changes)
--create the variables holding values for the previous frame
fieldid_old=fieldid
stepid_old=stepid
emu.frameadvance() --frame advance
end
I don't know if you still need this or not, but just in case.
I changed Randil's lua to make it work on pcsx, and added total number of steps by field in the dumped file.
--create the "display" variables. These will be used to display values when FieldID changes
stepid_disp=memory.readbyte(0x9C540)
danger_disp=memory.readword(0x7173C)
fraction_disp=memory.readbyte(0x9C6D8)
offset_disp=memory.readword(0x9AD2C)
timer_disp=memory.readword(0x9D264)
--previous fieldId value
fieldid_old=memory.readword(0x9A05C)
--open up text file results will be dumped to. this text file should appear in your emulator folder
myfile1 = io.open("ff7_results.txt", "w")
--write text file header (tab separated)
myfile1:write("FieldID")
myfile1:write("\t")
myfile1:write("StepID")
myfile1:write("\t")
myfile1:write("Danger")
myfile1:write("\t")
myfile1:write("Fraction")
myfile1:write("\t")
myfile1:write("Offset")
myfile1:write("\t")
myfile1:write("Timer")
myfile1:write("\t")
myfile1:write("Total steps in field")
myfile1:write("\n") --do not forget newline!
--text coordinates for displaying values on screen
x0=10 --x coordinate
y0=40 --y coordinate
dy=16 --pixels between each line
stepid_changes=0 --counter for stepID changes
stepid_old=memory.readbyte(0x0009C540) --stepID value the previous frame
while true do --main loop, executed once per frame
--read in the values for this frame
stepid=memory.readbyte(0x9C540)
danger=memory.readword(0x7173C)
fraction=memory.readbyte(0x9C6D8)
offset=memory.readword(0x9AD2C)
fieldid=memory.readword(0x9A05C)
timer=memory.readword(0x9D264)
if fieldid ~= fieldid_old then --when FieldID is not equal to its value the previous frame
--update the "disp"-variables
stepid_disp=stepid
danger_disp=danger
fraction_disp=fraction
offset_disp=offset
timer_disp=timer
--also, dump to text file
myfile1:write(fieldid)
myfile1:write("\t")
myfile1:write(stepid)
myfile1:write("\t")
myfile1:write(danger)
myfile1:write("\t")
myfile1:write(fraction)
myfile1:write("\t\t")
myfile1:write(offset)
myfile1:write("\t")
myfile1:write(timer)
myfile1:write("\t")
myfile1:write(stepid_changes)
myfile1:write("\n") --do not forget newline!
--reset stepid_changes, because we are in a new fieldID
stepid_changes=0
end
--display the disp variables
gui.text(x0,y0+0*dy,"FieldID: ".. fieldid)
gui.text(x0,y0+1*dy,"StepID: ".. stepid_disp)
gui.text(x0,y0+2*dy,"Danger: ".. danger_disp)
gui.text(x0,y0+3*dy,"Fraction: ".. fraction_disp)
gui.text(x0,y0+4*dy,"Offset: ".. offset_disp)
gui.text(x0,y0+5*dy,"Timer: ".. timer_disp)
if stepid~=stepid_old then --if stepid has changed, increase counter by 1
stepid_changes=stepid_changes+1
end
gui.text(x0,y0+7*dy,"StepID changes: " .. stepid_changes)
--create the variables holding values for the previous frame
fieldid_old=fieldid
stepid_old=stepid
emu.frameadvance() --frame advance
end
Joined: 3/18/2006
Posts: 971
Location: Great Britain
Awesome! Thanks Randil for making the script. And lil_gecko for the changes.
It worked just the way I wanted on first run.
However, there are a few things I forgot to mention that I would like added, if you get the time:
Walked Steps
I need to know every time I walk. A walk can be seen if the STEPID changes when I'm not pressing X. For every Walked step, I would also like the FieldID, StepID, Danger value, Fraction, offset, etc, to be shown in the text file.
Menu
I need to know every time I enter the menu. This can be identified by the pressing of Triangle. For each time I enter the menu, I would like the FieldID, StepID, Danger, Fraction, etc, (as above) to be shown in the text file.
Btw, would it be that much more difficult to put this information into excel rather than txt file? (if so, txt is fine)
This information is needed in order to optimise for random encounters!
Thanks!
--create the "display" variables. These will be used to display values when FieldID changes
stepid_disp=memory.readbyte(0x9C540)
danger_disp=memory.readword(0x7173C)
fraction_disp=memory.readbyte(0x9C6D8)
offset_disp=memory.readword(0x9AD2C)
timer_disp=memory.readword(0x9D264)
--previous fieldId and StepID values
fieldid_old=memory.readword(0x9A05C)
stepid_old=memory.readbyte(0x9C540)
--open up text file results will be dumped to. this text file should appear in your emulator folder
myfile1 = io.open("ff7_results.txt", "w")
--write text file header (tab separated)
myfile1:write("How;")
myfile1:write("\t")
myfile1:write("Field;")
myfile1:write("\t")
myfile1:write("StepID;")
myfile1:write("\t")
myfile1:write("Danger;")
myfile1:write("\t")
myfile1:write("Frac;")
myfile1:write("\t")
myfile1:write("Offset;")
myfile1:write("\t")
myfile1:write("Timer;")
myfile1:write("\t")
myfile1:write("Total steps in field")
myfile1:write("\n") --do not forget newline!
--text coordinates for displaying values on screen
x0=10 --x coordinate
y0=40 --y coordinate
dy=16 --pixels between each line
stepid_changes=0 --counter for stepID changes
stepid_old=memory.readbyte(0x0009C540) --stepID value the previous frame
while true do --main loop, executed once per frame
--read in the values for this frame
stepid=memory.readbyte(0x9C540)
danger=memory.readword(0x7173C)
fraction=memory.readbyte(0x9C6D8)
offset=memory.readword(0x9AD2C)
fieldid=memory.readword(0x9A05C)
timer=memory.readword(0x9D264)
how="Field"
if fieldid ~= fieldid_old then --when FieldID is not equal to its value the previous frame
--update the "disp"-variables
stepid_disp=stepid
danger_disp=danger
fraction_disp=fraction
offset_disp=offset
timer_disp=timer
--also, dump to text file
myfile1:write(how..";")
myfile1:write("\t")
myfile1:write(fieldid..";")
myfile1:write("\t")
myfile1:write(stepid..";")
myfile1:write("\t")
myfile1:write(danger..";")
myfile1:write("\t")
myfile1:write(fraction..";")
myfile1:write("\t")
myfile1:write(offset..";")
myfile1:write("\t")
myfile1:write(timer..";")
myfile1:write("\t")
myfile1:write(stepid_changes)
myfile1:write("\n") --do not forget newline!
--reset stepid_changes, because we are in a new fieldID
stepid_changes=0
end
--display the disp variables
gui.text(x0,y0+0*dy,"FieldID: ".. fieldid)
gui.text(x0,y0+1*dy,"StepID: ".. stepid_disp)
gui.text(x0,y0+2*dy,"Danger: ".. danger_disp)
gui.text(x0,y0+3*dy,"Fraction: ".. fraction_disp)
gui.text(x0,y0+4*dy,"Offset: ".. offset_disp)
gui.text(x0,y0+5*dy,"Timer: ".. timer_disp)
if ((stepid ~= stepid_old) and (memory.readbyte(0x696AF)~=191)) or memory.readbyte(0x696AF)==239 then --Check if StepID had changed while X not pressed or triangle is pressed
if memory.readbyte(0x696AF)==239 then how="Menu" --If it's triangle that is pressed
else how="Walk" --If StepID has changed while x not pressed
end
--Dump to text file
myfile1:write(how..";")
myfile1:write("\t")
myfile1:write(fieldid..";")
myfile1:write("\t")
myfile1:write(stepid..";")
myfile1:write("\t")
myfile1:write(danger..";")
myfile1:write("\t")
myfile1:write(fraction..";")
myfile1:write("\t")
myfile1:write(offset..";")
myfile1:write("\t")
myfile1:write(timer..";")
myfile1:write("\t")
myfile1:write(stepid_changes)
myfile1:write("\n") --do not forget newline!
end
if stepid~=stepid_old then --if stepid has changed, increase counter by 1
stepid_changes=stepid_changes+1
end
gui.text(x0,y0+7*dy,"StepID changes: " .. stepid_changes)
--create the variables holding values for the previous frame
fieldid_old=fieldid
stepid_old=stepid
emu.frameadvance() --frame advance
end
Since joypad.get doesn't record movie's input and I'm guessing you want to run the script while playing back a movie I had to search for the memory adress recording which key is pressed.
I found 0x696AF that has 191 when X is pressed and 239 when Triangle is.
I know it works for the beginning of the game but it may be a different adress and different values for where you're at, in which case you'll have to change it into the script.
I don't know if it's possible to dump into excel right away but I've add semicolon into the text file so you can copy/paste it into Excel and use the semicolons as separator.
Joined: 4/20/2005
Posts: 2161
Location: Norrköping, Sweden
I intentionally chose tab (/t) as separator, so that when you open the text file in excel it will automatically interpret it correctly. So try opening the ouput text file as it is in excel, and it should (hopefully!) look good.
Good luck with FF7, it's one of my favourite games and it would be awesome to see a TAS of it.