Gens Lua Documentation

Contents

Introduction

Gens allows you to run Lua scripts within it, so you can write scripts to extend its functionality however you like. In addition to the functions provided by Lua's default libraries, Gens provides additional functions you can call from Lua which for the most part are necessary if you want to do anything interesting. This documentation exists to show you what these useful functions are and how to use them in Gens. For general help with Lua itself you might want to refer to the
Lua 5.1 manual, although many things in Lua are easy to pick up by example.

Techniques / Answers

How to make Gens run a Lua script

First choose "Tools > Lua Scripting > New Lua Script Window..." from the menu. In the window that opens up, click Browse and choose a .lua file. That's all! It will automatically start running.

(An even easier way is to simply drag and drop a .lua file onto the main window of Gens.)

Note that Gens keeps a list of your recently loaded scripts in the "Tools > Lua Scripting" menu, so all you have to do is choose it from the menu to bring it back up later, or you can assign a hotkey to load the most recent script. You don't need to choose "New Lua Script Window" except when you're just getting started using a new script.

How to edit Lua scripts in Gens

Gens itself cannot edit Lua scripts. To edit a Lua script, you have to open it in an external text editor. You can quickly start editing a script file you have open in Gens by clicking the "Edit" button in the script window, assuming your editor has already been set up.

If you haven't already set up your text editor: First, choose which editor to use. It's a matter of personal preference, however, it is highly recommended that you use an editor that is smart enough to recognize when an already-open file is being opened, otherwise you can easily end up with the same script being edited in two different windows (which can get confusing and make you lose work). For example, Notepad++ or Notepad2 (with the "Single File Instance" option turned on) are adequate choices, while regular Notepad is not smart enough to do this and should be avoided. Now, once you've chosen an editor, you should associate .lua files with it. One way to do this in Windows is to try opening a .lua file, choose the program you want to use from the list or browse to it, then check the "Always use the selected program to open this kind of file" option and open the file.

Gens will try to show your changes "on the fly" if you edit a Lua file while it also open in Gens. It does this by immediately reloading and restarting your script every time you save the script file. If your edit involves GUI drawing or simple console output, in many cases you should see your results right away without even needing to switch the window back to Gens, assuming you have positioned your text editor to not completely cover up the emulator windows while you're using it. But, depending on what you are editing, you might need to make sure emulation is unpaused in the background in order to see the results of your changes as quickly as possible. ("Auto Pause" needs to be disabled in the General options to do this.) If your script has values that would be inconvenient to reset every time the script reloads, you can use something like gens.persistglobalvariables to prevent them from resetting when the script restarts.

How to make your script run for more than one frame

If you try to run a snippet of normal Lua code, Gens will temporarily suspend emulation, then run all the Lua code, then resume emulation. That all happens in one frame. But typically in Gens what you really want is for the script to run "alongside" the emulation, over many frames. There are several ways of achieving this:

One style of code you can write is a "frame advance loop" which overrides the emulator's main loop while the script is running:


-- initialization code (if any) goes here

while true do
  -- code that runs once per frame (and stops this loop when finished) goes here
 
gens.frameadvance() -- this tells Gens to advance to the next frame
end

-- cleanup code (if any) goes here

This type of script is well-suited for making "bots" and is possibly the easiest to get running, but it has some drawbacks. In particular, it cannot coexist peacefully with another script of the same type (they both try to take over the main loop so only one will run). Also, any GUI drawing functions you call will happen 1 frame late because of the way gens.frameadvance() works.

Another way is to tell Gens when to call which parts of your code, and then let Gens run your code while it stays in control of the main loop:


-- initialization code (if any) goes here

gui.register( function()
  -- put any drawing code you want to do here
end)

gens.registerbefore( function()
  -- put any code you want to run before each frame here
  -- (such as getting/setting the next frame's input or writing to memory)
end)

gens.registerafter( function()
  -- put any code you want to run after each frame here
  -- (such as getting the last frame's input or reading from memory)
end)

gens.registerexit( function()
  -- cleanup code (if any) goes here
end)

This type of script is very well-suited for displaying information overlays or passively analyzing or modifying a game being played. It also makes it easy run your script simultaneously with almost any other script in order to combine their functionality. It looks more complicated than the previous example but keep in mind that each section is optional and for many types of scripts it is actually simpler. The real disadvantage is that it's not as good for making bots, because while it gives you more control over when things happen within each frame, it makes it harder to control over how often frames happen.

You can do something in-between the above methods as well. For example, if you want to make a script that runs a bot and also displays some information about its progress as a GUI overlay, one way to structure it would be:


gui.register( function ()
  -- put code here that draws something about the bot's progress
end)

while true do
  -- put code here that runs the bot for a frame and stops the loop if it's done
  gens.frameadvance()
end

By the way, the command to stop a loop in Lua is break.

How to make a script forcefully stop itself

When a script returns in Gens, it doesn't necessarily stop, because it might have registered callbacks. As long as a script has any registered callbacks, Gens will keep the script alive to call those callbacks as appropriate. That's almost always what you would want to happen, but what if you actually want a script to completely terminate itself when some condition is met? You might wonder why Gens doesn't provide any "stop running" functions for this purpose. The reason is that Lua's default libraries already provide at least one perfectly good and simple mechanism for it:
error("script stopped itself because X")
Another option is to unregister all registered callbacks individually, and return. Most of the time you won't need to do either of these because the easier thing to do is simply let your scripts run forever until you decide to stop them manually (by clicking the "Stop" button or closing the emulator).

How to update a GUI while the game is paused

There is a gens.pause function, but that pauses both the emulation and the script. What if you only want to pause emulation, and keep your script running and updating the screen? For example, you might want to pause emulation and draw some options on the screen, then resume emulation when the user clicks on one of the options. You can do this in Gens with a slight variation on the "frame advance loop" that refreshes the screen in a loop but doesn't actually advance the emulation state:
while true do
  -- code that runs once per loop (and stops this loop when finished) goes here
 
gens.redraw()
  gens.wait()
end

It is recommended, but not necessary, that you use this in conjunction with a gui.register'd function. Also, since it doesn't advance the frame, this technique should work even before emulation has started.

How scripts interact with each other

In Gens you are allowed to run multiple Lua scripts at the same time. They operate independently, so you can combine the different behavior of separate scripts without needing to hack the scripts together or modify them in any way.

There are some limitations: Most importantly, at most one of the scripts is allowed to "take over" the frame advance loop at a time. See the second part of "how to make your script run for more than one frame" for advice on how to handle this correctly. If the scripts you are trying to combine are written properly, the practical effect of this limitation should boil down to "you can't run more than one bot at the same time". (If you try it, most likely one of them will wait for the other to finish before doing anything.)

For the most part, scripts that are running simultaneously operate completely independently. They each run in a separate Lua virtual machine and thus cannot intentionally or unintentionally affect anything about the Lua state of each other, for instance they cannot see or change each other's global variables. Additionally, they each maintain their own set of registered callback functions, they each maintain their own state about various things scripts can change such as the global drawing transparency level, and so on.

If multiple scripts register the same type of callback, the emulator will call all of them in sequence whenever the callback's trigger condition is met. The order they get called in is determined by the order the scripts started up relative to each other. In many cases the order doesn't matter, but if for some reason you need to control the order from scripts then there is not much you can do besides using gens.openscript to start the scripts in a certain order.

The only way for separately-running scripts to affect each other is indirectly: either through file operations, or through changing the state of the emulation. Both of these are expected (if not desirable) avenues of interaction. Note that using numbered savestates counts as a "file operation", which is why it is recommended for scripts to use anonymous (stored in memory) savestates instead whenever possible. Of course, loading any savestate, anonymous or not, counts as "changing the state of the emulation".


Global Functions

A small handful of the additional functions aren't in any library:

print (...)

Prints any value or values, mainly to help you debug your script. Unlike the default implementation, this can even print the contents of tables. Also, the printed values will go to the script's output window instead of stdout. Note that if you want to print a memory address you should use print(
string.format("0x%X",address)) instead of print(address).

If you want the text to appear on the game screen then this isn't the right function for that (see gui.text or gens.message). print is much slower than gui.text as well, so if you want to show information every frame, then gui.text is the preferred way of doing it.

print makes it easy to inspect the state of Lua, for example, you can print the entire table of global variables ( print(_G) ), or you can print a specific library ( print(gens) ) to see all the functions it defines. For an even more complete table than _G you can also try print(debug.getregistry()). If you want the old behavior of printing a table's unique ID instead of its contents, you can print addressof(table). If you want to customize print then you should really look at tostring instead.


AND (...)

Returns the bitwise AND of all the parameters. Zero or more integer arguments are allowed. Each bit in the result will be 1 if all of the inputs have that bit 1, or 0 otherwise.

OR (...)

Returns the bitwise OR of all the parameters. Zero or more integer arguments are allowed. Each bit in the result will be 1 if any of the inputs have that bit 1, or 0 otherwise.

XOR (...)

Returns the bitwise XOR of all the parameters. Zero or more integer arguments are allowed. Each bit in the result will be 1 if an odd number of the inputs have that bit 1, or 0 otherwise.

SHIFT (num, shift)

Returns a number shifted by the given number of bits. Negative shift means "shift left" and positive shift means "shift right". Both arguments should be integers, as will be the result, of course.

BIT (bit)

Returns a number with only the given bit set. There are 32 valid bits, numbered from 0 to 31. Going outside that range will wrap around.

tostring (arg)

Returns a string that represents the argument. You can use this if you want to get the same string that
print would print, but use it for some purpose other than immediate printing. This function is actually what gives print its ability to print tables and other non-string values. Note that there is currently a limit of 65536 characters per result, after which only a "..." is appended, but in typical use you shouldn't ever run into this limit.

For advanced Lua users that want to customize how strings are printed: Like any other function in Lua, you may assign your own function in place of tostring to override it, and in this case doing so will change the output of the print function as well. However, this implementation of tostring (and consequently print) will honor the __tostring metamethod, so it's better to use that mechanism instead of overriding the global tostring if you only want to customize how certain things are printed.


addressof (value)

Returns the pointer address of a reference-type value. In particular, this can be used on tables and functions to see what their addresses are. There's not much worth doing with a pointer address besides printing it to look at it and see that it's different from the address of something else. Please do not store the address to use for hashing or logical comparison, that is completely unnecessary in Lua because you can simply use the actual object instead of its address for those purposes. If the argument is not a reference type then this function will return 0.

copytable (original)

Returns a shallow copy of the given table. In other words, it gives you a different table that contains all of the same values as the original. This is unlike simple assignment of a table, which only copies a reference to the original table. You could write a Lua function that does what this function does, but it's such a common operation that it seems worth having a pre-defined function available to do it.

For reference, here is a Lua function that should have equivalent behavior:

copytable = function(t)
 if t == nil then return nil end
 local c = {}
 for k,v in pairs(t) do
  c[k] = v
 end
 setmetatable(c,debug.getmetatable(t))
 return c
end

Gens Library

General emulator-related functions are in the gens library.

gens.framecount ()

Returns the number of elapsed emulation frames.

gens.lagcount ()

Returns the number of emulation frames on which the system did not poll joypad input. Note that this number does NOT reset if the user presses the "reset lag count" hotkey.

gens.lagged ()

Returns true if the system did not poll joypad input during the previous frame, or false otherwise.

gens.emulating ()

Returns true if emulation has started, or false otherwise. Certain operations such as using savestates are invalid to attempt before emulation has started. You probably won't need to use this function unless you want to make your script extra-robust to being started too early.

gens.speedmode (mode)

Sets the speed mode used by subsequent calls to
gens.frameadvance.

mode can be one of the following:


gens.frameadvance ()

Emulates and renders one frame, with properties determined by the most recent call to
gens.speedmode.

Also handles OS events, allowing the user to do things like press a hotkey, access the menu, move the window, close the program, etc. before this function returns.

You may call this at almost any time, including from coroutines and most registered callback functions, but beware of recursion in the latter case because this function can trigger callback functions. Attempts to call this while not at a frame boundary will fail with a warning message that does not stop script execution. Attempts to call this before emulation has started will silently do nothing.


gens.pause ()

Pauses emulation and your script, and waits for the user to unpause it (by pressing a pause hotkey such as Esc or Pause) before continuing. This function acts immediately and is safe to call at any time, even inside memory hook callbacks.

gens.wait ()

Tells Gens to wait while your script continues on doing its processing. What this actually means is that it causes Gens to handle some OS events, allowing the program to feel more responsive than it otherwise would if you didn't ever call this during long calculations.

If your script goes for too long without calling either gens.wait or gens.frameadvance, then your script will become marked as <BUSY>, which means that Gens will occasionally automatically call gens.wait without your permission to keep at least some semblance of responsiveness. It's not the end of the world if your script dips into <BUSY> mode because you forget to call gens.wait while it's doing calculations, but keep in mind that it's similar to a Windows program that says "Not Responding" which is often an indication of sloppy programming. Don't worry about it too much though, especially if you're just writing little scripts for yourself you will probably never need to call gens.wait.


gens.redraw ()
or gui.redraw ()

Attempts to draw the current frame by immediately simulating a graphics processor update. This will not change the state of the emulation, although it will trigger any callbacks that have been registered by gui.register. If you want to update or animate a GUI drawn on top of the screen without advancing the emulation frame, then this may be the only way to do that. Note that the redrawn screen is not guaranteed to render exactly what the system would normally render, especially in games that change the palette at certain scanlines, but most of the time it is "close enough".

gens.message (msg)

Displays the given string (or
tostring(msg)) in the status region on the user's emulator screen, for some number of frames. Emulation should be running at normal speed if you want the user to actually see the message.

If you want control over things like where the message appears, what color it is, and how long it stays visible, then you should use the gui.text function instead of this.


gens.persistglobalvariables (variabletable)

Lets you define global variables that automatically have their values saved across restarts of the script.
gens.persistglobalvariables({
  mystring = "hello",
  mynumber = 42,
  mytable = {1,2,3},
  -- and so on
})
-- now you can use them like normal variables and they will be saved for you
You can pick whatever names and default values you want. The default values are only used the first time, after that each variable starts with the value it had the last time the script exited, even if you close and reopen Gens. However, for convenience, you can "reset" any variable simply by changing its default value.

As a special case, if you need the default value for a variable to be nil, then put the variable name alone in quotes as an entry in the table without saying "= nil". This special case is because tables in Lua don't store nil-valued entries.

Currently only the following types are supported: boolean, number, string, table, nil.


gens.registerbefore (func)

Registers a callback function to run immediately before each frame gets emulated. This runs after the next frame's input is known but before it's used, so this is your only chance to set the next frame's input using the next frame's would-be input. For example, if you want to make a script that filters or modifies ongoing user input, such as making the game think "left" is pressed whenever you press "right", you can do it easily with this.

Note that this is not quite the same as code that's placed before a call to gens.frameadvance. This callback runs a little later than that. Also, you cannot safely assume that this will only be called once per frame. Depending on the emulator's options, every frame may be simulated multiple times and your callback will be called once per simulation. If for some reason you need to use this callback to keep track of a stateful linear progression of things across frames then you may need to key your calculations to the results of gens.framecount.

Like other callback-registering functions provided by Gens, there is only one registered callback at a time per registering function per script. If you register two callbacks, the second one will replace the first, and the call to gens.registerbefore will return the old callback. You may register nil instead of a function to clear a previously-registered callback. If a script returns while it still has registered callbacks, Gens will keep it alive to call those callbacks when appropriate, until either the script is stopped by the user or all of the callbacks are de-registered.


gens.registerafter (func)

Registers a callback function to run immediately after each frame gets emulated. It runs at a similar time as (and slightly before)
gui.register callbacks, except unlike with gui.register it doesn't also get called again whenever the screen gets redrawn. Similar caveats as those mentioned in gens.registerbefore apply.

gens.registerexit (func)

Registers a callback function that runs when the script stops. Whether the script stops on its own or the user tells it to stop, or even if the script crashes or the user tries to close the emulator, Gens will try to run whatever Lua code you put in here first. So if you want to make sure some code runs that cleans up some external resources or saves your progress to a file or just says some last words, you could put it here. (Of course, a forceful termination of the application or a crash from inside the registered exit function will still prevent the code from running.)

Suppose you write a script that registers an exit function and then enters an infinite loop. If the user clicks "Stop" your script will be forcefully stopped, but then it will start running its exit function. If your exit function enters an infinite loop too, then the user will have to click "Stop" a second time to really stop your script. That would be annoying. So try to avoid doing too much inside the exit function.

Note that restarting a script counts as stopping it and then starting it again, so doing so (either by clicking "Restart" or by editing the script while it is running) will trigger the callback. Note also that returning from a script generally does NOT count as stopping (because your script is still running or waiting to run its callback functions and thus does not stop... see here for more information), even if the exit callback is the only one you have registered.


gens.registerstart (func)

Registers a function that runs once immediately if emulation has already started, and also runs again whenever the game is reset. A soft reset or movie playback will not cause the entire script to restart, so if you have some code that needs to run when the game starts in addition to when the script starts, then register it with this.

gens.atframeboundary ()

Returns true if Gens is at a frame boundary, or false otherwise. Certain operations such as advancing the frame or using savestates are invalid to attempt when not at a frame boundary. Generally Gens will always be at a frame boundary while your script has control and so you don't need to worry about checking this, except possibly in memory callback functions which usually get called while not at a frame boundary.

gens.emulateframe ()

Emulates and renders one frame, with properties similar to the "nothrottle" speed mode, but without handling OS events or allowing pauses.

Don't use this in place of gens.frameadvance or the emulator will become unresponsive (unless you also call gens.wait) and the user won't feel "in control" of the emulation (unless you add manual delays). An appropriate place to use this might be a short loop that automatically replays a small input macro, or if for some reason you want to prevent the user from pausing normally.


gens.emulateframefast ()

Emulates and renders one frame, with properties similar to the "turbo" speed mode, but without handling OS events or allowing pauses.

gens.emulateframeinvisible ()

Emulates and renders one frame, with properties similar to the "maximum" speed mode, but without handling OS events or allowing pauses. Also, it is safe to call this from inside a
gui.register'd function.

This acts as an extremely fast emulation update that also doesn't render any graphics or generate any sounds. If you load a savestate after calling this function, it should leave no trace of having been called, so you can do things like generate future emulation states every frame while the user continues to see and hear normal emulation. Note that non-GUI callbacks can still trigger during "invisible" emulation frames, though, and that saving/loading savestates every frame can be quite taxing on the CPU if you choose to do that.


gens.openscript (filename)

Opens a new script window and starts it running the given script file. If that file is already running in an existing window, then this function restarts that script instead of opening a new one.

You can use this to create a "hub script" that automates the process of opening multiple other scripts you want to use together. Note that there cannot be more than 16 script windows open simultaneously (although there is no reason this arbitrary limit couldn't be increased).


gens.loadrom ([filename])
or gens.openrom ([filename])

Loads a ROM or CD image from the given file location. If filename is omitted, the user will be asked to choose which file to load. Unlike when the user loads a ROM normally, this function does not restart any running scripts. It does trigger callbacks that have been registered with gens.registerstart, however.

If this function fails to load a ROM for whatever reason (user cancelled, file not found, etc.), it will throw an error.



Savestate Library

Functions for saving and loading the state of emulation are in the savestate library.

savestate.create ([location])

Creates a savestate object, but doesn't save anything in it yet. By default this creates an anonymous savestate object (allocated in memory) and returns it. However, if location is a number, this function will instead return a handle to the non-anonymous savestate file that has the given save slot number.

You may use and reuse the returned object many times, so normally you would only call this function at most a few times when your script is starting up. Savestates can eat a lot of memory so try not to make too many of them. Even if you're writing a bot that loads millions of savestates, you could probably get away with only creating 2 savestate objects for it to use to do that.

Note that non-anonymous savestate objects are actually represented by the savestate number alone, and they do not need to be created, so it's kind of pointless to use this function for anything except anonymous savestates.


savestate.save (location[, option])

Saves the current emulation state to the given location. location should be a savestate object that was returned by savestate.create.

To "play nice", a script should only use this function with anonymous savestates. Saving to numbered slots is fully supported, but doing so can clash with what the user was trying to use those save slots for, and it can clash with what other scripts might try to use those same slots for, and nothing cleans them up when you're done with them, and it's slower than saving to (recycled) anonymous savestates. That being said, you are allowed to use slot numbers outside of the normal 0 to 9 range (including negative numbers) and you may pass a number directly into this function without calling savestate.create first.

option is an optional string that modifies how the save is done:


savestate.load (location[, option])

Loads an emulation state from the given location. location should be a savestate object that was returned by savestate.create that has also already been saved to with savestate.save, or (this is not required) for non-anonymous savestates it is allowed to be an integer save slot number instead.

option is an optional string that modifies how the load is done:


savestate.registersave (func[, savekey])

Registers a function to get called whenever the emulation state is saved to any numbered save slot (either by the user or by a script). In addition, whatever your callback function returns will get saved alongside the savestate file, so you can use this to effectively save extra data of your choosing with each savestate the user saves.

Currently the following types are allowed to be saved (returned by your callback): boolean, number, string, table, nil. If your callback returns multiple values they will all be saved, although you don't technically need to use this because you could also put them all inside a table and return that as a single value.

The callback function func will receive the save slot number as an argument when it is called, although you can make the callback take no arguments if you don't care what number slot it is.

savekey is used to associate your returned data with the current script, so that other scripts don't accidentally get your data or vise-versa. The default value is the filename of the current script file, which normally is good enough. But if it bothers you that changing the filename of your script will cause it to be unable to load data it has previously saved, or if you think you'll need to run scripts that are different but have the same filename as each other, then you can supply your own unique string for savekey. (Note that you can still only register one callback at a time per script with savestate.registersave, after which you will displace the previous callback.)


savestate.registerload (func[, loadkey])

Registers a function to get called whenever the emulation state is loaded from any numbered save slot (either by the user or by a script).

The callback function func will receive the save slot number as its first argument when it is called. It will also receive as additional arguments whatever data was returned by a callback registered by savestate.registersave when the state being loaded was last saved. If you don't need to use that data now then don't define your load callback with any additional arguments.

Normally you don't need to supply a loadkey, but if you are using a custom savekey with savestate.registersave then you should pass the same string into loadkey as well (unless you're doing something really unusual like spying on the data saved by a different script...)


savestate.savescriptdata (location)

Calls any registered save callbacks and saves the return values alongside the savestate that's at the given location. location should be a save slot number.

This is equivalent to calling savestate.save(location, "scriptdataonly").


savestate.loadscriptdata (location)

Returns the data associated with the given savestate (data that was earlier returned by a registered save callback) without actually loading the rest of that savestate or calling any callbacks. location should be a save slot number.

This is not equivalent to calling savestate.load(location, "scriptdataonly"), which passes the data into registered load callbacks rather than returning it.



Memory Library

Functions for accessing and editing the emulated system's memory are in the memory library.

Addresses

Most of the memory functions take an integer argument called address. A typical address looks like this: 0xFFD010. The address refers to a specific location in the Genesis's memory. Here is a map of the memory as recognized by the memory functions: The above addresses generally correspond with the main68k's view of memory, which is the default view. Support for alternate views of the memory (such as the sub68k CPU for SegaCD games) is currently limited, and is only supported for functions that take a cpuname argument.

The unit scale of an address is always 1 byte. For example, 0xFF0003 is exactly 1 byte away from 0xFF0002.


memory.readbyte (address)
or memory.readbyteunsigned (address)

Reads 1 byte of memory and returns the result as an integer between 0 and 255.

memory.readbytesigned (address)

Reads 1 byte of memory and returns the result as an integer between -128 and 127.
(0 to 127 stay the same as memory.readbyte would return, but [128 to 255] shifts to [-128 to -1].)

memory.readword (address)
or memory.readwordunsigned (address)
or memory.readshort (address)
or memory.readshortunsigned (address)

Reads 2 bytes of memory (big-endian) and returns the result as an integer between 0 and 65535.

memory.readwordsigned (address)
or memory.readshortsigned (address)

Reads 2 bytes of memory (big-endian) and returns the result as an integer between -32768 and 32767.

memory.readdword (address)
or memory.readdwordunsigned (address)
or memory.readlong (address)
or memory.readlongunsigned (address)

Reads 4 bytes of memory (big-endian) and returns the result as an integer between 0 and 4294967295.

memory.readdwordsigned (address)
or memory.readlongsigned (address)

Reads 4 bytes of memory (big-endian) and returns the result as an integer between -2147483648 and 2147483647.

memory.readbyterange (address, size)

Reads size bytes of memory and returns the result as an array of integers that are each between 0 and 255, or nil for any bytes in the range you specified that are at
invalid addresses. Recall that arrays in Lua are tables that have integer keys (indices) starting at 1.

memory.writebyte (address, value)

Writes 1 byte of memory to the given address, placing the lowest byte of the given integer value there. Any attempts to write to ROM will be ignored, however. There is no need for "signed" variations of any of the memory.write functions, since you can use a value that has whatever sign you want.

memory.writeword (address, value)
or memory.writeshort (address, value)

Writes 2 bytes of memory (big-endian) to the given address, placing the lowest 2 bytes of the given integer value there. Any attempts to write to ROM will be ignored, however.

memory.writedword (address, value)
or memory.writelong (address, value)

Writes 4 bytes of memory (big-endian) to the given address, placing the lowest 4 bytes of the given integer value there. Any attempts to write to ROM will be ignored, however.

memory.register (address, [size,] [cpuname,] func)
or memory.registerwrite (address, [size,] [cpuname,] func)

Registers a function to be called immediately whenever the given memory address range is written to (either by the emulation or by a memory.write function).

size is the number of bytes to "watch". For example, if size is 100 and address is 0xFF0000, then you will register the function across all 100 bytes from 0xFF0000 to 0xFF0063. A write to any of those bytes will trigger the function. Having callbacks on a large range of memory addresses can be expensive, so try to use the smallest range that's necessary for whatever it is you're trying to do. If you don't specify any size then it defaults to 1.

The callback function will receive two arguments, (address, size) indicating what write operation triggered the callback. If you don't care about that extra information then you can ignore it and define your callback function to not take any arguments. The value that was written is NOT passed into the callback function, but you can easily use any of the memory.read functions to retrieve it.

You may use a memory.write function from inside the callback to change the value that just got written. However, keep in mind that doing so will trigger your callback again, so you must have a "base case" such as checking to make sure that the value is not already what you want it to be before writing it. Another, more drastic option is to de-register the current callback before performing the write.

If func is nil that means to de-register any memory write callbacks that the current script has already registered on the given range of bytes.

Normally you won't need to provide the cpuname argument. It defaults to "main" which indicates the main68k's view of memory. You can specify "sub" or "s68k" to refer to the sub68k's address space, but keep in mind that support for this elsewhere in the memory library is currently limited or nonexistent so it will be difficult to accomplish much using the sub68k view.

A single memory operation will trigger no more than one registered memory callback per script. For example, if a game writes 4 bytes with a single assembly instruction and you have a callback on more than one of those bytes, only the one on the lowest address will be called. Usually this won't be a problem.


memory.registerread (address, [size,] [cpuname,] func)

Registers a function to be called immediately whenever the given memory address range is read by the emulation.

Besides that, most of the information about memory.register applies to this function as well.


memory.registerexec (address, [size,] [cpuname,] func)
or memory.registerexecute (address, [size,] [cpuname,] func)
or memory.registerrun (address, [size,] [cpuname,] func)

Registers a function to be called immediately whenever the emulated system runs code located in the given memory address range.

The Genesis can run code directly from ROM, but it can also run code that is in RAM as well. You can specify either ROM or RAM locations depending on what your address is. Typically, RAM starts at 0xFF0000 and ROM starts at 0, but especially on the Sega CD the majority of running code may not be near either of those addresses.

Besides that, most of the information about memory.register applies to this function as well.


memory.isvalid (address)

Returns true if the byte at the given address is in a range of memory
recognized as valid by the memory library, or returns false otherwise.

memory.getregister (cpuregistername)

Returns the current value of the given hardware register.
For example, memory.getregister("pc") will return the main CPU's current Program Counter.

Valid registers are: "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "pc", and "sr".

You can prefix the string with "sub." or "s68k." to retrieve registers from the sub68k CPU instead of the main68k, or you can explicitly use "main." or "m68k." if you want. For example, memory.getregister("sub.a0") will return the value stored in the sub CPU's first Address Register.


memory.setregister (cpuregistername, value)

Sets the current value of the given hardware register.
For example, memory.setregister("pc",0x200) will change the main CPU's current Program Counter to 0x200.

Valid registers are: "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "pc", and "sr".

You can prefix the string with "sub." or "s68k." to set registers on the sub68k CPU instead of the main68k, or you can explicitly use "main." or "m68k." if you want.

You had better know exactly what you're doing or you're probably just going to crash the game if you try to use this function. That applies to the other memory.write functions as well, but to a lesser extent.



GUI Library

Functions mainly for drawing on the screen are in the gui library.

Coordinates

For GUI functions that use x and y coordinates, x is a number that increases from 0 at the left side of the screen to 319 at the right side of the screen, and y is a number that increases from 0 at the top of the screen to 223 at the bottom of the screen. (The Genesis can switch to other output resolutions, but they are much less common and are not yet well-supported by the GUI library.) You are allowed to specify offscreen coordinates, and doing so will not cause errors.

Colors

Although the Genesis outputs 16-bit color, the Gens GUI library uses full 32-bit RGBA color to give you greater flexibility. 32-bit RGBA means there are four color channels (red, green, blue, and alpha) each with values between 0 and 255. Many of the GUI functions take one or two color arguments, and you have several options for specifying what color you want: The red, green, and blue values determine the color's brightness (0=empty, 255=full), and the alpha value determines the color's transparency (0=invisible, 255=solid).

The following preset color names are recognized: 'white', 'black', 'clear', 'gray', 'grey', 'red', 'orange', 'yellow', 'chartreuse', 'green', 'teal', 'cyan', 'blue', 'purple', 'magenta'. Obviously, if you want a color that isn't one of those (or if you want some control over the transparency you draw colors at), you'll have to use one of the other, non-preset color representations. Also, note that 'clear' does not mean "erase" or "undo" (there is no such color that does that), it simply means "invisible".

If you choose to use one of the RGB[A] array/table color representations, beware that there is a hidden cost: Lua is not smart enough to automatically "recycle" temporary tables, so if you create colors with Lua's built-in {} operator every time, it will cause extreme slowdown if you do that too many hundreds of times per frame. You can work around this by recycling color tables yourself, although it may be easier to simply use the "RGBA number" representation instead which is the fastest one and will definitely never give you any performance problems. But...

If you use the "RGBA number" representation, keep in mind that unlike the other representations you must supply the alpha value as part of the number. For example, solid yellow is 0xFFFF00FF, but if you use 0xFFFF00 instead it will not work.

For RGBA numbers, you may find the bitwise "operators" such as OR and AND are useful for combining components of colors that are stored in numbers. For example, OR(color,0xFF) returns a completely opaque version color, and OR(AND(color,0xFFFFFF00),AND(color,0xFF)/2) returns a version of color that is twice as transparent as the original.


gui.register (func)

Registers a callback function to get called whenever the screen is drawn.

It is recommended that you make this callback the only place that you call GUI drawing functions (such as gui.text) from, otherwise they will execute 1 frame late and also run slower.


gui.getpixel (x, y)
or gui.readpixel (x, y)

Returns the RGB color at the given onscreen pixel location. You can say local r,g,b = gui.getpixel(x,y). r,g,b are the red/green/blue color components of that pixel, each ranging from 0 to 255. If the coordinate you give is offscreen, you will receive the color values of the nearest onscreen pixel instead.

Note that this function can return colors that have already been written to the screen by GUI drawing functions. If for some reason you want to make sure that you only get the clean untampered-with colors the emulation drew onscreen, then you'll have to call this function before any GUI drawing functions have written to the screen for the current frame. Probably the most reliable way to do that is to call gui.getpixel inside of a callback function that you register with gens.registerafter.


gui.text (x, y, str [, color [, outlinecolor]])
or gui.drawtext (x, y, str [, color [, outlinecolor]])

Displays the given string (or tostring(str)) at the given coordinate of the emulator screen for one frame. The x,y coordinate specifies the top-left corner of where the text should go, but the text may be shifted somewhat from there to ensure it fits onscreen. The string is allowed to contain newlines (which should function as you'd expect), and very long strings will automatically wrap around as well.

The default color for the text is solid white with a solid black outline, but you may optionally override those using colors of your choice (including separate transparency levels for the two if you wish).


gui.box (x1, y1, x2, y2 [, fillcolor [, outlinecolor]])
or gui.drawbox (x1, y1, x2, y2 [, fillcolor [, outlinecolor]])
or gui.rect (x1, y1, x2, y2 [, fillcolor [, outlinecolor]])
or gui.drawrect (x1, y1, x2, y2 [, fillcolor [, outlinecolor]])

Draws a rectangle between the given coordinates of the emulator screen for one frame. The x1,y1 coordinate specifies any corner of the rectangle (preferably the top-left corner), and the x2,y2 coordinate specifies the opposite corner.

The default color for the box is transparent white with a solid white outline, but you may optionally override those using colors of your choice. In addition, you may supply a color transformation function (which takes r,g,b numbers as input and returns a new r,g,b as output) instead of a color for either or both of the colors. This can be used to achieve special blending modes such as additive or subtractive blending or inversion of a large region of pixels. See the "blendmodes.lua" sample for a working example.


gui.line (x1, y1, x2, y2 [, color [, skipfirst]])
or gui.drawline (x1, y1, x2, y2 [, color [, skipfirst]])

Draws a line segment between the given coordinates of the emulator screen for one frame. The x1,y1 coordinate specifies one end of the line segment, and the x2,y2 coordinate specifies the other end. If skipfirst is true then this function will not draw anything at the pixel x1,y1, otherwise it will. skipfirst is optional and defaults to false. The default color for the line is solid white, but you may optionally override that using a color of your choice.

gui.pixel (x, y [, color])
or gui.setpixel (x, y [, color])
or gui.drawpixel (x, y [, color])
or gui.writepixel (x, y [, color])

Draws a single pixel at the given x,y coordinate of the emulator screen for one frame. The default color is solid white, but you may optionally override that using a color of your choice.

gui.parsecolor (color)

Returns the separate RGBA components of the given color.
For example, you can say local r,g,b,a = gui.parsecolor('orange') to retrieve the red/green/blue values of the
preset color orange. (You could also omit the a in cases like this.) This uses the same conversion method that Gens uses internally to support the different representations of colors that the GUI library uses. Overriding this function will not change how Gens interprets color values, however.

gui.opacity (alpha)

Scales the transparency of subsequent draw calls. An alpha of 0.0 means completely transparent, and an alpha of 1.0 means completely unchanged (opaque). Non-integer values are supported and meaningful, as are values greater than 1.0. It is not necessary to use this function (or the less-recommended gui.transparency) to perform drawing with transparency, because you can provide an alpha value in the color argument of each draw call. However, it can sometimes be convenient to be able to globally modify the drawing transparency.

gui.transparency (trans)

Scales the transparency of subsequent draw calls. Exactly the same as
gui.opacity, except the range is different: A trans of 4.0 means completely transparent, and a trans of 0.0 means completely unchanged (opaque).

gui.popup (msg [, type [, icon]])
or input.popup (msg [, type [, icon]])

Brings up a modal popup dialog box (everything stops until the user dismisses it). The box displays the message tostring(msg). This function returns the name of the button the user clicked on (as a string).

type determines which buttons are on the dialog box, and it can be one of the following: 'ok', 'yesno', 'yesnocancel', 'okcancel', 'abortretryignore'.
type defaults to 'ok' for gui.popup, or to 'yesno' for input.popup.

icon indicates the purpose of the dialog box (or more specifically it dictates which title and icon is displayed in the box), and it can be one of the following: 'message', 'question', 'warning', 'error'.
icon defaults to 'message' for gui.popup, or to 'question' for input.popup.

Try to avoid using this function much if at all, because modal dialog boxes can be irritating.


gui.gdscreenshot ()

Takes a screenshot of the current screen and returns it in a string format that can be used by
gd.

Here is an example that takes a screenshot, creates a gd image from it, and saves it out to a PNG file on the hard drive:
local gdstr = gui.gdscreenshot()
gd.createFromGdStr(gdstr):png("outputimage.png")


gui.gdoverlay ([x, y,] gdimage[, alphamul])
or gui.drawimage ([x, y,] gdimage[, alphamul])
or gui.image ([x, y,] gdimage[, alphamul])

Draws an image on the screen. gdimage must be in truecolor gd string format.

Transparency is fully supported. Also, if alphamul is specified then it will modulate the transparency of the image even if it's originally fully opaque. (alphamul=1.0 is normal, alphamul=0.5 is doubly transparent, alphamul=3.0 is triply opaque, etc.)

x,y determines the top-left corner of where the image should draw. If they are omitted, the image will draw starting at the top-left corner of the screen.

gui.gdoverlay is an actual drawing function (like gui.box and friends) and thus must be called every frame, preferably inside a gui.register'd function, if you want it to appear as a persistent image onscreen.

Here is an example that loads a PNG from file, converts it to gd string format, and draws it once on the screen:
local gdstr = gd.createFromPng("myimage.png"):gdStr()
gui.gdoverlay(gdstr)


What is gd and how can I install it?

GD is a library for image manipulation. The library you can use in Gens with Lua is more specifically called
Lua-GD. With it you can do things like load an image file (which Gens can then draw on the screen), convert between image formats, save image files, or perform relatively advanced drawing operations on images. You can read more about it at its home page.

Listed here are the steps I followed to install Lua-GD for Win32. They worked for me, but they might not exactly match up with your environment, so I'd suggest following the official installation instructions if these don't help:

  1. I downloaded a package called lua-gd-2.0.33r2-win32 at the one of the Lua-GD download pages, and extracted it.
  2. I copied gd.dll to where my Gens .exe was located.
  3. I copied freetype6.dll, jpeg62.dll, libgd2.dll, libiconv2.dll, libpng13.dll, xpm4.dll, and zlib1.dll to C:\WINDOWS\system32
  4. I downloaded a package called lua5_1_4_Win32_bin at the Lua Binaries download page, and extracted it.
  5. I copied both lua51.dll and lua5.1.dll to C:\WINDOWS\system32
After that I was able to use gd in any Lua script simply by putting the following code at the top:
require "gd"

It is not necessary to install or use GD. Gens Lua does not use it directly for anything, not even for gui.gdscreenshot or gui.gdoverlay. And it is possible to do anything that GD does without using GD. It is a convenient library, however.



Joypad Library

Functions for examining or changing the controller input that can be received by the emulation are in the joypad library.

joypad.get ([whichcontroller])
or joypad.read ([whichcontroller])

Returns a table of every game button, where each entry is true if that button is currently held (as of the last time the emulation checked), or false if it is not held. If a movie is playing, this will read the input actually being received from the movie instead of what the user is pressing. By default this only checks controller 1's input, but the optional whichcontroller argument lets you choose (valid choices are 1, 2, '1B' (or 0x1B), or '1C' (or 0x1C)).

For example, joypad.get() might return the table {up=false, down=false, left=false, right=true, A=true, B=false, C=false, start=false, X=false, Y=false, Z=false, mode=false}, meaning that player 1's last input sent to the game had the A and Right buttons held and everything else unheld.

You could check whether a particular button is held like so:
local buttons = joypad.get()
if buttons.B then print("the B button is held!") end


joypad.getdown ([whichcontroller])
or joypad.readdown ([whichcontroller])

Returns a table of only the game buttons that are currently held. Each entry is true if that button is currently held (as of the last time the emulation checked), or nil if it is not held. If a movie is playing, this will read the input actually being received from the movie instead of what the user is pressing. By default this only checks controller 1's input, but the optional whichcontroller argument lets you choose (valid choices are 1, 2, '1B', or '1C').

For example, joypad.getdown() might return the table {right=true, A=true}, meaning that player 1's last input sent to the game had the A and Right buttons held and everything else unheld.


joypad.getup ([whichcontroller])
or joypad.readup ([whichcontroller])

Returns a table of only the game buttons that are not currently held. Each entry is nil if that button is currently held (as of the last time the emulation checked), or false if it is not held. If a movie is playing, this will read the input actually being received from the movie instead of what the user is pressing. By default this only checks controller 1's input, but the optional whichcontroller argument lets you choose (valid choices are 1, 2, '1B', or '1C').

For example, joypad.getup() might return the table {up=false, down=false, left=false, B=false, C=false, start=false, X=false, Y=false, Z=false, mode=false}, meaning that player 1's last input sent to the game had the A and Right buttons held and everything else unheld.


joypad.peek ([whichcontroller])

Same as
joypad.get except it checks the buttons that are currently being held by the user instead of the buttons that were last received by the game. In other words, this is an asynchronous version of joypad.get, and if a movie is playing, this will ignore the movie's input and look at what the user is trying to press instead.

joypad.peekdown ([whichcontroller])

Same as
joypad.getdown except it checks the buttons that are currently being held by the user instead of the buttons that were last received by the game. In other words, this is an asynchronous version of joypad.getdown, and if a movie is playing, this will ignore the movie's input and look at what the user is trying to press instead.

joypad.peekup ([whichcontroller])

Same as
joypad.getup except it checks the buttons that are currently being held by the user instead of the buttons that were last received by the game. In other words, this is an asynchronous version of joypad.getup, and if a movie is playing, this will ignore the movie's input and look at what the user is trying to press instead.

joypad.set ([whichcontroller,] input)
or joypad.write ([whichcontroller,] input)

Modifies the input that the next frame of emulation receives. input must be a table of zero or more buttons (valid buttons are up, down, left, right, A, B, C, start, X, Y, Z, mode) each with values of true, false, or nil.

A value of true means "force this button to be held next frame". A value of false means "force this button to be unheld next frame". A value of nil (or no entry for the button) means "don't modify this button next frame, let it be whatever it would have been normally".

A consequence of this is that you can call joypad.set multiple times to piece together the next frame's input. For example:
joypad.set({A=true})
joypad.set({B=true, up=false})
Running the above code would force the player to press both A and B on the next frame, prevent the player from pressing Up on the next frame, and the other buttons like Left and Right are the user's choice to press or not press (they would be unheld on the next frame unless the user presses them in which case they would be held).

For just one example of how it might be useful to leave buttons nil, consider a script that calls joypad.set each frame to make the player jump in a certain pattern (i.e. a custom macro). If you make the macro only control the jump button, that leaves you free to press the other buttons yourself, so you can do things like guide your character left/right while the macro is handling the jump height and timing. This sort of "partial automation" can be handy, so don't override more buttons than you need to.

By default this function only sets controller 1's input, but the optional whichcontroller argument lets you choose (valid choices are 1, 2, '1B' (or 0x1B), or '1C' (or 0x1C)). Also, if an input movie is currently playing then this function will not do anything. It will work fine if a movie is recording, of course, but not if it's playing.



Input Library

Functions for getting non-game-controller user input are in the input library.

input.get ()
or input.read ()

Returns a table that represents the state of the mouse and keyboard.

Entries for the mouse are:

xmouse and ymouse will always be numbers in the returned table (never nil). If the cursor is not positioned in the emulator screen then these numbers will be outside of the normal range, for example they will be negative if the cursor is past the top-left corner of the emulator screen.

Entries for the keyboard each represent a key and can be true if the key is held or nil otherwise. Possible keyboard entries are:

It's generally somewhat bad practice to check keyboard keys at all because any user could easily have configured those keys to do some other more important emulator functions. However, it's still useful: Sometimes you just want to check an extra button quickly, for example if you're testing something or if you're writing a little throw-away script and you know it. On the other side of the spectrum, although it seems unlikely for anyone to bother doing this, it would be possible to write a script that checks specific keys but also provides its own key configuration mechanism to prevent it from clashing with the user's other keys.


input.registerhotkey (which, func)

Registers a callback function to run when a certain hotkey is pressed. which is the hotkey number, and currently must be a number between 1 and 16. This range corresponds with the user-configurable hotkeys "Lua Custom Hotkey 1" through "Lua Custom Hotkey 16", which will do nothing when pressed except trigger the aforementioned callback. These hotkeys must be configured by the user in the input settings beforehand.

The only real advantage this has over other methods of checking input is that it works even if Gens is paused. There is no alternative way of allowing user-controlled activation of script code during a pause except for making Gens enter into a fake pause instead of really pausing. (Although, depending on the situation, a fake pause might be the better option.)



Movie Library

Functions for dealing with recorded input movies are in the movie library.

movie.active ()

Returns true if any movie file is open, or false otherwise.

movie.recording ()

Returns true if a movie file is currently recording, or false otherwise.

movie.playing ()

Returns true if a movie file is currently playing, or false otherwise.

movie.mode ()

Returns one of the following:

movie.length ()

Returns the total number of frames in the current movie.

movie.name ()
or movie.getname ()

Returns a string containing the full filename (path) of the current movie file.

movie.rerecordcount ()

Returns the count of re-records that is stored in the current movie file.

movie.setrerecordcount (number)

Sets the re-record count of the current movie file to the given number.

movie.rerecordcounting ([enabled])

If enabled is false, this causes
savestate.load to never increment the re-record count. If enabled is true (or otherwise non-nil), this causes savestate.load to increment the re-record count when loading numbered savestates only (the default behavior). If enabled is not provided, this returns the current re-record counting setting (true if enabled, false otherwise) instead of changing it.

movie.readonly ()
or movie.getreadonly ()

Returns true if the current movie is in read-only mode (which means that loading a savestate would switch to playback), or returns false if the current movie is in non-read-only mode (which means that loading a savestate would switch to recording).

movie.setreadonly (readonly)

Sets the current movie's read-only state. This does not change the movie's mode between recording and playback or vice-versa, but it will determine which of those to switch to the next time a savestate is loaded (either by the user or by script code).

If the currently-loaded movie is actually a read-only file on disk (which is always the case if the movie file is still compressed in a zip archive) then calling this function can throw an error.


movie.framecount ()

Same as
gens.framecount. Returns the number of elapsed emulation frames. This actually has nothing to do with movies and will return a valid number even if there is no movie playing. (In the future there might be some difference between the two functions if a from-savestate movie is playing, but currently they are exactly identical.)

movie.play ([filename])
or movie.open ([filename])
or movie.playback ([filename])

Starts playing a movie file. If filename is not provided, the user will be prompted to choose which file to load from a dialog, otherwise the given movie file will be loaded. The movie is loaded in read-only mode (if you want to change that then simply call movie.setreadonly(false) afterward).

If this function fails to play a movie for whatever reason (user cancelled, file not found, etc.), this will throw an error with a description of why the movie couldn't be played.


movie.replay ()

Starts playing the currently open movie file from the first frame. This switches to playback if necessary but does not change the read-only mode. If there is no movie
currently loaded, this function will throw an error.

movie.stop ()
or movie.close ()

Stops and unloads the currently active movie. If no movie is open then this function does nothing.


Sound Library

Functions for doing audio-related things are in the sound library. Presumably things like recording channels of sound or mixing in your own sound effects or changing the CD track would go here, but currently this library is a little on the skimpy side.

sound.clear ()

Clears the sound buffer (instantaneous silence). If you ever notice the sound looping annoyingly when you do some lengthy operation, you can call sound.clear beforehand to fix it. You could also call this every frame during a certain range of frames to "blank out" audio that annoys you.