I've been hacking SPA the past couple weeks. Here's some of what I've found. I don't really follow the hacking community, so I'll probably use nonstandard terminology in places. Note that 0xxxxx/1xxxxx addresses are offset internally as 2xxxxx/3xxxxx addresses, as the NGPC mounts the ROM at 200000-3FFFFF.
Level data-
The main level data is listed at 19DE1A. Each level gets 14 bytes, as follows -
4: Level data
4: Some procedure I haven't gone through
2: Sonic's starting height (width is fixed)
2: "Background" color index (often not actually the background, but some other useful color)
2: [UPDATE:] Water level - affects physics, splashes, Sonic palette and drowning; everything else is level design
Here's the listing.
Map Formats-
NGPC graphics are composed of 8x8 4color tiles, with 16 4color palettes for each of the foreground, background and sprites (so 48 total). SPA has a large set of universal palettes; everything else is done per-level. I'll be referring to the NGPC memory map for what's drawn from the hardware rather than just rewriting it.
The SPA level designs are constructed of tiles using 4x4 blocks, which assign the tiles their palettes and orientation, in the format specified by the hardware for the scroll maps (see memory map 9000). The RAM tile positions are as such hardcoded, so structural tiles are constant throughout a level. The blocks for a level are listed out at the address at LvAddr+14; the number varies per level, but maxxes out at between 4096 and 8192 (as determined crudely by the fact that my level mapping code works).
The tiles themselves are at the address at LvAddr+30; their format is specified by the memory map's pattern table (A000). There's exactly 512, since the NGPC has space for 512 tiles and once the level is loaded they stay. A certain number of spots are used for sprites and fluctuate during play, but this is more or less ignored here.
Foreground palettes are at LvAddr+18, background at LvAddr+22. Sprites I haven't yet bothered to find but I assume they're close by. Note that what's stored here isn't actually palettes per se - those are all at 3C748. What IS here are the 16 palette indices (out of thousands) that are actually USED in the level.
OK, the map itself. At LvAddr there's a two byte level width in blocks, and two byte height in blocks. There's actually TWO maps, one for the background (LvAddr+10) and foreground (LvAddr+26). Each is a straight listing of 2byte block indices, with the level ordered in rows. Pretty straightforward. I've used all this info to make maps of each level, which you can find here, along with the generating PHP source. They're lacking sprites for the moment, but I'll rectify that some time soon.
One interesting note is that the rings are baked into the foreground map instead of acting as sprites, which as I understand it is unusual among the Sonic games. With the NGPC's 64 sprite limit, SPA would otherwise be limited to about 8 rings on screen otherwise. IIRC, the game actually has copies of each block with various rings present and removed.
Sprite Formats-
The sprite tiles (dec10916 of them) are at CB34. Here's a sheet of them all. The tiles are composited into actual sprites using data at 296. That format is as far as I know nonstandard, so I'll describe it below.
First two bytes - number of tiles
Varying quantities of
either one tile at a time... {
Two bytes - tile index
One byte - row offset (signed)
One byte - col offset (signed)
}
*AND/OR*
multiple consecutive tiles... {
Two bytes - FFFF (to note that there is extra stuff here)
Two bytes - number of tiles
Two bytes - initial tile index
One byte - row offset (signed)
One byte - col offset (signed)
} <- in this case, tiles after the first each go 8px below the last
... to match tile count.
Each sprite goes straight one after the other in this fashion, with no regular offsets or anything. Frankly I think it's a bit of a mess, but I guess it worked for them.
Here's a sheet of all the sprites, properly composited. Unfortunately the offsets for some of the sprites are all over the place, but I erred on the side of having some of the sprites overlap rather than making the image absolutely huge (and it's already pretty ridiculously huge, at 1024x30080). The odd ghostly sprites, most obvious after the Sonics at the beginning, are used to give a sprite more than four colors while staying within the 16 palette limit. And if anyone can think of what sprites 428-430 are used for, please clue me in. o_O
Anyway... I have some notes on the routines and procedures, but I tried to avoid disassembling whenever possible, both because asm is a pain to begin with and because I can't even find definitions for many of the opcodes so I've had to deduce them myself. That's what I get for the NGPC using such a weird obscure processor. Also, it appears to me that either the game was compiled from some higher level language or the programmers had really bizarre habits; I don't really have enough experience with asm to say for sure, but I don't think it's SOP to call subroutines four lines long that are halfway across the ROM. I also have notes on a whole bunch of the RAM locations and their purpose. Buuuuut I am tired! so I think I'll sleep instead and write them up later. XD Cheerio~
Level data-
The main level data is listed at 19DE1A. Each level gets 14 bytes, as follows -
4: Level data
4: Some procedure I haven't gone through
2: Sonic's starting height (width is fixed)
2: "Background" color index (often not actually the background, but some other useful color)
2: [UPDATE:] Water level - affects physics, splashes, Sonic palette and drowning; everything else is level design
Here's the listing.
LvAddr StHgt bgclr Water [2A3590] [39E742] a8 01 02 00 00 00 | NSI1 [2B472E] [39E742] 48 02 02 00 00 00 | NSI2 [2E0BA8] [39E755] 90 03 26 01 00 00 | SP1 [2E9F14] [39E76E] C0 05 26 01 97 00 | SP2 [31D04C] [39E78A] 18 04 70 01 00 00 | CC1 [326824] [39E78A] E8 01 70 01 00 00 | CC2 [34CA24] [39E729] 00 03 9C 01 87 02 | AR1 [35582E] [39E729] 30 03 9C 01 A7 02 | AR2 [35BB62] [39E7C5] A8 00 27 00 00 00 | SC [36BCC2] [39E7C6] 00 02 27 00 00 00 | AB [38A188] [39E7E2] 68 00 F0 01 00 00 | GA1 [393240] [39E7E2] C0 04 F0 01 00 00 | GA2 [396E4C] [39E728] F8 00 B8 01 00 00 | LU [36BCC2] [39E728] 18 02 02 00 00 00 | AB? [396EAA] [39E742] 60 00 02 00 00 00 | CS [2A3590] [39E742] A8 01 02 00 00 00 | TS1 [2B472E] [39E742] 48 02 02 00 00 00 | TS2
Map Formats-
NGPC graphics are composed of 8x8 4color tiles, with 16 4color palettes for each of the foreground, background and sprites (so 48 total). SPA has a large set of universal palettes; everything else is done per-level. I'll be referring to the NGPC memory map for what's drawn from the hardware rather than just rewriting it.
The SPA level designs are constructed of tiles using 4x4 blocks, which assign the tiles their palettes and orientation, in the format specified by the hardware for the scroll maps (see memory map 9000). The RAM tile positions are as such hardcoded, so structural tiles are constant throughout a level. The blocks for a level are listed out at the address at LvAddr+14; the number varies per level, but maxxes out at between 4096 and 8192 (as determined crudely by the fact that my level mapping code works).
The tiles themselves are at the address at LvAddr+30; their format is specified by the memory map's pattern table (A000). There's exactly 512, since the NGPC has space for 512 tiles and once the level is loaded they stay. A certain number of spots are used for sprites and fluctuate during play, but this is more or less ignored here.
Foreground palettes are at LvAddr+18, background at LvAddr+22. Sprites I haven't yet bothered to find but I assume they're close by. Note that what's stored here isn't actually palettes per se - those are all at 3C748. What IS here are the 16 palette indices (out of thousands) that are actually USED in the level.
OK, the map itself. At LvAddr there's a two byte level width in blocks, and two byte height in blocks. There's actually TWO maps, one for the background (LvAddr+10) and foreground (LvAddr+26). Each is a straight listing of 2byte block indices, with the level ordered in rows. Pretty straightforward. I've used all this info to make maps of each level, which you can find here, along with the generating PHP source. They're lacking sprites for the moment, but I'll rectify that some time soon.
One interesting note is that the rings are baked into the foreground map instead of acting as sprites, which as I understand it is unusual among the Sonic games. With the NGPC's 64 sprite limit, SPA would otherwise be limited to about 8 rings on screen otherwise. IIRC, the game actually has copies of each block with various rings present and removed.
Sprite Formats-
The sprite tiles (dec10916 of them) are at CB34. Here's a sheet of them all. The tiles are composited into actual sprites using data at 296. That format is as far as I know nonstandard, so I'll describe it below.
First two bytes - number of tiles
Varying quantities of
either one tile at a time... {
Two bytes - tile index
One byte - row offset (signed)
One byte - col offset (signed)
}
*AND/OR*
multiple consecutive tiles... {
Two bytes - FFFF (to note that there is extra stuff here)
Two bytes - number of tiles
Two bytes - initial tile index
One byte - row offset (signed)
One byte - col offset (signed)
} <- in this case, tiles after the first each go 8px below the last
... to match tile count.
Each sprite goes straight one after the other in this fashion, with no regular offsets or anything. Frankly I think it's a bit of a mess, but I guess it worked for them.
Here's a sheet of all the sprites, properly composited. Unfortunately the offsets for some of the sprites are all over the place, but I erred on the side of having some of the sprites overlap rather than making the image absolutely huge (and it's already pretty ridiculously huge, at 1024x30080). The odd ghostly sprites, most obvious after the Sonics at the beginning, are used to give a sprite more than four colors while staying within the 16 palette limit. And if anyone can think of what sprites 428-430 are used for, please clue me in. o_O
Anyway... I have some notes on the routines and procedures, but I tried to avoid disassembling whenever possible, both because asm is a pain to begin with and because I can't even find definitions for many of the opcodes so I've had to deduce them myself. That's what I get for the NGPC using such a weird obscure processor. Also, it appears to me that either the game was compiled from some higher level language or the programmers had really bizarre habits; I don't really have enough experience with asm to say for sure, but I don't think it's SOP to call subroutines four lines long that are halfway across the ROM. I also have notes on a whole bunch of the RAM locations and their purpose. Buuuuut I am tired! so I think I'll sleep instead and write them up later. XD Cheerio~
This post has been edited by Rolken: 24 October 2006 - 12:53 AM


00