2017/02/04

Development Insight #3: SMA2 Status Screen

Super Mario Advance 2 was my first experience with Super Mario World, so I hold it very dear to my heart. Of all the Advance-series ports, it's probably the least amazing in terms of new content. However, that doesn't mean it doesn't have new content. One of the neater additions is a status screen that pulls up on the overworld, which shows your progress in various worlds. Specifically: which levels you've unlocked, which ones you've completed, and which ones you collected all the Yoshi coins for, in addition to general information like score and time passed. Pretty useful, especially when you complete all the exits because then you're able to warp to any level simply by selecting it.

One time on CaffieNET (#smwc or #serioushax, not sure which since I no longer have logs of the time), the one and only Adam suggested that someone port this status screen to Super Mario World. I, being a rather compulsive idiot, jumped at the opportunity.



Like any "smart" coder, I didn't start from scratch, but rather used another patch of mine as a base. In this case, it was a patch that put a few counters onto the overworld border, specifically Yoshi coins (I eventually released this patch to SMWC). Hence the filename 'owyicoin.asm'. But before I did any coding, I had to research SMA2's status screen. As this was more of a "recreation" than a "port" (since it would be near-impossible to port over due to the different architectures), I basically had to make note of every little detail; scrolling speed, dimensions and padding, cursor dynamics, etc. using both an emulator and my own GBA. The emulator proved to be more useful of course, since I was able to rip images directly, view the composition in VRAM, palette, etc. But my GBA copy helped with the end-game changes since I was too lazy to obtain a 100% save file for emulation. Anyways, once I got all my resources I started planning.

Being a recreation, and given the different system architectures, it was ultimately impossible to accurately recreate the status screen. For starters, the GBA has a smaller screen resolution. Though this actually plays into the SNES's benefit: more levels can fit into one world.

Speaking of "worlds", this is one... problem? That SMW has and that SMA2 doesn't. It is impossible to determine what level is in which world. Conceptually, this gives you more freedom and less worry, but when you need to catalogue the levels into separate lists in-game you essentially have to manually sort the levels. That is, the player (hack author, patch user, whatever) needs to dictate what levels belong to which worlds. You'd think you can just separate via submaps and area on main map, but levels like the Vanilla secrets (which belong to Vanilla dome but are located on the main map) kinda screw that over.


How exactly SMA2 transitions to the status screen, whether it's a separate game mode, etc, I am not sure. I personally wanted to "preserve" the overworld (avoid rerendering, and thus speeding up the transition), so I decided to stay within the overworld game mode , and not touch layers 1 or 2, instead opting for a layer 3/sprite combo. As SMA2 uses a 16-color layer for the status screen, this ultimately meant a visual downgrade... though I believe I masked it well. Since the only thing that uses layer 3 on the overworld is the border (as well as text boxes, but those don't run during the border), making use of layer 3 is not much of a problem. In fact, rather than backup the layer 3 border and upload a custom image, I decided to implement the status screen below the overworld border, and repoint the old overworld border. Definitely something I would change in the future, as it probably introduces incompatibilities (like with newer Lunar Magic versions with their ability to have a per-submap border).

One aspect of the status screen that I put immense time and effort into was the current level name at the very top of the screen. This uses the same font as normal layer 3 text throughought the game (in message boxes and the level name on the overworld border), but with one distinction: it has a shadow. Although SMA2 probably has the text+shadow graphics hardcoded for simplicity (probably), I decided to go with the bold idea of dynamically rendering the shadow, since I was working with fewer color planes (layer 3). Basically, what I did was:
  1. Get the level name
  2.  Render the level name using the regular layer 3 font GFX, and store this in RAM
  3. Shift the colors around. This now becomes Copy1
  4. Shift the font itself down 1 pixel, change its color, and store this in separate RAM, becoming Copy2
  5. Fuse the two copies (bitwise math)
  6. Map this new render onto a layer 3 log graphic (more bitwise math), upload to layer 3 VRAM, and place at the top of the screen
I may not have followed this exactly, but you get the general idea. This is all done during loading of the status screen, since the name remains static.


I mentioned I used sprites in addition to layer 3. I had set an arbitrary restriction on layer 3 for myself: I could only use 2kb of GFX. The top-screen level name took up most of that, so in the end I ran out of space. Sprites were thus used where it made sense; areas that needed more than 3 or 4 colors (the Yoshi coin icon next to each level, Peach, etc). But they were also used where it would be (near) impossible to use layer 3. When you scroll through the worlds, the bottom segment with the levels moves left/right while the top segment remains static. These two segments actually overlap, so sprites were used in the overlap (in addition to HDMA) to create the illusion of two separate layers. Well, not really an illusion... but most people don't think of sprites as a layer of individually-positioned tiles.


I'm not a fan of using freeram, because nubs usually do not change the default addresses, and thus you get a billion threads on SMWC asking why a patch is broken when the other 20 patches they installed aren't. Additionally, in this case, there is A LOT of RAM that is used, so having to redefine everything would be nuts. So I had the (honestly stupid) idea of using the second half of the Map16 table at $7EC800 (specifically $7EE000+). Levels obviously store tile data here for every screen, but the overworld uses it for "Map16" as well as several other things, since the maps are not that large. Some of the RAM actually goes unused, so that's the part I end up using. I shove EVERYTHING here; VRAM backups, GFX buffers, tables, and general RAM addresses. If I were to remake the patch, I would definitely move most of that stuff to mirrored RAM (buffers and backups can stay) to save space and time. Though if I remade the patch properly then I probably wouldn't need so much RAM.


I''ll end it with a few random comments.

The most complicated portion of the patch is the one that arranges the level names and icons, preparing them for DMA. I have it commented as "the main meat of the patch". I often joke about how "idk how I got that to work lol" but I really have no clue how I managed to code this part. The crappy labels probably didn't help. I would honestly not touch this part in a remake. Which is weird because theoretically it doesn't sound too difficult to arrange the damn level names (that's probably the spirit that got me through it).

For some reason, I initially intended to keep everything in NMI. Probably because the overworld counters patch did it (and still does). Evidently, the patch got too big and certain things wouldn't work properly, so I had to break Ladida Rule #8 and use a secondary hijack.

The last part I coded was the ability to warp to different levels, as it's an endgame thing. It requires re-rendering the overworld; you can't just move Mario. It also requires pinpointing where on the two maps (main map and submaps as a whole) the specific level you chose is. It checks via indexing, so it's technically faster to warp to a level on the bottom of the submap map than the top of the main map 😀. Anyways I pretty much hacked this part together; not sure if I studied the original game's level -> OW transition. The last LAST part I coded was the cursor you use to select levels to warp to. There's a whole comment block I threw in there celebrating the end of the patch.


The patch is one of my greatest ASM achievements, especially considering its age. I'm happy with its current state, though if people want better I'm sure I can tackle it again. Just give me lots of painkillers.

No comments:

Post a Comment