Syndrome is a level editor for the Mega Man 7 SNES game. Syndrome has undergone 2 complete rewrites since the project began (three iterations in all). The most recent rewrite makes it platform independent, with main development taking place mostly on Mac OS X.
Work on Syndrome began on September 25, 2002 as a Visual Studio 6 MFC project. The screenshots below depict two different builds of the interface. On the left, an older version showing the first time a complete screen was rendered. On the right, a newer version with some tile issues fixed (also with transparency rendered in pink) and an empty sidebar added (once planned to become a toolbox):
On May 23, 2004, I decided to drop MFC (and C++, for that matter) and entirely rewrote the program in C for MinGW. This iteration saw a completely new interface, using an MDI layout and resizable windows. A console window was also included which would output debug information:
Syndrome source code is available on hgkw: . You can also clone the Mercurial repository with the following command:
$ hg clone http://hg.kodewerx.org/syndrome
The current source tree is a minimal implementation of a XULRunner application; the XUL, CSS, and JS sources are available in the /src subdirectory, and two shell scripts are included for launching the application.
The linux shell script requires XULRunner to be installed and available in your PATH. If you are on a recent version of Ubuntu, you already have everything needed to try it out:
The Mac OS X shell script will build an application bundle and place it into a new /Applications/Kodewerx directory. Then it will run the application. To use this, you must download a recent copy of the XULRunner runtime. At this time, the most current release is version 126.96.36.199:
For Windows, just double click the "syndrome-win" shortcut. You must have Firefox 3.0 (or newer) installed in the default location (C:\Program Files\Mozilla Firefox) for the shortcut to work. If you have Firefox installed to a different location, you can change the shortcut to point to the firefox.exe file by right clicking the shortcut and choosing "Properties".
I am often asked why the editor is called Syndrome; the name isn't typical of ROM hacking tools. The word 'syndrome' itself does not directly relate to Mega Man 7 or the Mega Man series in any way. The main reason for this is just to be different! But that doesn't explain where the name came from.
I'm not a big fan of the Mega Man series, to be entirely honest. (Writing an editor for this game was a suggestion that I took one day when bored and feeling an intense urge to build an editor.) I'm not familiar with many of the characters in the series, even; however, I knew that there was a character ... somewhere ... named Sigma. Sigma is a nice name. Almost as fancy as Epsilon. But that's another story.
The words 'sigma' and 'syndrome' (in my head, at least) have a very synesthetic feeling about them. Such that when I hear 'sigma' in my head, I also heard 'syndrome'. And that's the ultimately boring story about how the project came to be known as Syndrome!
The Reasoning Behind XULRunner
XULRunner is a nice platform; especially for people who are already familiar with doing web application programming. It's easy for web developers to pick up a XULRunner app and modify it to fit their needs. However, it's not very easy for a web developer to start a XULRunner application from scratch -- that's what XULRunner developers are for.
Briefly, I chose XULRunner as my cross platform framework because I wanted to avoid A) non-native looking widgets (rules out GTK+) and B) C++ (rules out wxWidgets and a whole lot of other similar toolkits). On top of that, I realized the potential of the XULRunner platform in Firefox (extensions, themes, internationalization, accessibility, ...) and I feel that Syndrome can benefit from these technologies.
Mega Man 7 Information
Syndrome is hard-coded to read data out of the US Mega Man 7 ROM. Other regions probably will not work. The first thing it does after opening the ROM file is detecting the ROM mapping mode. (This is part of the 'general utilities' described above!) Mega Man 7 is strictly a HiROM-mapped SNES ROM; but Syndrome does not care. It will detect the mapping mode anyway. This makes the ROM reading class general purpose. (This class also handles SMC format ROMs with or without the SMC header -- another win for modularity.)
The next thing Syndrome does is read the ROM title from the header, but in its current state it will not verify this information (currently used for debugging only).
Finally, it begins to "build" the first stage. This is a convoluted process (due to compression) which ends up with a very large HTML canvas (4864 x 1536 px) and a very basic SNES video mode buffer. The video mode buffer is a collection of: tiles, palettes, tile maps. These buffers are the same format as used by SNES.
The compression algorithm used on tiles is an LZSS derivative. It may also be used on other kinds of data.
Another intermediate form of compression used is often referred to as "Tile Squaroid Assembler" ("TSA") in the ROM hacking community. I dislike this name (in part because "Squaroid" is not a word in the English language) but do not have a better one to suggest. The method resembles a "Dictionary Table Encoded" ("DTE") array; a very simple form of Hash Table.
The idea behind the DTE/hash table is to represent several bytes (a "block") of information as a smaller block (typically only a single byte) of information. As an example, it is easy to represent a 2x2 square of tiles in only one byte; the byte used can therefore reference a total of 256 different 2x2 block combinations. The combinations available are first compiled into a big list called a dictionary. To decode a byte n into the resulting 2x2 square of tiles, you simply have to look up the nth entry in the dictionary.
Given each tile in the background layer tile map consumes 2 bytes, a stage the size of the MM7 intro level (4864 x 768 px for just the foreground) would require a tile map that's 116,736 bytes long. (Nearly 5% of the full ROM! And this is probably the smallest stage in the game.) That does not even include the tiles or palettes.
One way to "compress" a stage this size into something more reasonable is by breaking everything into smaller 'chunks' and indexing the crap out of it. To illustrate, we can start at the 'stage' level; a stage of 4864 x 768 px can be broken into chunks of 256 x 256 px 'rooms', giving a total map size of 19 x 3 'rooms' (that's 57 bytes!)
Now break each 'room' into 8 x 8 'structures', giving a total of 64 bytes per 'room'.
Break each 'structure' into 2 x 2 'blocks', giving a total of 8 bytes per 'structure'.
Break each 'block' into 2 x 2 tiles, giving a total of 8 bytes per 'block'.
You might imagine how this 'chunkifying' saves a whole lot of space, because it reduces redundancy (the main method of data compression, after all). With a stage like the intro (57 total rooms in the map) you might only use a maximum of 15 different kinds of rooms. And the same goes for creating rooms, structures, and blocks.
The Editor Interface
This is an area that I've spent a good deal of time exploring. Over 6 years worth of exploration, in fact. I think the best interface for this kind of game (considering the compression used, as explained above) will be to edit only one piece of the overall 'stage' at a time. For instance, the editor will start up in map edit mode on stage 0 (intro). In the map edit mode, the main canvas will display the complete stage. A toolbox will allow the user to select what kind of tool to use (in this example, a 'stamp' tool, to make changes). And below the toolbox, a palette for selecting one of the available 'rooms': Select an available room from the palette, and with the stamp tool, click on the map to 'stamp' that room into the location where the mouse is hovering.
Now this is fine for moving rooms around the map. But to get finer grained control over your editing, you would want to enter 'room edit mode' by double clicking on one of the rooms displayed in the palette. This will change the main canvas to display the room you double clicked, and the palette will change to display all available structures which can be placed into that room.
Double clicking a structure will then go one level deeper into structure edit mode; structure in the main canvas, and all available blocks in the palette.
And again, enter block edit mode by double clicking, and finally, tile edit mode by double clicking a tile in the block edit mode's palette. (The tile editing mode has a palette containing ... well, a color palette! Would it also be reasonable to enter a 'palette editing mode' by double clicking one of the available colors?)
This represents an overall of 5-6 nesting levels (map, room, structure, block, tile, ?palette?). To make this easy to use, 'back and forward' buttons should be made available. Links to all higher levels should also be available, similar to the GTK+ file picker window.
- Mockup screenshots to help illustrate conceptual ideas such as the nested-style user interface. Use Balsamiq Mockups to create the mockups.
- Write the rendering module in C as a dynamic library; call exported functions with js-ctypes.
- Extend the GetDataX() functions: maybe GetDataPtrX() ? or functions to get arrays...