09-25-2012, 07:06 PM
Yeeeaaah dunno if this is allowed but bear with me, aight?
Virtual Boy Wario Land has a rich set of sprites, and though Virtual Boy emulation has been around for several years now, the amount of rips from the game are few at most. There are a variety of valid reasons why this is, though:
- The graphics are compressed. Most of them are compressed with a variation of RLE, to which Previous wrote an experimental decompressor already. It isn't perfect though, and the game has another, yet-unknown compression method.
- The sprites are layered. I'd call it the "Yoshi's Island problem", as the tiles look fine and are available easily, but layering them exactly as the game does is far trickier. And nobody really wants "compile your own sprite"-sheets.
The first problem, the graphics being compressed, is easy to bypass, even without a dedicated decompressor. The most actively developed Virtual Boy emulator, VBJin (Or, for Mac and Linux users, Mednafen) uses .mc# as its save state format. Opening an mc# in Tile Molester and heading to 0x77821 (2bpp linear, reverse-order) will show you two full graphic pages. These are the common room elements. These graphics are 'always' in the RAM and look like this. I'll get back on these later.
In 0x79821, two banks after the CRE, are the level elements. These are tiles that the game loads to RAM immediately after a level is entered.
These are also the tiles that I'm going to primarily elaborate on.
These are stage 1's level elements. I'm Dividing them into a $0Fx$0F grid for easier viewing:
So, there's the tiles. A lazy man would arrange them a bit, save and submit. Although that would be better than nothing, it's better to go for the gold. In the ROM, at 0x1BFA9 there's a byte array that essentially contains the exact instructions of how all of the sprite is assembled. Take a good look at the bytes. I've formatted them into 4 bytes per row.
Code:
E0 02 90 02
D8 02 80 02
E8 04 A0 02
F4 04 97 02
F4 FC 96 02
F8 04 A3 02
F8 FC A2 02
F8 F4 A1 02
F0 04 93 02
F0 FC 92 02
F0 F4 91 02
E8 04 83 02
E8 FC 82 02
E8 F4 81 02
E0 F8 90 22
D8 F8 80 22
E8 F6 A0 22
FF FF FF FF
DC 02 90 02
D4 02 80 02
E4 04 A0 02
F0 04 97 02
F0 FC 96 02
F4 04 A6 02
F4 FC A5 02
F4 F4 A4 02
FC 04 87 02
FC FC 86 02
EC FC 95 02
EC F4 94 02
E4 FC 85 02
E4 F4 84 02
EC 04 93 02
E4 04 83 02
DC F8 90 22
D4 F8 80 22
E4 F6 A0 22
FF FF FF FF
DC 02 90 02
D4 02 80 02
E4 04 A0 02
F0 04 97 02
F0 FC 96 02
F4 04 A6 02
F4 FC A5 02
F4 F4 A4 02
EC FC 92 02
EC F4 91 02
E4 FC 82 02
E4 F4 81 02
FC 04 87 02
FC FC 86 02
EC 04 93 02
E4 04 83 02
DC F8 90 22
D4 F8 80 22
E4 F6 A0 22
FF FF FF FF
E0 01 90 02
D8 01 80 02
E8 03 A0 02
F4 03 97 02
F4 FB 96 02
F8 04 A3 02
F8 FC A2 02
F8 F4 A1 02
F0 04 93 02
F0 FC 92 02
F0 F4 91 02
E8 04 83 02
E8 FC 82 02
E8 F4 81 02
E0 F9 90 22
D8 F9 80 22
E8 F7 A0 22
FF FF FF FF
DC 01 90 02
D4 01 80 02
E4 03 A0 02
F0 03 97 02
F0 FB 96 02
F4 04 A6 02
F4 FC A5 02
F4 F4 A4 02
FC 04 87 02
FC FC 86 02
EC FC 95 02
EC F4 94 02
E4 FC 85 02
E4 F4 84 02
EC 04 93 02
E4 04 83 02
DC F9 90 22
D4 F9 80 22
E4 F7 A0 22
FF FF FF FF
DC 01 90 02
D4 01 80 02
E4 03 A0 02
F0 03 97 02
F0 FB 96 02
F4 04 A6 02
F4 FC A5 02
F4 F4 A4 02
EC FC 92 02
EC F4 91 02
E4 FC 82 02
E4 F4 81 02
FC 04 87 02
FC FC 86 02
EC 04 93 02
E4 04 83 02
DC F9 90 22
D4 F9 80 22
E4 F7 A0 22
FF FF FF FF
E8 FD AC 02
E8 F5 9C 02
E9 ED 8C 02
F8 06 BD 02
F0 06 BC 02
F0 10 A7 02
F8 08 AA 02
F8 00 A9 02
F8 F8 A8 02
F0 08 9A 02
F0 00 99 02
F0 F8 98 02
E8 08 8A 02
E8 00 89 02
E8 F8 88 02
F0 FC AC 02
F0 F4 9C 02
F1 EC 8C 02
FF FF FF FF
E8 FD AC 02
E8 F5 9C 02
E9 ED 8C 02
F7 06 BD 02
EF 06 BC 02
F8 0B AB 02
F0 0B 9B 02
E8 0B 8B 02
F8 08 AA 02
F8 00 A9 02
F8 F8 A8 02
F0 08 9A 02
F0 00 99 02
F0 F8 98 02
E8 08 8A 02
E8 00 89 02
E8 F8 88 02
F0 FC AC 02
F0 F4 9C 02
F1 EC 8C 02
FF FF FF FF
E8 FC AC 02
E8 F4 9C 02
E9 EC 8C 02
F8 05 BD 02
F0 05 BC 02
F0 10 A7 02
F8 08 AA 02
F8 00 A9 02
F8 F8 A8 02
F0 08 9A 02
F0 00 99 02
F0 F8 98 02
E8 08 8A 02
E8 00 89 02
E8 F8 88 02
F0 FD AC 02
F0 F5 9C 02
F1 ED 8C 02
FF FF FF FF
E8 FC AC 02
E8 F4 9C 02
E9 EC 8C 02
F7 05 BD 02
EF 05 BC 02
F8 0B AB 02
F0 0B 9B 02
E8 0B 8B 02
F8 08 AA 02
F8 00 A9 02
F8 F8 A8 02
F0 08 9A 02
F0 00 99 02
F0 F8 98 02
E8 08 8A 02
E8 00 89 02
E8 F8 88 02
F0 FD AC 02
F0 F5 9C 02
F1 ED 8C 02
FF FF FF FF
F8 FD B3 02
F8 F5 B2 02
F7 ED B1 02
EC 06 BD 12
F4 06 BC 12
F0 07 9F 02
F3 0F B0 02
F8 07 AF 02
F8 FF AE 02
F8 F7 AD 02
F0 FF 9E 02
F0 F7 9D 02
E8 07 8F 02
E8 FF 8E 02
E8 F7 8D 02
EF FC B3 02
EF F4 B2 02
EE EC B1 02
FF FF FF FF
F8 FD B3 02
F8 F5 B2 02
F7 ED B1 02
EB 06 BD 12
F3 06 BC 12
F8 0F BB 02
F8 07 BA 02
F0 0F B9 02
F0 07 B8 02
F0 FF B7 02
E8 0F B6 02
E8 07 B5 02
E8 FF B4 02
F8 FF AE 02
F8 F7 AD 02
F0 F7 9D 02
E8 F7 8D 02
EF FC B3 02
EF F4 B2 02
EE EC B1 02
FF FF FF FF
F8 FC B3 02
F8 F4 B2 02
F7 EC B1 02
EC 05 BD 12
F4 05 BC 12
F0 07 9F 02
F3 0F B0 02
F8 07 AF 02
F8 FF AE 02
F8 F7 AD 02
F0 FF 9E 02
F0 F7 9D 02
E8 07 8F 02
E8 FF 8E 02
E8 F7 8D 02
EF FD B3 02
EF F5 B2 02
EE ED B1 02
FF FF FF FF
F8 FC B3 02
F8 F4 B2 02
F7 EC B1 02
EB 05 BD 12
F3 05 BC 12
F8 0F BB 02
F8 07 BA 02
F0 0F B9 02
F0 07 B8 02
F0 FF B7 02
E8 0F B6 02
E8 07 B5 02
E8 FF B4 02
F8 FF AE 02
F8 F7 AD 02
F0 F7 9D 02
E8 F7 8D 02
EF FD B3 02
EF F5 B2 02
EE ED B1 02
FF FF FF FF FF FF FF
- The first byte tells us the y coordinate of the tile
- The second byte tells us the x coordinate of the tile
- The third byte tells us the tile in question
- The fourth byte tells us the orientation of the tile. Read bitwise as bbhv bbbb
- h = horizontal flip
- v = vertical flip
- b = bank related. No real use and could be ignored (for now?)
- h = horizontal flip
- FF FF FF FF means "the assembly for this single sprite is done"
- FF FF FF FF FF FF FF means "the composition for this character's each sprite is done"
So let's see the grid:
After some trial and error, I came to the conclusion that this kind of coordinate system is used. So let's assemble our first sprite by reading the instructions in order (this is crucial because the layering of the tiles depends on it. The horn in the back is printed last, because it's the sprite 'most behind')
Click here to download the instructional GIF. If you can, watch it frame-by-frame. It might go faster than you can keep up with of what's going on (I would've made a html slideshow with "next step" etc. buttons but I don't know how).
As you can see in the GIF, I pick up a tile, set its Y position (byte 1), then set its x position (byte 2), then elaborate what the tile is (byte 3), and finally go through the property byte to see if it's flipped (byte 4).
Then I read the next four bytes with the same idea. Repeat until FF FF FF FF. Save complete sprite as "sprite1-frame1", start reading bytes again, repeat, repeat, repeat until FF FF FF FF FF FF FF. Sheet done.
Well, not exactly. That's what I would do. But as you saw, the assembly is pretty tedious. Making that GIF alone took a nice chunk of time. Doing this by hand is absolutely out of the question, so I come forth with a question — could this process be automated by a program?
Of course it would. Being unable to program, though, this is as far as I can help here. If anyone has any interest in writing such a sheet-compiler, we could go forth towards step two.
"Step two? So step one is basically you asking for someone to write a program to do all the work so you can export sheets and claim as yours?!"
Not exactly. Step one here is pretty much only a theoretical, planning-stage type manifest. Even if the program is done, it will still need to know the assembly instructions and separate save states for each sprite set, and these are in no way linked—there is no pointer table in the ROM that tells where the instructions for each graphics page's sprites are. Most instructions I've found are directly after the respective compressed graphics, but, for example, instructions for the CRE are after the instructions of some random graphics with no indicator of "hey, we're not defining that guy's sprites anymore" anywhere inbetween.
The only clues we really have are that all(?) instruction sets begin with a 00 00 00 00 00 00 00 00-header and continue like I explained above until FF FF FF FF FF FF FF is met. That, and the fact that most instructions are after the compressed graphics.
I can single-handedly hunt down every instruction set in the ROM and make save states even, if enough people are interested. What I really want to know here is that is anyone interested in programming this essential tool, and if yes, once it's done, is any of you guys up for splitting the burden of "try this instruction set with that graphics file/save state until it matches" with me? Or something, I dunno.