Post subject: Lua help: Calculate steps taken?
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!
Skilled player (1889)
Joined: 4/20/2005
Posts: 2160
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.
I would like the script to show the StepID, Danger, Fraction, Offset, and Timer values each time FieldID changes.
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.
Also, I would like it to show 'Total steps in field' by adding up each time StepID changes for a given FieldID.
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.
And all of this should be dumped into a text file.
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
Lil_Gecko
He/Him
Player (94)
Joined: 4/7/2011
Posts: 520
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
Post subject: Could you add walked steps, and when I enter the menu?
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!
Lil_Gecko
He/Him
Player (94)
Joined: 4/7/2011
Posts: 520
--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.
Skilled player (1889)
Joined: 4/20/2005
Posts: 2160
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.