Table of Contents

Suikoden II Bug: Guardian Deity Plans
Cause
Fix

Suikoden II Bug: Guardian Deity Plans


This bug is a bit hypothetical. In investigating other bugs, it has been discovered that the code that manages Guardian Deity Plans is badly flawed. Triggering this bug would require a combination of bad luck, and waiting to acquire the plans until very late in the game. Most people will never run afoul of this problem, because the character the Plans are used with is not recruited until very late in the game.

This bug affects all versions.

Cause


When Guardian Deity Plan are handed into Jude, bit-flags are set to indicate this. These flags will inform other aspects of the game that it is no longer appropriate for these plans to be dropped by enemies. There are sixteen plans in total, which means two bytes are necessary to indicate the status of all plans. However, the way the check was coded, it will examine four bytes, and only the first four bits of each. So the first four plans will be checked properly; the second set of four will be checked against the flags for the third set of four, and the last eight plans will be checked against flags that aren't even for plans.

This code resides in /CDROM/150_BPRG/BUFF0/BP0_AFT.BIN
RAM:8002D8A0 BlueprintFlags:                          # CODE XREF: OnetimeFlags+D8j
RAM:8002D8A0                 sltiu   $v0, $a0, 0x10   # is item a plan?
RAM:8002D8A4                 beqz    $v0, WindowFlags # if no, check windows
RAM:8002D8A8                 move    $v1, $a0
RAM:8002D8AC                 bgez    $v1, loc_8002D8B8# this check is pointless
RAM:8002D8B0                 move    $v0, $v1
RAM:8002D8B4                 addiu   $v0, $s3, 0xFFE8
RAM:8002D8B8
RAM:8002D8B8 loc_8002D8B8:                            # CODE XREF: OnetimeFlags+108j
RAM:8002D8B8                 sra     $v0, 2           # Shift blueprint number right 2.  Intended to set the byte number.
RAM:8002D8BC                 sll     $v1, $v0, 2      # Shift the result left 2.  This will be used to calculate the bit shift amount.
RAM:8002D8C0                 addu    $v0, $s4, $v0    # Add byte number to base address
RAM:8002D8C4                 lbu     $v0, 0x1FA($v0)  # Load flags byte
RAM:8002D8C8                 subu    $v1, $a0, $v1    # Subtract result of left shift from recipe number.  This is the shift amount.
RAM:8002D8CC                 srav    $v0, $v1         # Shift the desired bit into the lowest-order position
RAM:8002D8D0                 andi    $v0, 1           # Isolate bit.
RAM:8002D8D4                 bnez    $v0, loc_8002D92C# If bit is on, plan was handed in.
RAM:8002D8D8                 li      $v0, 1
The code determines what byte the flag is in, so it can load it, then it determines what bit number within the byte will represent that plan. If the bit is 1, then you already handed it over to Jude. This code behaves as though every byte consists of only four bits. Therefore, the first four plans are checked properly, and thereafter the wrong byte is being analyzed. Furthermore, only the four least-significant bits in every byte can be analyzed.

Bonus: Not only does it analyze the wrong bytes, when setting the flags, Konami swapped the Rabbit and Turtle Plans around. As the highest item numbers, the Turtle plans should take up the uppermost 4 bits, but they are instead indicated by the least-significant 4 bits.

Flags are at 0x8006AA3A, occupying 16-bits (half-word).
All items are type 5 with quantity 0 (0x50).
Bit Offset
Item Digit
Plan Number
Plan Name
0
0x1B
1
Dragon Plans #1
1
0x1C
2
Dragon Plans #2
2
0x1D
3
Dragon Plans #3
3
0x1E
4
Dragon Plans #4
4
0x1F
5
Unicorn Plans #1
5
0x20
6
Unicorn Plans #2
6
0x21
7
Unicorn Plans #3
7
0x22
8
Unicorn Plans #4
8
0x27
13
Turtle Plans #1
9
0x28
14
Turtle Plans #2
10
0x29
15
Turtle Plans #3
11
0x2A
16
Turtle Plans #4
12
0x23
9
Rabbit Plans #1
13
0x24
10
Rabbit Plans #2
14
0x25
11
Rabbit Plans #3
15
0x26
12
Rabbit Plans #4

As you can see, it goes from item 0x22 to 0x27. The flag number is calculated in the check routines by first subtracting 0x1B from the Item Digit. However, the calculation cannot be so simple here, because they didn't keep the linear increases consistent. Setting flags is typically done by including a byte index and a bit mask, so this would be an easy mistake to make. Somebody forgot which set of four came first, and then the person responsible for the bit-flag check routines did their usual botched job.


Fix


The fix is to modify the code so that it behaves as though a byte has 8 bits. This can be done by simply modifying the two shift instructions used to determine the byte index and bit shift value. However, as of this writing, the fix has not been implemented or tested. There is an extremely remote possibility that the code is intentional and correct, and due to the aforementioned lateness with which Jude joins, it is likely that very few people would have had the opportunity to notice this bug. There are a few sparse reports of issues with finding plans, but they were typically attributed to bad luck and the matter dropped. Compared to the Recipes Bug this is totally invisible.

In a test play-through, Jude is about to recruited. At which time it will be possible to analyze the flags as they are set. If the supposition presented here turns out to be correct, the bug-fix will be a two-byte change in the patch file. GameShark codes will also work, but hardly anyone will need them.

With the additional bug involving the setting of the flags, this becomes more complicated to fix. The routine has been recoded to access the flags as a single half-word, and checks have been added to calculate the bit offset correctly. This will require specialized testing in-game. It must be played so that none of the plans are acquired before Jude is recruited, and then checked with and without the fix.