All of these bugs were due to the same cause: The Smilesoft, Comic BomBom, and Natsume logos were disabled in the bootlegs, skipping straight to the title screen; therefore, the patch restores the logos to accomplish the bug fixes. (I had long suspected that disabling the logos was responsible for the game over and the A+B+Select+Start crashes, but I couldn't prove it until now.) Removing the logos was obviously done to remove any credit given to them (which is sort of a good thing, as the most of the naive people who bought the bootlegs would think they were responsible for the awful translation and glitches). However, the way it was removed was incredibly sloppy.
First of all, the way the logo screens were disabled (they aren't actually removed, just made inaccessible) are different between Diamond and Jade, suggesting the bootleggers were disorganized. Yes, it's inconsistent, and that's why Diamond has more bugs than Jade does. I'll go over Diamond's method first.
First, here is code for Power, Speed, and Jade:
Code: Select all
ROM0:1C14 3E 02 ld a,02 ;Switch bank to 02 (0x8000-0xBFFF in ROM is copied to 0x4000-0x7FFF in RAM)
ROM0:1C16 EA 23 C4 ld (C423),a
ROM0:1C19 D7 rst 10
ROM0:1C1A C3 00 53 jp 5300 ;Load Smilesoft/Comic BomBom/Natsume screens
Code: Select all
ROM0:1C14 EA E1 C3 ld (C3E1),a ;(C3E1) has an effect on the screen that shows up.
;However, due to this code, (C3E1) = 0x14 after exiting Game Over screen!!
;Notice that the last byte of this address (0x1C14) is also 0x14 -- this
;is not a coincidence! (See code at 0x1BE2 to see why -- clearly the
;testers hadn't intended for the code there to jump to here.)
ROM0:1C17 3E 01 ld a,01
ROM0:1C19 EA E0 C3 ld (C3E0),a ;Not completely sure what (C3E0) does or why Diamond needs to set it to 01
ROM0:1C1C C9 ret ;Return to function caller; this effectively skips the logo screens at the
;beginning
It turns out that replacing this section of code with the code in Power/Speed/Jade (which is what the Diamond patch at the bottom of this post does) is enough to restore the logos and fix all three bugs! I'll explain why this is later.
Now let's look at what Jade does.
Here is code from Power, Speed, and Diamond:
Code: Select all
ROM2:5300 FA E1 C3 ld a,(C3E1) ;Used for finding the right pointer in a pointer table
ROM2:5303 21 0A 53 ld hl,530A ;0x530A (0x930A in ROM) is where some pointer table starts
ROM2:5306 CD 97 0E call 0E97 ;Get pointer to determine where program should go next
ROM2:5309 E9 jp hl ;Jump to 0x93BD for Smilesoft screen; 0x94C5 for title screen
This is the code for Jade:
Code: Select all
ROM2:5300 FA E1 C3 ld a,(C3E1) ;Used for finding the right pointer in a pointer table
ROM2:5303 C3 E0 7F jp 7FE0 ;Hijack original routine by adding additional code
ROM2:5306 CD 97 0E call 0E97 ;Get pointer to determine where program should go next
ROM2:5309 E9 jp hl ;Jump to 0x93BD for Smilesoft screen; 0x94C5 for title screen
ROM2:7FE0 FE 02 cp a,02
ROM2:7FE2 20 05 jr nz,7FE9 ;If (C3E1) != 0x02 then do not change it
ROM2:7FE4 3E 15 ld a,15 ;Otherwise, if (C3E1) == 0x02, then change it to 0x15
ROM2:7FE6 EA E1 C3 ld (C3E1),a ;Set (C3E1) to 0x15;
;This is what skips the Smilesoft/Natsume/Comic BomBom logos in
;Jade because the bootleggers don't want to give them any credit
ROM2:7FE9 21 0A 53 ld hl,530A ;0x530A (0x930A in ROM) is where some pointer table starts
ROM2:7FEC C3 06 53 jp 5306 ;Go back
As before, replacing 0x9303-0x9305 with the original Japanese code will load the title screen, and consequently fix the colors in the intro. This is what the Jade patch at the bottom of this post does!
Now why does disabling the logo screens cause so many bugs? Let's start with the glitchy color palettes in the intro, which is the least obvious one.
It turns out that since the logos are skipped in the bootlegs, it also skips writing to a byte in RAM that is later necessary to use the proper colors.
First, when the game starts up, this code gets executed, in ALL versions.
Code: Select all
ROM0:159F AF xor a ;XOR a with itself. This makes a = 0.
ROM0:15A0 22 ldi (hl),a ;hl = DD06, so at startup, (DD06) = 0 in ALL versions
Now, this code is executed as long as the Smilesoft screen appears:
Code: Select all
ROM2:53D0 3E 01 ld a,01
ROM2:53D2 EA 06 DD ld (DD06),a ;Set (DD06) to 1; this only happens on the Smilesoft screen, so this
;gets skipped in bootlegs
Let's look at more code:
Code: Select all
ROM0:0B1A F5 push af ;Save current value of a for later (there should be a pop af later on)
ROM0:0B1B FA 06 DD ld a,(DD06) ;Read from (DD06)
ROM0:0B1E B7 or a ;Is (DD06) == 0?
ROM0:0B1F CA 9E 0B jp z,0B9E ;If so, then skip routine the generates palettes
Spoiler!
Code: Select all
ROM4:4089 3E 01 ld a,01
ROM4:408B EA 06 DD ld (DD06),a ;Set (DD06) to 1; this happens on the D-Shot screen, so even
;bootlegs reach this code
It also turns out that if you get a Game Over in Jade, the intro will load the proper colors afterwards. I didn't know that before looking at this code, but you can see for yourself.
Now as for crashing after the Game Over screen: This is more complicated...
Let's look at the code here, which gets executed very frequently throughout the game (this is identical in all versions).
Code: Select all
ROM0:1BE2 FA E0 C3 ld a,(C3E0) ;Get value from (C3E0)
;0x0E on Game Over screen (all versions)
;0x00 just after exiting Game Over screen (all versions)
ROM0:1BE5 21 F4 1B ld hl,1BF4 ;0x1BF4 = Base pointer
ROM0:1BE8 16 00 ld d,00
ROM0:1BEA 5F ld e,a
ROM0:1BEB CB 23 sla e ;Multiply value from (C3E0) by 2
ROM0:1BED CB 12 rl d
ROM0:1BEF 19 add hl,de ;Add to pointer to get another pointer
;Just after exiting Game Over screen: 0x1BF4 + 0 * 2 = 0x1BF4
ROM0:1BF0 2A ldi a,(hl) ;Read little endian pointer
ROM0:1BF1 66 ld h,(hl)
ROM0:1BF2 6F ld l,a ;0x1BF4 returns pointer of 0x1C14
ROM0:1BF3 E9 jp hl ;Jump to pointer
Note that, at address 0x1BF0, the lower byte (0x14) gets assigned to register a, which causes problems for Diamond once it goes to 0x1C14. Scroll up to the second code block and look at it -- since a is 0x14, this gets written to 0xC3E1!! (As you can see, only Diamond writes to 0xC3E1 here.) This causes problems, as you will soon see...
Code: Select all
ROM2:493F FA E1 C3 ld a,(C3E1) ;(C3E1) = 14 in Diamond after Game Over screen; 0 in everything else!!
ROM2:4942 21 49 49 ld hl,4949 ;Base pointer: 0x8949 in ROM
ROM2:4945 CD 97 0E call 0E97 ;In Power/Speed/Jade: Reads from ROM address 0x8949 + 2*0x0 = 0x8949.
; Reads pointer at 0x8949 and returns 0x496F; this translates to 0x896F in ROM
; (since we are in ROM bank 2).
;In Diamond: Reads from ROM address 0x8949 + 2*0x14 = 0x8971.
; Reads pointer at 0x8971 and returns 0xCD00;
; this translates to 0xCD00 in RAM!!!
ROM2:4948 E9 jp hl ;In Power/Speed/Jade: Program jumps to 0x896F to load title screen.
;In Diamond: Program jumps to 0xCD00 and eventually crashes!!!
Code: Select all
ROM0:0E97 06 00 ld b,00
ROM0:0E99 4F ld c,a ;Get value from (C3E1)
ROM0:0E9A CB 21 sla c ;Multiply by 2
ROM0:0E9C CB 10 rl b
ROM0:0E9E 09 add hl,bc ;Add to pointer from before
;When called from 0x9306:
; Smilesoft screen: 0x930A + 2*0x2 = 0x930E;
; title screen: 0x930A + 2*0x15 = 0x9334
;When called from 0x8945:
; Power/Speed/Jade: 0x8949 + 2*0x0 = 0x8949; Diamond: 0x8949 + 2*0x14 = 0x8971
ROM0:0E9F 2A ldi a,(hl) ;Read little-endian pointer
ROM0:0EA0 66 ld h,(hl) ;
ROM0:0EA1 6F ld l,a ;When called from 0x9306:
; Smilesoft screen: 0x930E returns 0x93BD; Title screen: 0x9334 returns 0x94C5
;When called from 0x8945:
; Power/Speed/Jade: 0x8949 returns 0x896F;
; Diamond: 0x8971 returns 0xCD00 in RAM!!
ROM0:0EA2 C9 ret ;Return
But in Diamond, the pointer is at 0x8949 + 2*0x14, which is... 0x8971. I'm not sure if this is even meant to be a pointer, but in any case, the values are 00 CD (at least in Diamond -- in Power, it's 09 CD -- this difference is strange in and of itself, but that's beside the point), which translates to 0xCD00 in RAM. So, the program will jump here, even though it's not supposed to. There are lots of "nop" instructions (which do nothing), but eventually the game will crash since it will come across some invalid instruction sooner or later (which depends on the current values in RAM).
As for A+B+Select+Start? I haven't really looked in great detail why this occurs, but since restoring the logos fixes this bug, it's probably related to the Game Over screen glitch. One thing is for certain: Like the other bugs, it's due to the removal of the company logos.
This was fun to reverse engineer, and I hope you enjoy the small but useful patches. It's amazing how the bootleggers care so much about removing any traces of the original creators of the game, and yet do it so sloppily that it causes bugs not originally present. Obviously they just cared about making money and not about the quality of the end product. But that's obvious, right?
One final thing: Try the GameShark code 01xx06DD. Replace xx with 00 in the Japanese games, or xx with 01 in the non-patched bootleg games, then watch the intro. See anything interesting? (Actually, replacing xx with 00 is fun to try in both games, in various screens, not just the intro!