Suikoden II Bug: Suikoden I Hero Name Is Mangled
This was one of the first bugs discovered in
Suikoden II. When you load save data from
Suikoden I, you get certain bonuses, including a side quest that lets you add the hero from the
Suikoden I to your party. Anyone loading this data will most likely be disappointed to find that the name is horribly mangled, containing some combination of the name they used and characters from the string "McDohl".
This bug was not present in the Japanese version, because the character sets are entirely different. It was fixed in the European versions.
Cause
During the load, the game must copy and re-encode the name, since the original used a different character set. By default, the destination string allows for up to 7 bytes (8 including the terminating null), and contains "McDohl" by default. During the copy, a coding error results in all lowercase letters being bypassed, and the routine neither copies nor inserts a terminating null. The result is that the name contains any capital letters from the player's chosen name, and whatever characters from the default string that were left unmodified. Famously, the result is "TcDohl", as the
Suikoden novelization gives the protagonist the name "Tir".
Below is the routine responsible, with a few comments. They have to make a number of adjustments, because of the odd ways in which they modified the character set from game to game.
RAM:80110E0C strcpyS1toS2: # CODE XREF: RAM:8010F92Cp
RAM:80110E0C # RAM:8010F944p ...
RAM:80110E0C blez $a2, locret_80110E70
RAM:80110E10 move $a3, $0
RAM:80110E14
RAM:80110E14 loc_80110E14: # CODE XREF: strcpyS1toS2+5Cj
RAM:80110E14 addu $v0, $a0, $a3 # This whole thing fails to take terminating nulls into account.
RAM:80110E18 lbu $v1, 0($v0)
RAM:80110E1C nop
RAM:80110E20 addiu $v0, $v1, 0xFFF0
RAM:80110E24 sltiu $v0, 0x1B # Check for lower case.
RAM:80110E28 bnez $v0, loc_80110E60 # #Skip it, if lowercase. Oops.
RAM:80110E2C addiu $v0, $v1, 0xFFD5
RAM:80110E30 sltiu $v0, 0x1A
RAM:80110E34 bnez $v0, loc_80110E5C
RAM:80110E38 addiu $v0, $v1, 0x10
RAM:80110E3C addiu $v0, $v1, 0xFFBB
RAM:80110E40 sltiu $v0, 0x13
RAM:80110E44 bnez $v0, loc_80110E5C
RAM:80110E48 addiu $v0, $v1, 0x53
RAM:80110E4C addiu $v0, $v1, 0xFFA8
RAM:80110E50 sltiu $v0, 0x15
RAM:80110E54 beqz $v0, loc_80110E60
RAM:80110E58 addiu $v0, $v1, 0x10
RAM:80110E5C
RAM:80110E5C loc_80110E5C: # CODE XREF: strcpyS1toS2+28j
RAM:80110E5C # strcpyS1toS2+38j
RAM:80110E5C sb $v0, 0($a1)
RAM:80110E60
RAM:80110E60 loc_80110E60: # CODE XREF: strcpyS1toS2+1Cj
RAM:80110E60 # strcpyS1toS2+48j
RAM:80110E60 addiu $a3, 1
RAM:80110E64 slt $v0, $a3, $a2
RAM:80110E68 bnez $v0, loc_80110E14
RAM:80110E6C addiu $a1, 1
RAM:80110E70
RAM:80110E70 locret_80110E70: # CODE XREF: strcpyS1toS2j
RAM:80110E70 jr $ra
RAM:80110E74 nop
Essentially, they branch 1 operation too far after determining that the character is lowercase. The problem that remains is the lack of support for terminating nulls.
Fix
Ideally, the destination string would be initialized to binary zeroes before even attempting to copy. Unfortunately, the code is pretty tight here, and can't be easily modified to make a function call. In the end, the best solution was to insure that the terminating nulls from the
Suikoden I string are copied like any other character. Even that required rewriting the entire routine, so that the necessary operations could be safely inserted.
The fix eliminates the check on the destination pointer. This would be potentially dangerous, except for the fact that this code is only called from three places in one module, and in all cases the destination is a non-zero address.
GameShark Code
A GameShark Code for this is not practical. It would be over 100 lines long. There are already codes that will allow you to fix the name after it has been mangled, by directly overwriting it.
Patch
See the Patch Files page for your version.