Active Time Battle Code and Delay
Thanks to Pseudoarc and inuksuk.
While playing Chrono Trigger, I noticed that ATB recharge time was unusual with dual and triple techs. You can see this in action at (not my video) https://www.twitch.tv/videos/937335977. Google search gave a few results with others noticing the same phenomenon but no description of what the exact penalty is.
The relevant code is in the subroutine beginning at $C1BD6F. A relevant code fragment is below: Code: [Select]
$C1/BE6D AD 8C B1 LDA $B18C [$7E:B18C] $C1/BE70 AA TAX $C1/BE71 BF DC 2B CC LDA $CC2BDC,x[$CC:2BE2] $C1/BE75 29 0F AND #$0F $C1/BE77 AA TAX $C1/BE78 B9 AB AF LDA $AFAB,y[$7E:AFB1] $C1/BE7B C9 FF CMP #$FF $C1/BE7D F0 25 BEQ $25 [$BEA4] $C1/BE7F 7B TDC $C1/BE80 86 28 STX $28 [$00:0028] $C1/BE82 B9 AB AF LDA $AFAB,y[$7E:AFB1] $C1/BE85 AA TAX $C1/BE86 86 2A STX $2A [$00:002A] $C1/BE88 20 0B C9 JSR $C90B [$C1:C90B] $C1/BE8B A6 2C LDX $2C [$00:002C] $C1/BE8D 86 28 STX $28 [$00:0028] $C1/BE8F A2 0A 00 LDX #$000A $C1/BE92 86 2A STX $2A [$00:002A] $C1/BE94 20 2A C9 JSR $C92A [$C1:C92A] $C1/BE97 A5 2C LDA $2C [$00:002C] $C1/BE99 18 CLC $C1/BE9A 79 AB AF ADC $AFAB,y $C1/BE9D 90 02 BCC $02 [$BEA1] $C1/BE9F A9 FF LDA #$FF $C1/BEA1 99 AB AF STA $AFAB,y $C1/BEA4 99 DD 99 STA $99DD,y $C1/BEA7 99 22 9F STA $9F22,y
At the start of this fragment, Y holds the index of the player character (0,1, or 2) whose ATB is being reset after a tech. The tech id is in $B18C. The tech id is used as an index into memory beginning at $CC2BDC. Only the four low order bits of this number are kept. Call this atb_pen.
At the point in the subroutine, the character's normal max_atb is sitting in $AFAB+Y. For the record, I chased this down, and max_atb=(1+battle_speed)(25-char_speed). This is the number of frames it takes for the atb to fill up. What happens next is that max_atb is rewritten with max_atb + (max_atb*atb_pen)/10. In other words, an increase of atb_pen*10 percent. The final value is stored back in $AFAB+y as well as a few other places.
The story gets a little bit more interesting. Here's a view of the range beginning at $CC2BDC. Code: [Select]
00 10 20 30 30 50 30 50 60 10 10 20 20 10 20 30 30 10 10 10 20 20 30 40 50 10 10 20 20 20 30 30 40 10 10 20 20 30 30 30 50 10 10 20 20 10 30 40 50 20 20 20 20 20 10 30 40 11 32 53 11 31 53 11 23 54 11 23 35 11 23 23 21 33 35 11 22 22 22 33 23 11 22 43 11 23 43 11 33 43 21 22 32 12 12 23 11 12 33 31 32 55 53 31 33 35 23 53 35 12 12 21 33 52 32 11 53 03 02 03 03 03 03 03 01 04 01 04 02 03 03 02 FF FF FF FF FF FF FF FF FF FF FF FF
These numbers are the atb_pen values we described above in tech_id order. The basic attack is first with a 00 penalty. Then come each character's single techs. These all have the form X0, which might seem weird because it was the *low* order bits that were used above. It turns out while the low order bits are used as the penalty for some, the high order bits are used for the others. From what I can gather, whoever is first in the performance group gets the high order bits. Second and third seem to get the lower order four bits.
Here's the corresponding code for first in the performance group. Code: [Select]
$C1/BDF1 AD 8C B1 LDA $B18C [$7E:B18C] $C1/BDF4 AA TAX $C1/BDF5 BF DC 2B CC LDA $CC2BDC,x[$CC:2BE2] $C1/BDF9 4A LSR A $C1/BDFA 4A LSR A $C1/BDFB 4A LSR A $C1/BDFC 4A LSR A $C1/BDFD 29 0F AND #$0F $C1/BDFF AA TAX $C1/BE00 B9 AB AF LDA $AFAB,y $C1/BE03 C9 FF CMP #$FF $C1/BE05 F0 23 BEQ $23 [$BE2A] $C1/BE07 7B TDC $C1/BE08 86 28 STX $28 [$00:0028] $C1/BE0A B9 AB AF LDA $AFAB,y $C1/BE0D AA TAX $C1/BE0E 86 2A STX $2A [$00:002A] $C1/BE10 20 0B C9 JSR $C90B [$C1:C90B] $C1/BE13 A6 2C LDX $2C [$00:002C] $C1/BE15 86 28 STX $28 [$00:0028] $C1/BE17 A2 0A 00 LDX #$000A $C1/BE1A 20 2A C9 JSR $C92A [$C1:C92A] $C1/BE1D A5 2C LDA $2C [$00:002C] $C1/BE1F 18 CLC $C1/BE20 79 AB AF ADC $AFAB,y[$7E:AFB1] $C1/BE23 90 02 BCC $02 [$BE27] $C1/BE25 A9 FF LDA #$FF $C1/BE27 99 AB AF STA $AFAB,y $C1/BE2A 99 22 9F STA $9F22,y
Looks good, right? The value is shifted right four times so we use the high bits instead of the low ones. One crucial difference is that the value 10 for atb_pen/10 is never actually stored. After the LDX #$000A there should be STX $28 to pass into the division subroutine. Because this is missing, the division errors out and returns 0. There is no resulting atb penalty.
This is not too hard to fix. Fixing it does introduce another bug though. Because the new atb is not stored in $99DD+y like in the first code fragment, the atb bar bugs out for the first few frames. Adding in a STA $99DD,y instruction after computation fixes this bug. Be warned that everyone will be a big sluggish if you fix this. Luminaire, for example, carries a hefty 60% max_atb penalty. If you don't want any atb penalties, you can just NOP out the STX at $C1BE92 (edit: safer to change to STX #$00).
While I hope this is of intrinsic interest, it may be of some pratical use for rom hackers. If you expand the tech list, you may find yourself going beyond the expected range into those FFs and load up crazy atb penalties for your double techs and triple techs. This also may give some design space for balancing out powerful techs with more wild atb penalties.
This great write-up helped find where Haste and Slow get calculated, too. Double thanks! (That subroutine is at $01BD6F.)