MM: sprite work extended
Pwwwhooo.. You run into problems when you give NES extended sprite sizes ;>_>
NES doesn’t have negative left coords for hiding or moving sprites to the left off screen. They do for the right side though, but it’s only 8 pixels wide. The X position is 8bit: 0 to $ff. $F8-$FF don’t get shown onscreen and so they don’t wrap around. And since the largest width for a sprite on the NES *is* 8 pixels, it works. The problem occurs on the original NES is when you want that effect left side. Megaman handles this by hiding the sprites in 8pixel wide columns of the whole meta-sprite. So you get this sort of jarring/popping on the edge. Not a huge deal on the real system, especially back in the day when the edge of the 256 pixel wide screen was almost always partially in overscan area (TVs were rather poorly calibrated back then and the tolerance allowed for overscan was rather sloppy for consumer grade equipment).
So in comes my problem. I replaced all MM main character meta sprite with a single entry: 32×32. The game logic tries to remove the right edge on MM when he’s right at the edge of the left side, thus he disappears. Big problem? Not really. I can fix that logic. But that got me thinking. If I don’t find a solution to this problem, it could definitely be a problem for any other NES game one might want to upgrade as such. There aren’t enough bits left in the sprite attribute byte to fix this either (the problem is not to break compatibility).
So after mulling this over for a few days, I’ve come up with a solution. It’s pretty damn rare that games use “OAM data” ($2004). They all seem to use the sprite dma controller ($4014). The nice thing about the sprite dma is that it copies all 64 OAM entries to PPU OAM ram while halting the cpu. The dma controller takes an address based on $x00 from ram. And the NES only has 2k of ram ($000-$7ff). This is perfect for the solution. I have a shadow 64 entry in higher/invalid ram area of the NES range. This provides four additional bytes to the original four bytes for an OAM entry. For X and Y, the shadow equivalent bytes are a signed offset (2’s compliment). Perfect for offsetting the sprite with it ‘wrapping’ onscreen. And here comes the tricky part. For compatibility, the sprite dma function backend code clears each byte after it reads it. So the game engine itself doesn’t need to clear the shadow list. And if it isn’t used, values of $00 do nothing to effect the original. This also allows to me to use all 16 subpalettes for sprites and also allows me to use other sprite ‘banks’ in PCE vram.