Remote linking to avatars
Do not link to Suikosource images on forums, webpages, or anyplace else. If you wish to use the images, place them in your own webspace. We do not allow you to use them from our server.
Randomly appearing Recipes, such as Recipe #34, can become impossible to acquire.
Recipes Bug
Bug Details
System(s) Playstation,
PSP,
PSN (POPS)
Bug TypeGameplay
Region Introduced
Patch Version2.01.065b

Regions Affected
This bug is one of the more frustrating problems that players can encounter in Suikoden II. Recipes are items obtained during story events, from chests, random people, bookshelves, enemy drops, shop rare finds, etc. If the designers decided they could place items in an object, chances are at least one recipe can be found in an instance of it. This bug can make it impossible to find certain recipes. It also makes it possible to obtain duplicate copies of some recipes.

Cause
This bug has variously been attributed to getting Recipe #X before Recipe #Y, handing recipes to Hai Yo, and twirling the wrong color cat in a graveyard at the full moon. The reason this bug is so annoying is that five of the recipes are rare drops from enemies, so it is difficult to tell if you are being denied by bad luck, or the bug. Recipe #34 famously becomes unobtainable unless great care is taken in dealing with recipes.

The underlying cause of the bug is a simple programming error. There is a function that checks the bit flags that indicate a recipe has been given to Hai Yo. This is used when determining if it is appropriate for an enemy to drop a recipe, and is also checked to see if a recipe should appear in Rare Finds in a shop. Code for North American (NTSC/UC) version is shown below, with commentary that illuminates the problem. This code resides in /CDROM/150_BPRG/BUFF0/BP0_AFT.BIN.

RAM:8002DA18                 bnez    $a1, loc_8002DAB0        <- Check the item type for zero.
RAM:8002DA1C                 move    $v0, $0
RAM:8002DA20                 addiu   $v0, $a0, 0xFFC8        <-Essentially chop out the bottom of type-zero items by adding -0x38
RAM:8002DA24                 andi    $v0, 0xFF
RAM:8002DA28                 sltiu   $v0, 0x10            <- If the result is a value less than 0x10, it's one of the recipes.
RAM:8002DA2C                 beqz    $v0, loc_8002DAAC        <- Get out if it's not a recipe.
RAM:8002DA30                 andi    $v0, $v1, 0xFF          <- Clear out the high-order bits of the item index/digit.
RAM:8002DA34                 addiu   $a1, $v0, 0xFFE1        <- Add -0x1F (-31)...this gives the recipe #, but it's wrong.  It should be -32.
RAM:8002DA38                 bgez    $a1, loc_8002DA44        <- This should always be true, given previous logic.
RAM:8002DA3C                 move    $v1, $a1
RAM:8002DA40                 addiu   $v1, $v0, 0xFFE8
RAM:8002DA44
RAM:8002DA44 loc_8002DA44:
RAM:8002DA44                 sra     $s2, $v1, 3        <- Get the byte offset.
RAM:8002DA48                 move    $v1, $s2            <- Save the byte offset.
RAM:8002DA4C                 sll     $v0, $v1, 3        <- This line and...
RAM:8002DA50                 subu    $s2, $a1, $v0        <- This line establish the bit number within the byte.
RAM:8002DA54                 move    $s3, $v1            <- Save the bit number.
RAM:8002DA58                 la      $s1, sub_800D4CBC        <- The next few lines are all debug prints.
RAM:8002DA60                 la      $a0, aBitValDNoDShif
RAM:8002DA68                 move    $a2, $s2
RAM:8002DA6C                 move    $a3, $s3
RAM:8002DA70                 lui     $s0, 0x8004
RAM:8002DA74                 jalr    $s1
RAM:8002DA78                 sw      $s1, off_8003AEF0
RAM:8002DA7C                 sw      $s1, off_8003AEF0
RAM:8002DA80                 addu    $s0, $s2, $s4        <-Adds the bit number to the flag address.  Should be byte number.
RAM:8002DA84                 lui     $a0, 0x8003        <-More debug print screen crap coming up.
RAM:8002DA88                 lbu     $a1, 0x1E6($s0)        <-Load the flag byte for printing.
RAM:8002DA8C                 jalr    $s1
RAM:8002DA90                 la      $a0, aFoodFlg8b
RAM:8002DA94                 lbu     $v1, 0x1E6($s0)        <-Load flag byte so bit within can be checked, this address will be wrong.
RAM:8002DA98                 nop
RAM:8002DA9C                 srav    $v1, $s3            <-Shift the flags by the byte number.  Should be bit number, but even that's wrong.
RAM:8002DAA0                 andi    $v1, 1            <-Clear all bits except the flag bit we want.
RAM:8002DAA4                 bnez    $v1, loc_8002DAB0        <-Go to exit if found, return the 1 set below.
RAM:8002DAA8                 li      $v0, 1
RAM:8002DAAC
RAM:8002DAAC loc_8002DAAC:
RAM:8002DAAC
RAM:8002DAAC                 move    $v0, $0            <-Otherwise, return not found (i.e., you can get the recipe in battle).
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 recipe. If the bit is 1, then you already handed it over to Hai Yo. The problem is, they determine both numbers in a way that is incorrect, and then they use the incorrect numbers wrong by treating the bit number as the byte offset, and the byte offset as the bit number. When they initially calculate the numbers, it is done in such a way that one bit per byte seems not to exist (the last one), and the byte number comes up one off for many recipes. They compute the bit number, and forget that you do not find "bit 1" of byte 4 by right-shifting the value of byte 4 by 1, because that actually puts the second bit into the first position. It is a cavalcade of really dumb mistakes, and it is a miracle that any recipes drop at all after you give a few to Hai Yo.

This routine will determine that Recipe #34 is handed into Hai Yo if the third byte's 5th bit is set. This actually indicates Recipe #21, which is the one the Land Sharks in the Two River Sewers drop. The exact same routine is duplicated for Recipes #1-24, which are a different item type, so a different subtrahend must be used. For whatever reason, the flags are set properly, but checking them is a mess.

Breakdown of Mangled Checks

Acquired Check Recipe Flag At
Recipe Gotten How? Byte Bit Actual Recipe
Recipe #1 (Tomago-Yaki) (Event) Hai Yo joins 1 0 Recipe #9
Recipe #2 (Tomato Soup) (Event) Cook-off 1 2 0 Recipe #17
Recipe #3 (Ohitashi) (Speak) Huan in Muse 3 0 Recipe #25
Recipe #4 (Salad) (Event) Hai Yo joins 4 0 Recipe #33
Recipe #5 (Gyoza) (Speak) Cook in Coronet Inn 5 0 Unknown Data
Recipe #6 (Chowder) (Event) Hai Yo joins 6 0 Unknown Data
Recipe #7 (BBQ Meat Bun) (Event) Hai Yo joins 7 0 Unknown Data
Recipe #8 (Buttered Clams) (Event) Cook-off 2 0 1 Recipe #2
Recipe #9 (Fish Fry) (Search) Kuskus bookshelf 1 1 Recipe #10
Recipe #10 (Ice Cream) (Event) Hai Yo joins 2 1 Recipe #18
Recipe #11 (Quiche) (Rare Find) Kuskus Item shop 3 1 Recipe #26
Recipe #12 (Sandwich) (Drop) Eagle Man, Kobold Forest 4 1 Recipe #34
Recipe #13 (Meat Pie) (Speak) Cook in Kobold Village Chief's tent 5 1 Unknown Data
Recipe #14 (Simmered Fish) (Speak) Cook in Radat Tavern 6 1 Unknown Data
Recipe #15 (Fried Fish Balls) (Event) Hai Yo joins 7 1 Unknown Data
Recipe #16 (Sunomono) (Search) Lakewest, Shelf in Taki's house 0 2 Recipe #3
Recipe #17 (Cake) (Event) Cook-off 3 1 2 Recipe #11
Recipe #18 (Croquettes) (Rare Find) Radat Item Shop 2 2 Recipe #19
Recipe #19 (Pasta) (Event) Cook-off 4 3 2 Recipe #27
Recipe #20 (Tempura) (Speak) Cook in Greenhill Inn 4 2 Recipe #35
Recipe #21 (Grilled Fish) (Drop) Land Sharks in Two River Sewers 5 2 Unknown Data
Recipe #22 (Gratin) (Event) Cook-off 6 6 2 Unknown Data
Recipe #23 (Rice Omelet) (Rare Find) Two River Item Shop 7 2 Unknown Data
Recipe #24 (Fried Rice) (Event) Cook-off 5 0 3 Recipe #4
Recipe #25 (Pizza) (Rare Find) Greenhill Item Shop 1 3 Recipe #12
Recipe #26 (Teriyaki) (Rare Find) Highway Village Item Shop 2 3 Recipe #20
Recipe #27 (Tonkatsu) (Event) Cook-off 8 3 3 Recipe #28
Recipe #28 (Curry Rice) (Rare Find) Gregminster Item shop 4 3 Recipe #36
Recipe #29 (Grilled Beef) (Drop) Zombie Slug in Matilda Path 5 3 Unknown Data
Recipe #30 (Ramen) (Event) Cook-off 7 6 3 Unknown Data
Recipe #31 (Hamburger) (Rare Find) Kobold Village Item Shop 7 3 Unknown Data
Recipe #32 (Obento) (Speak) Kent's mother in Highway Village 0 4 Recipe #5
Recipe #33 (Sushi) (Event) Cook-off 10 1 4 Recipe #13
Recipe #34 (Japanese Stew) (Drop) DoReMi Elves in Greenhill Forest Path 2 4 Recipe #21
Recipe #35 (Full Course) (Rare Find) Muse Item shop 3 4 Recipe #29
Recipe #36 (Ghengis Khan) (Drop) Highland Soldiers in Rockaxe 4 4 Recipe #37
Recipe #37 (Steak) (Search) Gorudo's room in Rockaxe 5 4 Unknown Data
Recipe #38 (Sashimi Combo) (Event) Cook-off 11 6 4 Unknown Data
Recipe #39 (Special Stew) (Speak) Gremio in Gregminster 7 4 Unknown Data
Recipe #40 (Kaiseki Dinner) (Event) Cook-off 12 0 5 Recipe #6

Fix
The fix is fairly small, if a bit confusing. The code must be modified so that it subtracts 32 in initially determining the recipe's position, and then it must be further modified so that it uses the byte index and bit shift values for their intended purposes.