1 2 3 4
7 8
Post subject: Re: Input from Lua is not recorded by FCEUX
Banned User
Joined: 12/23/2004
Posts: 1850
One thing you could try doing is either using InputSimplifier or just writing the output to the screen. e.g.
00  A  R
01 B U
etc. Then manually inputting this instead of the bot. If it works successfully, well, there you go. I'm not really sure in any other case, as I could record a movie after loading a Lua script...
Perma-banned
Post subject: Re: Input from Lua is not recorded by FCEUX
Editor, Active player (297)
Joined: 3/8/2004
Posts: 7469
Location: Arzareth
Xkeeper wrote:
just writing the output to the screen. e.g.
00  A  R
01 B U
etc. Then manually inputting this instead of the bot.
And for that, you can use this: http://tasvideos.org/Bisqwit/LuaFunctions.html#FunctionExplainInput (makes especially long sequences of input more manageable)
Joined: 4/25/2004
Posts: 615
Location: The Netherlands
Bisqwit did you ever manage to get IUP running under Linux? I've heard it's a real bitch and so far I don't remember anyone doing it in conjunction with FCEUX.
qfox.nl
Post subject: Re: Input from Lua is not recorded by FCEUX
Moderator, Senior Ambassador, Experienced player (907)
Joined: 9/14/2008
Posts: 1014
Bisqwit wrote:
And for that, you can use this: http://tasvideos.org/Bisqwit/LuaFunctions.html#FunctionExplainInput (makes especially long sequences of input more manageable)
I think I'll do that. I was thinking something along the same lines (writing the flat Lua table out to a file) but this will probably be more elegant. I'm going to test this bug with SMB1 using a script which performs a single jump on level 1-1 and saves to see if using Lua always truncates movie files in FCEUX. If I can reproduce it with that script it'd be a lot easier to pass the script file off to the FCEUX guys as a way to trigger the bug. Thanks for the suggestions! A.C. ******
I was laid off in May 2023 and became too ill to work this year and could use support via Patreon or onetime donations as work on TASBot Re: and TASBot HD is stalled. I'm dwangoAC, TASVideos Senior Ambassador and BDFL of the TASBot community; when healthy, I post TAS content on YouTube.com/dwangoAC based on livestreams from Twitch.tv/dwangoAC.
Post subject: Update - CWD is being changed
Moderator, Senior Ambassador, Experienced player (907)
Joined: 9/14/2008
Posts: 1014
OK, I've found the actual source of the bug - sometimes when a Lua script is executed, the current working directory is changed and the entire movie file is copied to a different directory. In my case, from the root of FCEUX I have the .fm2 movie file in \Movies and the Lua script file in \Tools. When the bug happens, a \Tools\Movies folder is created and the movie file is saved in that directory. I will file a bug in the FCEUX thread about this bug and a couple of others I've found while working on this script. The good news is I've been able to put my general purpose item finder script to good use in a few different scenarios and I've added several useful features to it. The following things are now supported: - Monitor a memory address for any number of desirable values while attempting random input with specific buttons for a specific number of frames - Watch a memory address for an undesirable value and retry if matched - Button mask - define exactly which buttons can be randomized - Button override - hold down a specific button while randomizing others - Selectable player input - pick which player's input to randomize - Uses popups to allow the user to accept a solution or retry and gives the user the option to let the script keep trying if a solution isn't found in the predefined number of attempts I've also cleaned up all of the variable names and documented the script thoroughly. Please give it a shot and let me know what you think - it should be useful to someone out there other than myself. :) You'll find the updated script at: http://lua.pastey.net/97912 Thanks again for the feedback, A.C. ******
I was laid off in May 2023 and became too ill to work this year and could use support via Patreon or onetime donations as work on TASBot Re: and TASBot HD is stalled. I'm dwangoAC, TASVideos Senior Ambassador and BDFL of the TASBot community; when healthy, I post TAS content on YouTube.com/dwangoAC based on livestreams from Twitch.tv/dwangoAC.
Player (121)
Joined: 2/11/2007
Posts: 1522
Sorry if I should report this elsewhere, but here's my current FCEUX Lua wishlist: -Ability to register a function to execute when saving and loading states. This makes it so you can essentially store the "state" of your script -Ability to read/write to other parts of RAM (PPU in particular) -The ability to toggle stuff like "show background" -- pretty much anything that can be assigned a hotkey ;) -Get the current ROM checksum and other info like name of movie file... Just throwing out ideas :D
I make a comic with no image files and you should read it. While there is a lower class, I am in it, and while there is a criminal element I am of it, and while there is a soul in prison, I am not free. -Eugene Debs
Skilled player (1827)
Joined: 4/20/2005
Posts: 2161
Location: Norrköping, Sweden
How do I make a lua script that adds input under some simple condition? For example, a lua script where I want to add the input "right" when recording a movie whenever RAM address $0000 is 0. Is this possible to do with a lua script? I still want to be able to add input of my own, I just want the lua script to run in the background, automatically pressing right for me when the condition is met.
Joined: 4/25/2004
Posts: 615
Location: The Netherlands
What you can do is create a table (array) to hold your future input. Then check the RAM for this condition and set table.right to 1. Then do other stuff and set other buttons of this table to 1 as well, as required by your script. Then feed that table to input. Something like (barring syntax errors...):
while (true) do
  local input = {}
  if (memory.readbyte(0) == 0x50) then
    input.right = 1
  end
  -- do more stuff, optionally setting input.up=1, input.down=1, etc...
  joypad.set(1,input)
  FCEU.frameadvance()
end
qfox.nl
Joined: 10/3/2005
Posts: 1332
Randil wrote:
I just want the lua script to run in the background, automatically pressing right for me when the condition is met.
I had to test to be sure, but you can actually do that, as it turns out. Surprising.
while true do
        local myinputs = {}
	myinputs = joypad.read(1)
	if(memory.readbyte(0x7e0030) < 250) then
		myinputs.right = true
		joypad.set(1,myinputs)
	end
	snes9x.frameadvance()
end
Skilled player (1827)
Joined: 4/20/2005
Posts: 2161
Location: Norrköping, Sweden
qFox: The script works, but when it's running, the game doesn't respond to my own input, just the input added by the script. You talked about storing future input in a table, does that mean that when the script is running, the game can't accept my own input, just input from this table? Dromiceius: I modified your script to work for FCEU (changed snes9x.frameadvance() to fceu.frameadvance() and changed to another condition), but once the condition was met, the script held down right the whole time, even when the condition wasn't met anymore. Seems there's a difference between FCEU and SNES9X in this case.
Joined: 4/25/2004
Posts: 615
Location: The Netherlands
Oh, I'm sorry. Yes, if Lua sets input, your input is ignored. However, you can read your input by joypad.read(1), use that as your starting table as the previous example and set right 1 or 0 depending, like before.
qfox.nl
Banned User
Joined: 12/23/2004
Posts: 1850
Any input driven by Lua will ignore everything else. There is no known way to "blend" input, as you can't read human input if you write it.
Perma-banned
Joined: 10/3/2005
Posts: 1332
Randil wrote:
Dromiceius: I modified your script to work for FCEU (changed snes9x.frameadvance() to fceu.frameadvance() and changed to another condition), but once the condition was met, the script held down right the whole time, even when the condition wasn't met anymore. Seems there's a difference between FCEU and SNES9X in this case.
My bad. You need to add "myinputs.right = nil" to unpress the button. I fixed it and tested it again (carefully, this time! :D) with Gradius III, and I think it did exactly what you were asking for. Apologies in advance if this technique doesn't work in FCEU- anything Snes9x can do, FCEU should do better, logically, but I can't test that ATM.
while true do
	local myinputs = joypad.read(1)
	if(memory.readbyte(0x7e020A) < 100) then
		myinputs.B = true
	end
	joypad.set(1,myinputs)
	myinputs.B = nil

	snes9x.frameadvance()
end
Good luck!
Joined: 4/25/2004
Posts: 615
Location: The Netherlands
I've created an EmuLua reference. You can find it at http://cbc.qfox.nl/emulua Please let me know if there are any problems or additions :)
qfox.nl
Skilled player (1827)
Joined: 4/20/2005
Posts: 2161
Location: Norrköping, Sweden
I know that you can make a Lua-script that saves and loads savestates for slots 1-9, but is there any way to save or load to a savestate created by the "Save state as..." feature? For example, if I make a savestate named test1.fca for Tetris, can I in some way make a lua script that under some condition loads this state?
Joined: 10/3/2005
Posts: 1332
I don't think there's a legitimate way of doing that, but you could possibly try is something like...
mystate = file.io("./states/test1.fca", "r")
savedata = mystate.read("all")

customstate = file.io("./states/romname.fc0", "w")
customstate.write(savedata)
Pretty simple: take mystate.fca, put it in a string, then put that string in one of Lua's normal, enumerated savestates- preferably one you don't use much. I'd wrap it in a function that takes the statename as an argument and returns a savestate object, or something like that.
Active player (328)
Joined: 2/23/2005
Posts: 786
Is this a bug? I've been trying to write a lua script that draws stuff on the screen at certain places. I've found that if you are on a frame where no lua drawing happens, the drawn stuff from the previous frame stays. So if I write a script to draw a box around a certain enemy, and then I walk off the screen so the enemy is not there, the drawn box will get frozen on the screen in the last place it was (as determined by the script that halts the drawing of the box if parts are off the screen), and will not disappear until lua draws something else. I fixed it by drawing a single pixel to the screen every frame, but it doesn't seem like this is the intended behavior. If it is intended behavior (I can see it being useful for certain scripts), is there perhaps a "gui.clear()" command that can be placed at the beginning of the loop to delete all lua stuff from the screen?
Skilled player (1827)
Joined: 4/20/2005
Posts: 2161
Location: Norrköping, Sweden
Yeah, I noticed this too. I believe I solve it by replacing the line if (condition) then (draw box) end by if (condition) then (draw box) else gui.text(10,10,"") end or something like that. The key is to get the Lua script to do something else, whatever you like, when it's not drawing the box. So basically, that gui.text command works as a gui.clear in this case. Otherwise the script thinks "well, since I don't do anything when I'm NOT drawing a box, I might as well keep the box there". Lazy Lua scripts... With that said, there's probably a better way to solve this, but this is how I solve this problem.
Active player (328)
Joined: 2/23/2005
Posts: 786
Thanks, that helps a bit. Here's my WIP of a script I'm working on to help me with the next version of the Boulder Dash TAS. It's mostly only useful when playing at slow speeds. http://www.rphaven.org/cad/TAS/boulderdash.lua Features: - Counts amoebas on stages that have them. - Shows whether falling objects are about to fall, are falling, are at rest, or will topple to the left or the right side off something else. - Indicates the next direction enemies will move, or if they can't move, shows the direction they will attempt to move. (The arrow turns blue when the enemy will wait a turn. The enemy will still move that turn if their path is unblocked before then.) - Tries to draw a red X on every tile that will kill you if you are standing on it at the beginning of the next turn. (Note: an X can still appear on top of you as you are moving into a tile, and you will be safe as long as you immediately move off that tile.) - Draws the invisible "placeholder" barriers that block movement when certain objects (like the player) move. - Marks the exit tile. Bugs: - Red Xs are only about 95% accurate. I'm still weeding out stuff. - Draws junk on the screen when not in a level. This is my first lua script, I'm pretty satisfied with it so far.
Banned User
Joined: 12/23/2004
Posts: 1850
Randil wrote:
With that said, there's probably a better way to solve this, but this is how I solve this problem.
If you haven't modified the view area (e.g., it's still 8-231) you can draw a single pixel on the screen at 0, 0. Arguably, the best way to do it would be to do "gui.pixel(0, 0, "transparent")" (or was it "clear"?) immediately after FCEU.frameadvance(). That would have absolutely no impact whatsoever on the drawing but would still update the screen, afaik.
Perma-banned
Skilled player (1827)
Joined: 4/20/2005
Posts: 2161
Location: Norrköping, Sweden
I made a Super Mario Bros dancing script! It's not very advanced, but it works and looks pretty funny. Just run the script while recording a movie, and Mario will start dancing!
while true do

local function displayer()

movetime=3

music1 = memory.readbyte(0x0F7)
music2 = memory.readbyte(0x0F8)
music3 = memory.readbyte(0x0F5)

if m1~=music1 then change1=1 else change1=0 end
if m2~=music2 then change2=1 else change2=0 end
if m3~=music3 then change3=1 else change3=0 end

if change1==1 then d1=movie.framecount() end
if change2==1 then d2=movie.framecount() end
if change3==1 then d3=movie.framecount() end

diff1=movie.framecount()-d1
diff2=movie.framecount()-d2
diff3=movie.framecount()-d3


if      diff1<movetime and diff2<movetime and diff3<movetime then joypad.set(1, {right=true, left=true, A=true}) 
elseif  diff1<movetime and diff2<movetime then joypad.set(1, {right=true, left=true}) 
elseif  diff1<movetime then joypad.set(1, {right=true})
elseif  diff2<movetime then joypad.set(1, {left=true})
else    joypad.set(1, {}) end

end

gui.register(displayer)

m1=music1
m2=music2
m3=music3

   FCEU.frameadvance()
end
Those of you who are more skilled than me at making Lua scripts might be able to come up with pretty hilarious dancing scripts. Anyone else wanna give this a try? :) EDIT: Changing the value of "movetime" will modify how long Mario will perform each "dance step". If movetime=5, then each input will be held down for 5 frames before releasing, resulting in some different dancing.
Banned User
Joined: 12/23/2004
Posts: 1850
input.get is implemented in an interm build, so I took the oppertunity to create a sort of "demonstration" script with it. Result: SMB1 with mouse controls. Kind of. I plan on releasing the source when FCEUX's input.get is finalized, as right now I gave adelikat some suggestions that would require a bit of rewriting in the code.
Perma-banned
Skilled player (1827)
Joined: 4/20/2005
Posts: 2161
Location: Norrköping, Sweden
I made a script for Deja Vu that adds some additional menu movements. For example, pressing select makes the cursor move like in Uninvited, jumping between the different boxes. Holding down Start while on the picture or minimap and pressing a directional button will move the cursor to the that corner of the picture (for example, pressing start+up+right on the picture will move the cursor to the NE corner of the picture). Give it a try!
local function boxset(x,y,box,pic)

--sets x coord
memory.writebyte(0x0A5,x) 
memory.writebyte(0x207,x-5)
memory.writebyte(0x20B,x+3) 
memory.writebyte(0x20F,x-5)  
memory.writebyte(0x213,x+3)

--sets y coord
memory.writebyte(0x0A6,y) 
memory.writebyte(0x204,y-1)
memory.writebyte(0x208,y-1) 
memory.writebyte(0x20C,y+7)  
memory.writebyte(0x210,y+7) 

--sets the correct box
memory.writebyte(0x0C3,box) 
memory.writebyte(0x0C2,pic) 

end;

while true do

x=memory.readbyte(0x0A5)
y=memory.readbyte(0x0A6)
press=memory.readbyte(0x0F0)
pic = memory.readbyte(0x0C2)
input=memory.readbyte(0x0F7)

rambox = memory.readbyte(0x0C3)

if     x>15  and x<128 and y>31  and y<144 then box=20
elseif x>127 and x<184 and y>181 and y<232 then box=19
else box=rambox

end

if box>=7 and box<=14 then area=1 end
if box>=0 and box<=6  then area=2 end
if box==20 then area=3 end
if box>=15 and box<=19  then area=4 end

if AND(input,32)/32==1 then change=1 else change=0 end

if area==1 and change==1 and press==3 then boxset(72,82,7,0) end
if area==2 and change==1 and press==3 then boxset(138,170,15,1) end
if area==3 and change==1 and press==3 then boxset(154,42,0,1) end
if area==4 and change==1 and press==3 then boxset(26,170,7,1) end

xw = 23
xm = 72
xe = 120

ys = 136
ym = 82
yn = 40

t =  {[0]= 21, 20, 22, 18, 16, 17, 26, 24, 25}
p1 = {[0]= xe, xm, xw, xw, xm, xe, xw, xm, xe}
p2 = {[0]= ys, ys, ys, ym, ym, ym, yn, yn, yn}

for i=0,8,1 do 
if pic==0 and input==t[i] and press==3 then boxset(p1[i],p2[i],7,0) end
end

mxw = 143
mxm = 155
mxe = 168

mys = 216
mym = 204
myn = 191

mp1 = {[0]= mxe, mxm, mxw, mxw, mxm, mxe, mxw, mxm, mxe}
mp2 = {[0]= mys, mys, mys, mym, mym, mym, myn, myn, myn}

for i=0,8,1 do 
if pic==2 and input==t[i] and press==3 then boxset(mp1[i],mp2[i],7,2) end
end

   FCEU.frameadvance()
end
It might be fun to TAS Deja Vu with this script, just to see how much faster it would be. :) EDIT: Changed decimal values to hexadecimal values in the boxset function for better readability.
Banned User
Joined: 12/23/2004
Posts: 1850
You've just inspired me to work on something else :) But, damnit! I want to finish my SMB script..! Aaagh. Also, for readablility, please write your addresses in hexadecimal notation. Never, ever use standard decimal for ROM/RAM addresses (and often, values). e.g., if you need to jump a tile over in NES screen, it's easier to remember 0x10 than 16 (and far easier to do multiplications of it).
Perma-banned
Active player (328)
Joined: 2/23/2005
Posts: 786
I doubt this, but I'll ask anyway: Is there any way to paint moving objects on a paused FCEU screen?
1 2 3 4
7 8