Snes9x Lua Library

This is the API from DeHackEd's version of Lua in ZSnes. At the time of writing, FCUE's Lua was based on this API.

# Basics

Your code will be run alongside the emulator's main loop. You code should probably look roughly like this:

    -- initialization goes here
    while condition do
       -- Code executed once per frame

       snes9x.frameadvance()

    end

    -- Cleanup goes here

When Lua execution starts, the emulator will be automatically unpaused if it is currently paused. If so, it will automatically be paused when the script exits, voluntarily or otherwise. This allows you to have a script execute some work on your behalf and then when it exits the emulator will be paused, ready for the player to continue use.

# Base library

Handy little things that are not put into a class. Mostly binary operations right now.

    int AND(int arg1, int arg2, ..., int argn)

Since Lua lacks binary operators and since binary will come up with memory manipulation, I offer this function. Output is the binary AND of all its parameters together. Minimum 1 argument, all integers.

At a binary level, the AND of two binary bits is 1 if both inputs are 1, and the output is 0 in any other case. Commonly used to test if a bit is set by ANDing with a number with only the desired position set to 1.

    int OR(int arg1, int arg2, ..., int argn)

The OR of two bits is 1 if either of the inputs is 1, and 0 if both inputs are 0. Typically used to force a single bit to 1, regardless of its current state.

    int XOR(int arg1, int arg2, ..., int argn)

XOR flips bits. An even number of 1s yields a zero and an odd number of 1s yields a 1. Commonly used to toggle a bit by XORing.

    int BIT(int which)

Returns a number with only the given bit set. `which` is in the range from 0 to 15 since the SNES is a 16 bit system. `BIT(15) == 32768`

... Actually this system will accept a range of 0 to 30, but none of the memory access functions will accept it, so you're on your own for those. 31 is not allowed for now due to signedness risking wreaking havoc.

# snes9x

Basic master emulator control.

    snes9x.speedmode(string mode)

Selects the speed mode snes9x should run at while Lua is in control of frame advance. It must be set to one of the following:

- `normal` sets to normal operation. The game runs at its normal speed. Speed control (eg: 50%) apply.
- `nothrottle` makes snes9x run at maximum CPU speed while still showing each frame on screen.
- `turbo` drops some frames. It looks like high speed fast-forwarding.
- `maximum` disables screen rendering

In modes other than normal, pause will have no effect.

    snes9x.frameadvance()

Snes9x executes one frame. This function pauses until the execution finishes. General system slowdown when running at normal speed (ie. sleeping for 1/60 seconds) also occurs here when not in high speed mode.

Warning: Due to the way the code is written, the times this function may be called is restricted. Norably, it must not be called within a coroutine or under a [x]pcall(). You can use coroutines for your own purposes, but they must not call this function themselves. Furthermore, this function cannot be called from any "registered" callback function. An error will occur if you do.

    snes9x.message(string msg)

Displays the indicated string on the user's screen. snes9x.speedmode("normal") is probably the only way this is of any use, lest the message not be displayed at all

    snes9x.pause()

v0.05+ only
Pauses the emulator. This function blocks until the user unpauses.

This function is allowed to be called from outside a frame boundary (ie. when it is not allowed to call snes9x.frameadvance). In this case, the function does not wait for the pause because you can't pause midway through a frame. Your code will continue to execute and the emulator will be paused at the end of the current frame. If you are at a frame boundary, this function acts a lot like snes9x.frameadvance() plus the whole pause thing.

It might be smart to reset the speed mode to "normal" if it is not already so.

    snes9x.wait()

v0.06+ only
Skips emulation of the next frame. If your script needs to wait for something to happen before proceeding (eg. input from another application) then you should call this. Otherwise the GUI might jam up and your application will not appear to be responding and need termination. It is expected that this function will pause the script for 1/60 of a second without actually running the emulator itself, though it tends to be OS-dependent right now.

If you're not sufficiently confused yet, think of this as pausing for one frame.

If you need to do a large amount of calculations -- so much that you risk setting off the rampant script warning, just call this function every once in a while.

Might want to avoid using this if you don't need to. If the emulator is running at normal speed, paused and the user presses frame-advance, they might be confused when nothing happens.

# memory

Memory access and manipulation.

    int memory.readbyte(int address)
    int memory.readword(int address)

Reads a number of bits (8 or 16) and returns the memory contents. The address must be a fully qualified memory address. The RAM range is 0x7e0000 through 0x7fffff, but you may use any memory address, including the ROM data itself.

    int memory.readbytesigned(int address)
    int memory.readwordsigned(int address)

v0.04+ only
Same as its counterparts, except numbers will be treated as signed. Numbers larger than 127 for bytes and 32767 for words will be translated into the correct negative numbers. For reference, an alternate formula is to subtract 256 for bytes and 65536 for words from any number equal to or larger than half that number. For example, a byte at 250 becomes `250-256 = -6`.

    memory.writebyte(int address, int value)
    memory.writebyte(int address, int value)

Writes a number of bits (8 or 16) to the indicated memory address. The address MUST be in the range of 0x7e0000 through 0x7fffff.

    memory.register(int address, function func)

When the given memory address is written to (range must be 0x7e0000 to 0x7fffff), the given function will be called. The execution of the CPU will be paused mid-frame to call the given function.

Only one function can be registered with a memory address. 16 bit writes will only trigger the lower address listener. There is no distinction between 8 and 16 bit writes. `func` may be nil in order to delete a function from listening.

Code called may not call snes9x.frameadvance() or any savestate save/load functions, and any button manipulation results are undefined. Those actions are only meaningful at frame boundaries.

# joypad

Access to the gamepads. Note that Lua makes some joysticks do strange things. Setting joypad inputs causes the user input for that frame to be ignored, but only for that one frame.

Joypads are numbered 1 to 5.

Joypad buttons are selected by use of a table with special keys. The table has keys start, select, up, down, left, right, A, B, X, Y, L, R. Note the case is sensetive. Buttons that are pressed are set to a non-nil value (use of the integer 1 is just a convention). Note that "false" is valid, but discouraged as testing for logical true will fail.

Currently reading input from a movie file is not possible, but a movie will record button presses from Lua.

    table joypad.read(int which)

Returns a table indicating which buttons are pressed by the user. This is probably the only way to get input to the script by the user. This is always user input, even if the joypads have been set by joypad.set.

    joypad.set(int which, table buttons)

Sets the buttons to be pressed. These choices will be made in place of what the user is pressing during the next frame advance; they are then discarded, so this must be called once every frame, even if you just want to keep the same buttons pressed for several frames.

# savestate

Control over the savestate process. Savestate objects are opaque structures that represent non-player accessible states (except for the functions that return "official" savesates). Such an object is garbage collectable, in which case the savestate is no longer usable. Recycling of existing savestate objects is highly recommended for disk space concerns lest the garbage collector grow lazy.

Each object is basically a savestate file. Anonymous savestates are saved to your temp directory.

    object savestate.create(int userslot=nil)

Creates a savestate object for use. If the userslot argument is given, the state will be accessible via the associated F-key (F1 through F12 are 1 through 12). If not specified or nil, an anonymous savestate is created that only Lua can access.

Each call to `savestate.create()` (without parameters) returns a unique savestate. As such, if you discard the contents of a variable containing an important savestate, you've just shot yourself in the foot.

An object may be used freely once created, saved over and loaded whenever.

It is an error to load an anonymous (non-player accessbile) state that has not been saved yet, since it's empty.

Each savestate uses about 120 KB of disk space and the random filename generator has its limits with regards to how many filenames it can generate. Don't go too overboard. If you need more than 1000 savestates, maybe you should rethink your tehcnique. (The actual windows limit is about 32768, Linux is higher).

    savestate.save(object state)

Saves the current state to the given object. Causes an error if something goes horribly wrong, or if called within any "registered" callback function.

    savestate.load(object state)

Loads the given state. Throws an error for all the same bad things that might happen.

    function savestate.registersave(function save)

v0.06+ only
Registers a function to be called on a savestate event. This includes both calls to `savestate.save()` and users pressing buttons. The function will be called without parameters.

The function called is permitted to return any number of string and number values. Lua lets you do this by simply writing `return 1, 2, 3, "four and five", 6.2, integerVar`

These variables must be numeric or string. They will be saved into the savestate itself and returned back to the application via savestate.registerload() should the state ever be loaded again later.

Only one function can be registered. Registering a second function will cause the first function to be returned back by savestate.registersave() before being discarded.

Savestates created with this mechanism are likely to break some savestate features in other emulators. Don't be surprised if savestates from this version don't work on others if you enable all those fancy features. Compatible savestates are created if there is no registered save function, or if the save function returns no parameters at all.

    function savestate.registerload(function load)

v0.06+ only
The companion to savestate.registersave, this function registers a function to be called during a load. The function will be passed parameters -- exactly those returned by the function registered for a save. If the savestate contains no saved data for your script, the function will be called without parameters.

Concept code:

    function saveState() .... end
    function loadState(arg1, arg2, ...)  ... end

    savestate.registersave(saveState)
    savestate.registerload(loadState)

    -- Behind the scenes
    local saved_variables

    -- User presses savestate
    saved_variables = { saveState() } -- All return values saved

    -- Time passes
    -- ...

    -- User presses loadstate
    loadState(unpack(saved_variables))

## Recommendations for registered savestates

- You may want to reserve the first parameter as a sort of key to make sure that the right script or the correct revision of a script is receiving its data.
- The order of declarations in your script should be local variables, then functions (inclduing these), then any registration calls, and then your main loop. Code is executed top-to-bottom, and that includes variables being prepared as locals, functions created, etc.
- You can build a string using string.char() from bytes and disassemble one from string.byte(). If you need to store a table's worth of data, you'll have to do this.

# movie

Access to movie information.

    int movie.framecount()

Returns the current frame count, or nil if no movie is running.

    string movie.mode()

Returns "record", "playback", or nil, depending on the current movie.

    movie.rerecordcounting(boolean counting)

Select whether rerecording should be counted. If set to false, you can do all the brute force work you want without inflating the rerecord count.

This will automatically be set to true after a script finishes running, so don't worry about messing up the rerecord count for the player.

    movie.stop()

Stops movie recording/playback. I'm not sure why you'd want to do that, but you can.

# gui

0.03+ only
The ability to draw on the surface of the screen is a long sought feature. The surface is 256x239 pixels (256x224 most of the time though) with (0,0) being in the top-left corner of the screen.

The SNES uses a 16 bit colour system. Red and blue both use 5 bits (0 through 31) while green uses 6 bits (0 through 63), in place of the usual 0 to 255 range. If you want to construct your own exact colours, multiply your red value by 2048, your green value by 32 and leave your blue value untouched. Add these all together to get a valid colour. Bright red would be `31*2048 = 63488`, for example.

Some strings are accepted. HTML style encoding such as "#00ff00" for green is accepted. Some simple strings such as "red", "green", "blue", "white" and "black" are also accepted.

The transparent colour is 1 (a VERY dark blue, which is probably not worth using in place of black) or the string "clear". Remove drawn elements using this colour.

Output is delayed by a frame. The graphics are drawn on a separate buffer and then overlayed on the image during the next refresh, which means allowing for a frame to execute. Also, the buffer is cleared after drawing, so if you want to keep something on screen, you must keep drawing it on each frame.

It is an error to draw outside the drawing area. gdoverlay is the only exception to this rule - images will be clipped to the visible area.

    r,g,b = gui.getpixel(int x, int y)

Returns the pixel on the indicated coordinate. (0,0) is the top-left corner and (255, 223) is the typical bottom-right corner, though (255,238) is allowed. The return value range is (0,0,0) to (31,63,31). You get the actual screen surface before any damage is done by your drawing. Well, unless you call snes9x.wait() in which case your damage is applied and the SNES hardware doesn't get a chance to draw a new frame. :)

    gui.drawpixel(int x, int y, type colour)

Draw a single pixel on the screen.

    gui.drawline(int x1, int y1, int x2, int y2, type colour)

Draw a line between the two indicated positions.

    gui.drawbox(int x1, int y1, int x2, int y2, type colour)

Draw a box going through the indicated opposite corners.

    gui.text(int x, int y, string message)

Write text on the screen at the indicated position.

The coordinates determine the top-left corner of the box that the text fits in. The font is the same one as the snes9x messages, and you can't control colours or anything. `:(`

The minimum y value is 9 for the font's height and each letter will take around 8 pixels of width. Text that exceeds the viewing area will be cut short, so ensuring your text will fit would be wise.

    string gui.gdscreenshot()

0.04+ only
Takes a screen shot of the image and returns it in the form of a string which can be imported by the gd library using the gd.createFromGdStr() function.

This function is provided so as to allow snes9x to not carry a copy of the gd library itself. If you want raw RGB32 access, skip the first 11 bytes (header) and then read pixels as Alpha (always 0), Red, Green, Blue, left to right then top to bottom, range is 0-255 for all colours.

Warning: Storing screen shots in memory is not recommended. Memory usage will blow up pretty quick. One screen shot string eats around 230 KB of RAM.

    gui.gdoverlay(int x=0, int y=0, string gdimage)

0.04+ only
Overlays the given image on top of the screen with the top-left corner in the given screen location. Transparency is not fully supported -- a pixel must be 100% transparent to actually leave a hole in the overlayed image or else it will be treated as opaque.

Naturally, the format for input is the gd file format, version 1. The image MUST be truecolour.

The image will be clipped to fit into the screen area.

    gui.transparency(int strength)

0.04+ only
Transparency mode. A value of 0 means opaque; a value of 4 means invisible (useful option that one). As for 1 through 3, I'll let you figure those out.

All image drawing (including gui.gdoverlay) will have the given transparency level applied from that point on. Note that drawing on the same point over and over will NOT build up to a higher opacity level.

    function gui.register(function func)

0.04+ only
Register a function to be called between a frame being prepared for displaying on your screen and it actually happening. Used when that 1 frame delay for rendering is a pain in the butt.

This function is not necessarily complicated to use, but it's not recommended to users new to the whole scripting thing.

You may pass nil as the parameter to kill off a registered function. The old function (if any) will be returned.

    string function gui.popup(string message, [string type = "ok"])

v0.05+ only
Pops up a dialog to the user with a message, and returns after the user acknowledges the dialog. `type` may be any of "ok", "yesno", "yesnocancel". The return value will be "yes", "no" or "cancel" as the case may be. "ok" is a waste of effort.

Linux users might want to install xmessage to perform the work. Otherwise the dialog will appear on the shell and that's less noticable.