Not one capture here. Every picture is drawn from the bytes of the ROM, by running in Python the same two script interpreters the Z80 runs. The listing and the numbers are reproducible with make, and reassembling gives back the ROM byte for byte.
On a bonus stage, if you stand on the exact square X=0x90, Y=0x39, the game prints KONAMI 5730 PTS and awards those 5730 points. The two figures agree on their own: the caption says so and the ld de,05730h at 0x4931 adds it.
The number is not arbitrary. Japanese numbers can be read by their sound too: 5 = go, 7 = na, 3 = mi, that is go-na-mi. It is an easter egg the company reused across many of its games, arcade ones included.
When nobody is playing, the character moves by itself. No routine decides anything: there are 77 recorded keypresses, compressed at 0x5D82, unpacked to 0xE342, which the routine at 0x468F feeds in where the joystick input would go, one every two frames, until it hits an 0xFF.
The values are the joystick masks themselves, so the rest of the game cannot tell whether a person or the script is playing.
This cartridge keeps no walkability map in memory. To find out, it reads the screen: it calls RDVRM and looks at which pattern is drawn on the square. Anything below 0x80 counts as wall, from 0x90 on you can walk.
That explains a detail that would otherwise look odd: whenever an object is placed, the game notes down what was underneath. Otherwise picking it up would punch a walkable hole in the wall.
The game announces fifty zones, and there are only twenty-five distinct maps: at 0x498E, once the zone number reaches 25, it subtracts 25 and starts over from the first map.
And of those twenty-five, four are the same one: entries 4, 9, 14, 19 and 24 all point at the block at 0x6E87. One zone in five is a bonus stage, and they all share a screen.
The proof that the maps are read correctly is not that they look right: it is that all twenty-five, compressed with the house RLE and carrying their length nowhere, unpack to exactly 120 bytes.
In SCREEN 2 you normally put patterns at 0x0000 and colours at 0x2000. Here it is reversed, and the eight bytes the cartridge loads into the VDP registers say so (the table at 0x45F7, 02 E2 0E 7F 07 76 03 E0): R3=0x7F puts colours at 0x0000 and R4=0x07 patterns at 0x2000.
Reading it the wrong way round does not fail loudly: it gives correct shapes and striped colours. It is the classic trap of this mode.
The dispatch at 0x569F sends each type to its own routine:
The MSX1 can only show four sprites per line, and the ones that win are always the first in the table: the rest simply vanish.
The routine at 0x459A fixes that by dumping the table starting sixteen bytes further along each frame, wrapping at the end. Since the order keeps shifting, the sprite that loses is never the same one, and what you see is shared flicker instead of an invisible character.
The background animations have no alternative artwork in the ROM. The pattern already sitting in video memory is taken and its bits are rotated with rrca or rlca: one pixel of travel per turn, eight bytes per pattern.
The other variant shifts whole bytes one row with an lddr, wrapping the one that falls off.
0xE0B0 is two different things depending on when you look: while the zone is being built it holds the unpacked map, 120 bytes; during play it is the 32 sprite attributes, 128 bytes dumped in one go to 0x3B00 -where R5 puts its table-.
The same kilobyte does both jobs because they are never needed at the same time.
The routine at 0x41D5 looks up the zone number in the list of those carrying a big razzon and, failing to find it, prints the NO BIG RAZZON notice. It enters with ld b,00eh, that is fourteen turns, but from 0x609E to 0x60AA there are only thirteen bytes.
The fourteenth comparison already falls into the next block, zone 0's, and reads 0x08. The thirteen on the list run in ascending order and that 0x08 breaks it. The effect can be stated without guessing at intent: zone 8 matches too, and so it never gets the notice even though it is not on the list.
At 0x4575 sits a ten-byte routine that sets up a READ from video memory: the exact twin of the write one that is used. There is not a single call or jp to that address in the whole ROM, nor does it appear as a word in any table. It was left in.
Under each picture is where it comes from and what is on it.
inc d per cell. The colour comes from a 480-byte fill that alternates between two values, which is why the wordmark changes colourcp 00ch and cp 00ah the loop at 0x64CD counts withNO BIG RAZZON notice without being on the list