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.
Animals and seeds do not show up in the farm, if you hand in more than one at a time.
Castle Farm Bug
Bug Details
System(s) Playstation,
PSP,
PSN (POPS)
Bug TypeGameplay
Region Introduced
Patch Version2.01.065b

Regions Affected
Throughout the game, the player can collect farm animals that can be given to Yuzu in the castle garden. Likewise, plant seeds can be collected and passed to the gardener, Tony. When these items are handed in, they should be shown wandering the screen (in the case of animals) or growing in the garden the next time the player returns to the screen. This is what happens as long as you turn in only one of a particular type of item. Turn in two or more of a single item, for instance, two Cabbage Seeds, at the same time, and only one new set will be shown.

Cause
There are several copies of each item type that can be found throughout the game. The caretakers have some of them by default (Tony starts with a Cabbage and Potato Seed), but in general there are three available to find. When you turn in a seed, a count is updated, to track how many have been handed in. After the count is updated, the bit flags for the item are set based on the count. The problem is that when the count is 3, it only sets the bit for the third copy of the item. If you have handed in all three at once, that means it will immediately set the flag for the third set, leaving the first two unset.

A total of 25 items are available, three seeds each for Cabbage, Potatoes, Spinach, and Tomatoes; three Chicks, Pigs, and Cows; and four Sheep. Konami packs these bits into three bytes, which complicates retrieving and setting them, but not as much as their code would indicate. Here is how the data breaks down.

Item Type Count Address Flag 1 Flag 2 Flag 3 Flag 4
Address Bit Address Bit Address Bit Address Bit
Cabbage 0x8006AA2B 0x8006A91C 0 0x8006A91C 1 0x8006A91C 2
Potato 0x8006AA2C 0x8006A91C 3 0x8006A91C 4 0x8006A91C 5
Spinach 0x8006AA2D 0x8006A91C 6 0x8006A91C 7 0x8006A91D 0
Tomato 0x8006AA2E 0x8006A91D 1 0x8006A91D 2 0x8006A91D 3
Chick 0x8006AA2F 0x8006A91D 4 0x8006A91D 5 0x8006A91D 6
Pig 0x8006AA30 0x8006A91D 7 0x8006A91E 0 0x8006A91E 1
Sheep 0x8006AA31 0x8006A91E 2 0x8006A91E 3 0x8006A91E 4 0x8006A91E 5
Cow 0x8006AA31 0x8006A91E 6 0x8006A91E 7 0x8006A91F 0

The code below is taken from the routine that accepts seeds. It is slightly simpler, owing to the fact that there are only three of each kind of item it has to deal with. Still, it has to span bytes and handle the data in somewhat ugly ways. The snippet is after the counting of seeds in the party's inventory. There is nothing wrong with the way the count is done. All the relevant code is in /CDROM/110_ARK/VK19.BIN.

RAM:8015E198                 lbu     $a0, 0x1A2B($v1)
RAM:8015E19C                 li      $v0, 1
RAM:8015E1A0                 bne     $a0, $v0, loc_8015E1B4
RAM:8015E1A4                 nop
RAM:8015E1A8                 lbu     $v0, 0x191C($v1)
RAM:8015E1AC                 j       loc_8015E1E4
RAM:8015E1B0                 ori     $v0, 1
RAM:8015E1B4  # ---------------------------------------------------------------------------
RAM:8015E1B4
RAM:8015E1B4 loc_8015E1B4:                            # CODE XREF: TakeSeeds+134j
RAM:8015E1B4                 li      $v0, 2
RAM:8015E1B8                 bne     $a0, $v0, loc_8015E1CC
RAM:8015E1BC                 nop
RAM:8015E1C0                 lbu     $v0, 0x191C($v1)
RAM:8015E1C4                 j       loc_8015E1E4
RAM:8015E1C8                 ori     $v0, 2
RAM:8015E1CC  # ---------------------------------------------------------------------------
RAM:8015E1CC
RAM:8015E1CC loc_8015E1CC:                            # CODE XREF: TakeSeeds+14Cj
RAM:8015E1CC                 li      $v0, 3
RAM:8015E1D0                 bne     $a0, $v0, loc_8015E1E8
RAM:8015E1D4                 nop
RAM:8015E1D8                 lbu     $v0, 0x191C($v1)
RAM:8015E1DC                 nop
RAM:8015E1E0                 ori     $v0, 4
RAM:8015E1E4
RAM:8015E1E4 loc_8015E1E4:                            # CODE XREF: TakeSeeds+140j
RAM:8015E1E4                                          # TakeSeeds+158j
RAM:8015E1E4                 sb      $v0, 0x191C($v1)
RAM:8015E1E8
RAM:8015E1E8 loc_8015E1E8:                            # CODE XREF: TakeSeeds+164j
RAM:8015E1E8                 ori     $v1, $s7, 0x8000
RAM:8015E1EC                 lbu     $a0, 0x1A2C($v1)
RAM:8015E1F0                 li      $v0, 1
RAM:8015E1F4                 bne     $a0, $v0, loc_8015E208
RAM:8015E1F8                 nop
RAM:8015E1FC                 lbu     $v0, 0x191C($v1)
RAM:8015E200                 j       loc_8015E238
RAM:8015E204                 ori     $v0, 8
RAM:8015E208  # ---------------------------------------------------------------------------
RAM:8015E208
RAM:8015E208 loc_8015E208:                            # CODE XREF: TakeSeeds+188j
RAM:8015E208                 li      $v0, 2
RAM:8015E20C                 bne     $a0, $v0, loc_8015E220
RAM:8015E210                 nop
RAM:8015E214                 lbu     $v0, 0x191C($v1)
RAM:8015E218                 j       loc_8015E238
RAM:8015E21C                 ori     $v0, 0x10
RAM:8015E220  # ---------------------------------------------------------------------------
RAM:8015E220
RAM:8015E220 loc_8015E220:                            # CODE XREF: TakeSeeds+1A0j
RAM:8015E220                 li      $v0, 3
RAM:8015E224                 bne     $a0, $v0, loc_8015E23C
RAM:8015E228                 nop
RAM:8015E22C                 lbu     $v0, 0x191C($v1)
RAM:8015E230                 nop
RAM:8015E234                 ori     $v0, 0x20
RAM:8015E238
RAM:8015E238 loc_8015E238:                            # CODE XREF: TakeSeeds+194j
RAM:8015E238                                          # TakeSeeds+1ACj
RAM:8015E238                 sb      $v0, 0x191C($v1)
RAM:8015E23C
RAM:8015E23C loc_8015E23C:                            # CODE XREF: TakeSeeds+1B8j
RAM:8015E23C                 ori     $v1, $s7, 0x8000
RAM:8015E240                 lbu     $a0, 0x1A2D($v1)
RAM:8015E244                 li      $v0, 1
RAM:8015E248                 bne     $a0, $v0, loc_8015E264
RAM:8015E24C                 li      $v0, 2
RAM:8015E250                 lbu     $v0, 0x191C($v1)
RAM:8015E254                 nop
RAM:8015E258                 ori     $v0, 0x40
RAM:8015E25C                 j       loc_8015E29C
RAM:8015E260                 sb      $v0, 0x191C($v1)
RAM:8015E264  # ---------------------------------------------------------------------------
RAM:8015E264
RAM:8015E264 loc_8015E264:                            # CODE XREF: TakeSeeds+1DCj
RAM:8015E264                 bne     $a0, $v0, loc_8015E280
RAM:8015E268                 li      $v0, 3
RAM:8015E26C                 lbu     $v0, 0x191C($v1)
RAM:8015E270                 nop
RAM:8015E274                 ori     $v0, 0x80
RAM:8015E278                 j       loc_8015E298
RAM:8015E27C                 sb      $v0, 0x191C($v1)
RAM:8015E280  # ---------------------------------------------------------------------------
RAM:8015E280
RAM:8015E280 loc_8015E280:                            # CODE XREF: TakeSeeds:loc_8015E264j
RAM:8015E280                 bne     $a0, $v0, loc_8015E298
RAM:8015E284                 nop
RAM:8015E288                 lbu     $v0, 0x191D($v1)
RAM:8015E28C                 nop
RAM:8015E290                 ori     $v0, 1
RAM:8015E294                 sb      $v0, 0x191D($v1)
RAM:8015E298
RAM:8015E298 loc_8015E298:                            # CODE XREF: TakeSeeds+20Cj
RAM:8015E298                                          # TakeSeeds:loc_8015E280j
RAM:8015E298                 ori     $v1, $s7, 0x8000
RAM:8015E29C
RAM:8015E29C loc_8015E29C:                            # CODE XREF: TakeSeeds+1F0j
RAM:8015E29C                 lbu     $a0, 0x1A2E($v1)
RAM:8015E2A0                 li      $v0, 1
RAM:8015E2A4                 bne     $a0, $v0, loc_8015E2B8
RAM:8015E2A8                 nop
RAM:8015E2AC                 lbu     $v0, 0x191D($v1)
RAM:8015E2B0                 j       loc_8015E2E8
RAM:8015E2B4                 ori     $v0, 2
RAM:8015E2B8  # ---------------------------------------------------------------------------
RAM:8015E2B8
RAM:8015E2B8 loc_8015E2B8:                            # CODE XREF: TakeSeeds+238j
RAM:8015E2B8                 li      $v0, 2
RAM:8015E2BC                 bne     $a0, $v0, loc_8015E2D0
RAM:8015E2C0                 nop
RAM:8015E2C4                 lbu     $v0, 0x191D($v1)
RAM:8015E2C8                 j       loc_8015E2E8
RAM:8015E2CC                 ori     $v0, 4
RAM:8015E2D0  # ---------------------------------------------------------------------------
RAM:8015E2D0
RAM:8015E2D0 loc_8015E2D0:                            # CODE XREF: TakeSeeds+250j
RAM:8015E2D0                 li      $v0, 3
RAM:8015E2D4                 bne     $a0, $v0, loc_8015E2F0
RAM:8015E2D8                 li      $v0, 1
RAM:8015E2DC                 lbu     $v0, 0x191D($v1)
RAM:8015E2E0                 nop
RAM:8015E2E4                 ori     $v0, 8
RAM:8015E2E8
RAM:8015E2E8 loc_8015E2E8:                            # CODE XREF: TakeSeeds+244j
RAM:8015E2E8                                          # TakeSeeds+25Cj
RAM:8015E2E8                 sb      $v0, 0x191D($v1)
RAM:8015E2EC                 li      $v0, 1

Fix
There are so many different and better ways this could have been handled. It seems like the developer was trying to create an easily expanded routine, as if the final number of these items was unknown at the time. Even assuming that, this is bad. It seems like it was coded by someone unaware of how to work with data at the level of bits, which is bit of a theme with Suikoden II.

There really is not an easy way to modify the existing routine to work correctly. So it had to be rewritten. This is actually pretty easy to do. The existing routine is huge and bloated, and can be replaced with a routine about a third of the size. Code just needs to be inserted after the inventory count, to replace the setting of flags.

.openfile VK19.BIN, 0x8015DC50
.headersize 0
.org 0x8015E198
; file location will be 0x540
 
; start with cabbage.
cabbage:
    lbu v0, 0x1A2B(v1)                ; cabbage count
    lw s4, 0x191C(v1)                ; flags (seeds and stock)
    li s6, 7                    ; mask base
    li s5, 3                    ; max count  (this will keep)
    subu v0, s5, v0                    ; shift amount
    srlv v0, s6, v0                    ; 0x7 >> (3 - cabbage count)
    or s4, s4, v0                    ; flags |= mask
potato:
    lbu v0, 0x1A2C(v1)                ; count
    li s6, 7                    ; load delay
    subu v0, s5, v0
    srlv v0, s6, v0
    sll v0, v0, 3                    ; finish mask
    or s4, s4, v0
 
spinach:
    lbu v0, 0x1A2D(v1)                ; count
    li s6, 7                    ; load delay
    subu v0, s5, v0
    srlv v0, s6, v0
    sll v0, v0, 6                    ; finish mask
    or s4, s4, v0
tomato:
    lbu v0, 0x1A2E(v1)                ; count
    li s6, 7                    ; load delay
    subu v0, s5, v0
    srlv v0, s6, v0
    sll v0, v0, 9                    ; finish mask
    or s4, s4, v0
store:
    sw s4, 0x191C(v1)
    beq zero, zero, 0x8015E2EC            ; skip the rest
    nop
.close

The above takes the counts, and uses them to construct an appropriate mask that will be used to set the required bits in the game's data. It sets all the bits indicated by the counts, each time the routine is called. In this way, you can turn in none or all the seeds at one time, and the flags will be retained or set as needed. It also treats the entire 32-bit value allocated to the farm flags (both seeds and livestock) as a single variable. Doing this, the code does not need to worry about moving ahead bytes. It just has to set the right bits in the data. Since the only modification done to the flags is a bitwise OR, it can never unset anything by accident.