The final battle with Luca Blight is one of the most difficult fights in the game. Luca can attack three times per turn. He has a three-hit combination with his sword that does enormous damage to one person, a special move that attacks one column of the party for high damage with a fire element bonus, and a second, nearly identical special move that hits one row for slightly less damage per person. Luca can easily mow down most parties, unless the player prepares thoroughly, or invests a fair amount of time leveling up characters. However, there is a bug that can be exploited for an easy win.
Luca uses a short-range weapon, and all of his attacks must target the front row. Normally, this wouldn't be an issue because the game will not allow you to place characters in the back row until the front row is filled. Unfortunately for Konami, during the events leading up to the Luca battle, a special version of the Party Change module is run that doesn't fully enforce this rule.
Exploit
After the major battle with Luca, the party is automatically emptied, and the Hero is placed in his customary spot, leftmost in the front row. The next event will involve setting up an ambush for Luca Blight. AFter choosing to deploy, the player will have to select members for three parties, one led by the Hero, one by Viktor, and the last led by Flik. In order to exploit the bug, the player must delay selecting these parties, and instead go to Leona in the tavern. Once there, form a party with the hero in the leftmost spot in the back row (position 4). The party should be formed without using Viktor or Flik (Viktor should not be available anyway). Using them can break the exploit. Other than that, it does not matter who is used, as the event will purge them anyway. After forming the party, return to Shu and continue the events. When selecting the hero's party, don't add or remove anyone. Instead, exit the menu immediately. The formation menu will appear, and the hero will be alone in the party and in the back row. When his party fights Luca, it will be impossible for him to attack (although he can counter), and the player can slowly whittle away Luca's health without any real danger.
Bug
In this situation, where a special module must manage three parties, the bug is that the programmer assumed that no player in his/her right mind would form anything less than a full party to take on Luca, and they'd certainly never let the Hero go alone. It's dangerous. Normally, when even a single character is removed, the party is reorganized so that the front row is filled, and any empty spots are shifted to the back row. There's a convenient function that does all this work. It just isn't called by the special module after emptying the Hero's party. Viktor's party, and Flik's party are both initialized with leaders in the first position, so they cannot be exploited.
The code below is responsible for emptying the Hero's party. It resides in
/CDROM/140_HONP/PARTYCE1.BIN. In order to reorganize the party, a single function can be called that resides in the main executable, and is loaded at 0x80073894. After emptying a party, this function would simply shift the hero to the first position. There are also script commands, and code in other modules that similarly empty the party. Had they been used, instead of writing a duplicate routine, the bug would not exist.
RAM:80110C00 move $s0, $0
RAM:80110C04 li $s1, 0x80072F04 # Routine: GetIDForPartyPos
RAM:80110C0C li $s5, 0x80072844 # Routine: MP_CharaRecStat
RAM:80110C14 li $s3, 0x8007344C # Routine: RemoveFromParty
RAM:80110C1C sb $0, 2($s4)
RAM:80110C20
RAM:80110C20 loc_80110C20: # CODE XREF: RAM:80110C78j
RAM:80110C20 sw $s1, -0x5304($s2)
RAM:80110C24 jalr $s1
RAM:80110C28 move $a0, $s0
RAM:80110C2C beqz $v0, loc_80110C70
RAM:80110C30 nop
RAM:80110C34 sw $s1, -0x5304($s2)
RAM:80110C38 jalr $s1
RAM:80110C3C move $a0, $s0
RAM:80110C40 li $v1, 1
RAM:80110C44 beq $v0, $v1, loc_80110C70
RAM:80110C48 move $a0, $s0
RAM:80110C4C jalr $s1
RAM:80110C50 sw $s1, -0x5304($s2)
RAM:80110C54 li $a0, 0x26
RAM:80110C58 move $a1, $v0
RAM:80110C5C jalr $s5
RAM:80110C60 sw $s5, -0x5304($s2)
RAM:80110C64 move $a0, $s0
RAM:80110C68
RAM:80110C68 CallRemoveFromParty_00: # After this, it should call 0x80073894 - ReformPartyOnExit
RAM:80110C68 jalr $s3
RAM:80110C6C sw $s3, -0x5304($s2)
RAM:80110C70
RAM:80110C70 loc_80110C70: # CODE XREF: RAM:80110C2Cj
RAM:80110C70 # RAM:80110C44j
RAM:80110C70 addiu $s0, 1
RAM:80110C74 slti $v0, $s0, 6
RAM:80110C78 bnez $v0, loc_80110C20
RAM:80110C7C li $a0, 0x25
RAM:80110C80 li $s0, 0x80072844
Fix
After buying some space by eliminating leftover debug/trace code, and shuffling a few operations, the appropriate function just needs to be called. The next version of the patch released will include this fix.
; Suikoden II Luca Bug/Party Change Fix
; Written by Pyriel
;
.psx
.align 4
; all the $s registers are pretty much fair game.
; Using $v1 for address (already loaded).
.openfile PARTYCE1.BIN, 0x8010DC50
.headersize 0
.org 0x80110C20
; file location will be 0x2FD0
.area 0x80110C80-.
; replace loop that empties party
loop:
jalr $s1
move $a0, $s0
beqz $v0, continue
nop
jalr $s1
move $a0, $s0
li $v1, 1
beq $v0, $v1, continue
move $a0, $s0
jalr $s1
nop
li $a0, 0x26
jalr $s5
move $a1, $v0
move $a0, $s0
jalr $s3 ; RemoveFromParty After this, it should call 0x80073894 - ReformPartyOnExit
nop
continue:
addiu $s0, 1
slti $v0, $s0, 6
bnez $v0, loop
nop
jal 0x80073894
nop
li $a0, 0x25
.endarea
.close