don't click here

SPA stuff

Discussion in 'Engineering & Reverse Engineering' started by Rolken, Oct 23, 2006.

  1. Rolken


    Tech Member
    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.
    Code (Text):
    1. LvAddr          StHgt bgclr Water
    2. [2A3590] [39E742] a8 01 02 00 00 00 | NSI1
    3. [2B472E] [39E742] 48 02 02 00 00 00 | NSI2
    4. [2E0BA8] [39E755] 90 03 26 01 00 00 | SP1
    5. [2E9F14] [39E76E] C0 05 26 01 97 00 | SP2
    6. [31D04C] [39E78A] 18 04 70 01 00 00 | CC1
    7. [326824] [39E78A] E8 01 70 01 00 00 | CC2
    8. [34CA24] [39E729] 00 03 9C 01 87 02 | AR1
    9. [35582E] [39E729] 30 03 9C 01 A7 02 | AR2
    10. [35BB62] [39E7C5] A8 00 27 00 00 00 | SC
    11. [36BCC2] [39E7C6] 00 02 27 00 00 00 | AB
    12. [38A188] [39E7E2] 68 00 F0 01 00 00 | GA1
    13. [393240] [39E7E2] C0 04 F0 01 00 00 | GA2
    14. [396E4C] [39E728] F8 00 B8 01 00 00 | LU
    15. [36BCC2] [39E728] 18 02 02 00 00 00 | AB?
    16. [396EAA] [39E742] 60 00 02 00 00 00 | CS
    17. [2A3590] [39E742] A8 01 02 00 00 00 | TS1
    18. [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)
    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~
  2. ICEknight


    Researcher Researcher
    Heh, I didn't know Aquatic Relix had those funny faces within the wall bricks.

    Those maps rule, great job finding those formats!

    Isn't that a Sonic2-style shield?
  3. Sparks


    Sondro Gomez / Kyle & Lucy
    Holy shit, this something I've wanted to look into for awhile now, looks like ya beat me. :P

    SPA hacking tool perhaps? *shotshot*
  4. stormislandgal


    It's not a phase! Tech Member
    Married life <3
    Hey Hey, only 5 posts and you're already a Tech Member. Good job!

    While I myself am not too interested in Sonic Pocket Adventure hacking, this will surely, and hopefully, inspire more hacking of this game, and possibly others.

    Oh, nice sprite sheet by the way. Can't put my finger on the sprites you mentioned though, and they don't look like shields to me... I dunno though, maybe I'm not looking hard enough.
  5. Sparks


    Sondro Gomez / Kyle & Lucy
    Those look like the same shields used in the game.
  6. Rolken


    Tech Member
    Those are indeed the shields. I was thrown by how huge they are, but on looking back in the game, they really are that much bigger than Sonic. :X

    As for the RAM data. I don't have the level of comprehensive info on the RAM that I'm gaining with 8-bit Sonic, simply because the tools aren't there, so I've really only found what was convenient or I was interested in. There's a debug version of NeoPop that lets you pause emulation and check the memory, but it mysteriously completely stopped working on my PC; even downloading it into different directories with different ROMs didn't work. But even if it did work it's not nearly as useful as Meka's watch-it-as-it-runs capability. As it is I'm more or less reduced to analyzing savestates and source. It's worth noting that NeoPop's savestates are basically a RAM dump with two bytes appended at the beginning, whereas every other emulator seems to use less useful formats (and be less useful in general).

    Aaaanyway. I'll just list out what I have. It's worth minding that 0100-6C00 is general usage RAM and 8000-BFFF is VRAM. The NGPC has far more RAM than SPA actually uses, so I haven't found any RAM locations that're reused so far. Everything up to 4000 is left unused, and the rest still has huge blocks of 0s. Broadly speaking, SPA uses 49xx-50xx for sprite/display data, and 67xx-6Bxx for status data.

    49F8-49FC: Sprite work variables
    4Axx: I *think* these are the various sprite statuses, but haven't nailed down
    4B6E-4C6D: Sprite workarea; tiles are assembled and tagged and copied to 8800-88FF
    4C6E: Er... I forget, but it does SOMETHING XD
    4CEE: Likewise
    4CF0-4D2F: Palette workarea; goes to 8C00-8CFF
    5056-5057: Background scroll, goes to 8032-8033
    506C-506D: Foreground scroll, goes to 8034-8035
    5086: Sprite scroll
    67A4.2: Camera X
    67A6.2: Camera Y
    67A8.4: Ring counter
    67CC.2: Timer, as a straight frame count (30fps).

    My procedural knowledge thus far is primarily confined to the display crankers. I'll use NGPC 200000 offsets for differentiation from RAM addresses.

    23C663: The 'master' drawing procedure. Calls a bunch of subroutines and then hangs around and waits for an interrupt while writing 4E to 6F (the NGPC resets if 6F goes unwritten to for 100ms). The following addresses are the various subroutines it calls and my labels for them.

    23E488 "Slashnburn": Dumps FFs and 00s all over the sprite stuff to get ready for the next frame
    3DFE39 "FgMap" (23C496 w/ 0->A): Offsets the space at 9000-93FF by two and sticks 01FF at the front
    23C1F8 "PreSpCalc": Initializes the sprite work variables to signal to SpCalc that it's starting anew
    23E884: I don't have complete notes on this, got distracted by the sprite layout algorithm
    23C03D "SpCalc": The big one. Does all the sprite compilation work.
    23E1BA: I think this is some kind of tile moving shenanigans
    29112A "MinuWork": Hijinks around the 5056-5070 area
    23BFE2 "SpCopy": Copies stuff from sprite workarea to the sprite real area
    23E17D "PltCopy": Same thing, for palettes
    2911B9 "ScrCopy": Same thing, for scrolling

    The next order of business is to find how the sprites are encoded in the level design so I can splice them onto the maps. I suspect that the relevant address is at LvAddr+6, as it's the only piece of data there I haven't pinned down.

    Also if anyone plans to put this to use, I should make you aware of a few errors I've tended to make in case any persist. I often typo Es in addresses as 3s and more occasionally As as 4s; I blame l33tsp3ak clouding my mind. :/ RAM addresses might also be 2 higher than they should be if I neglected to correct the savestate offset. And occasionally I've calculated terminating addresses incorrectly.

    Sooooo that's it for now. Further bulletins as events warrant. I originally was doing all this with the goal of making maps for TSC and pinning the puzzle piece locations (which I learn is now already done), so whatever else I do/n't do will be fueled by random curiosity or requests. As for making a fullfledged hacker... maybe at some point, but it's pretty far down on the priority list, so don't hold your breath. :P

    Edit: A few more notes. I'm assuming that finding the level sprite encoding will also provide the palettes the game uses, in which case I can update the grayscale sprite sheet with colored ones. Also, while I certainly don't mind being given credit for rips, don't feel obligated to. As far as I'm concerned, it's the artists who made them, my contribution is secondary.

    Edit2: Here's the disassembly I've been using for research. Be warned, it's a 50MB text file, don't try to open it in Notepad; I use Visual Studio myself. I used an obscure NGPC-specific program and disassembled the whole thing indiscriminately, so large chunks of it are gibberish it tried to pull from data.
  7. Rika Chou

    Rika Chou

    Tech Member
    *moved to archive and opens*

    Seriously deserves to be here.
  8. Bibin


    New York City
    Ghost in the Machine
    This is awesome and interesting- but is there any known way to edit sonic's palette?