Update: this is a basic discussion. See here for a straight list of complete jobs.
For nearly a month now I've been caught up in developing hitbox viewer Lua scripts. These show the hitboxes superimposed on the characters while the game is running.
Hitbox calculations are the mechanism by which a 2D game determines whether an attack connects or misses. The characters have invisible rectangles over their sprites that, when overlapped by the rectangles of an opponent's attack, cause the character to get hit. These are respectively known as vulnerability and attack boxes. A third type is the exclusion or push box, which can never overlap with another exclusion box. This prevents characters from occupying the same space.
Generally characters have multiple vulnerability boxes to better conform to the shape of the sprite, and only one push box and attack box at a time. Attack boxes only appear during the active frames of attacks. By convention, vulnerability boxes are shown in blue, attack boxes in red, and pushboxes in green.
Seeing how the boxes are laid out is of some value to combo video types. However, it's more useful to players who need to know what button to push in any given situation, or who don't understand why nothing seems to work against a certain attack. Plus, it's interesting just to see what the developers were thinking when they programmed the game.
Hitboxes are difficult to reveal because it's not simply a matter of finding the right memory addresses with a memsearch tool. Each box is defined by offsets from the character's position and by width and height dimensions. These parameters get read from ROM, which never changes, so memsearch alone is not enough to determine them. Instead, you have to find the address that says where to read. As it turns out, you typically start at a known address and read its value as an address to another value, and multiple values have to be pieced together in this way to get to the final address. At every step of the process you have to know exactly what is going on.
This is where the debugger comes in. MAME comes with a debugging tool that can keep track of every action that the emulated machine performs. These actions are known as instructions. The set of available instructions, known as the machine code or assembly language, depends on the processor of the emulated machine. The CPS-2, along with the NeoGeo, the Sega Genesis and many other systems, uses an M68000 processor. The debugger can follow the emulation instruction by instruction or you can run a trace, during which all instructions are dumped to a log file for later study.
Just a few frames of emulation can run thousands of instructions. If you know a relevant RAM address, such as a character's amount of vitality or animation frame, you can set a watchpoint there, which causes emulation to pause when that address is read from or written to. A breakpoint performs the same function, but for a ROM address instead. Starting a trace a couple frames before the event of interest and stopping it at a watchpoint narrows down the code to be analyzed. Then, starting at the end of the trace dump, where the variable was changed, you can read backwards until you reach the instruction that draws the hitboxes from ROM. This is very powerful. Unlike empirical approaches, you can obtain any information about how the game works with complete certainty. The drawback is the effort required in learning the assembly, and the difficulty of following the logic of the code in reverse.
Actually, I was too stupid/lazy to get far with debugger traces. Instead I've been using the memory browser built in to the debugger. It was felinkei and mz who did the seminal work in reverse engineering the hitbox code and converting it to Lua. The first games were Vampire Savior and Street Fighter Alpha 2 and 3. What I did was modularize the scripts so they work with many games, and added the other CPS-2 games and the Street Fighter II series. I did this by studying them in the memory browser and looking for similarities to the known games, making adjustments as necessary.
What they all have in common is that every frame of animation has characteristic hitbox IDs for each of the game's hitbox types. A character's idle animation frames typically have head, torso, and leg vulnerability boxes with ID 1, a pushbox with ID 1, and an attack box with ID 0. The placement and size of the boxes depend on those IDs, with ID 0 always denoting no box. Even though there are many frames in the idle stance and they change constantly, they all have the same IDs, so the character is effectively not moving. (When I speak of an animation frame, I'm talking about the sprite being displayed, not a measure of time.)
Projectiles are considered independent objects from the characters, and their hitboxes work the same way as with characters, mostly. The key differences are that there can be many of them at once, and they can wink into and out of existence, so some code was required to determine which ones should be drawn. Every game has a different maximum number of projectiles. The vulnerability or exclusion box of a projectile has a special function: when hit by the attack box of another, the projectiles negate one another. Projectiles with only an attack box cannot negate or be negated by others.
In the next series of articles I will discuss the hitbox systems of the various games I've covered.
This is unrelated but Your third strike lua script does not show offensive hitboxes, only defensive ones.
Any advice? Is the script just made for a specific third strike version
Posted by: CWheezy | 01/19/2011 at 09:33 PM
I didn't write that one. It was developed by LennethEX as part of his mameserver project:
http://code.google.com/p/mameserver/
mz was kind enough to translate the hitbox display from the source code of mameserver to Lua, but I haven't gotten around to working with it yet. I've been putting it off because I want to get mame-rr improved, at least a 64 bit build for more speed.
I'm pretty sure I'll be able to get it working like the other hitbox lua scripts, and make it work for all the CPS3 games too.
Posted by: dammit | 01/20/2011 at 12:22 AM
I think it only shows offensive hitboxes in MAME.
I have no idea why it doesn't work correctly in FBA...
Posted by: mz | 01/20/2011 at 12:17 PM
OK thanks, keep up the good work on your blog, it is always interesting reading this stuff
Posted by: CWheezy | 01/21/2011 at 03:29 PM
Yeah, it seems to be missing all of them, not just projectiles...
It might be hard to diagnose/fix the problem, with no debugger in FBA.
Posted by: dammit | 01/24/2011 at 01:40 AM
Seems FBA-rr (LUA implementation) can't read/access beyond 0x04000000.
Active hitboxes are beyond 0x06000000...
Same thing for RAM search tool.
Posted by: ESN | 05/09/2011 at 05:49 AM
So Lua and RAM search just don't reach far enough, that's why the 3S boxes don't work in FBA?
At least there's not some weird emulation difference, which is what I thought at first.
Posted by: dammit | 05/09/2011 at 11:14 PM