This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.
1
Chrono Trigger Modification / Max HP Bonus hacking guide
« on: August 04, 2024, 12:05:39 am »
Introduction
This is a guide to adding the +25% HP bonus that appears on Silver Earring to other accessories. It is intended to double as an assembly hacking tutorial. The guide is targeted at modders who find they want to make changes to the game that aren’t already addressed by the excellent modding tools available for Chrono Trigger. Sometimes the only way to make your change will be to modify the game’s code yourself!
The guide assumes the reader can use debugging tools such as bsnes+ to set breakpoints so the game’s code can be inspected. Some background knowledge about SNES assembly programming and SNES architecture is also assumed.
If you’ve already familiarized yourself with the modding tools available for Chrono Trigger and are looking to take your skills to the next level by learning to modify the game’s code yourself, then this is the guide for you!
Investigating
We begin knowing very little about how the game applies Silver Earring’s HP bonus. It seems to be applied in an ad hoc way and not in the systematic way other item data is processed. That makes it difficult for the creators of modding tools to include it. If we want to design a new accessory with an HP bonus, we’ll have to do it ourselves. So, let’s dive in!
There must be sections of RAM devoted to storing information about the PCs, but where exactly in RAM? Lucky for us, Stephen Geiger, the creator of Temporal Flux, audited the ROM way back in 2007 and that gives us a great starting point (download the Chrono Trigger Database directly from Geiger's website). According to the memory map, each PC has $50 bytes of data starting at $7e2600 in RAM. Crono’s max HP is stored at $7e2605. This is a good place to start when investigating a bonus that grants max HP!
Set a Write breakpoint at $7e2605, Crono’s max HP, and then equip Crono with the Silver Earring.
Nothing happens! Whatever change occurred, it didn’t write Crono’s new max HP where we expected, and the breakpoint wasn’t triggered. Not to worry: the first idea you have isn’t always the right one. It pays to be patient and try different things. It’s maybe not so surprising that the change is happening in another location in memory, since the Equip menu is able to show a stat preview when you’re browsing equipment. The menu code probably works on its own version of Crono’s data.
Let’s instead set a Read breakpoint at $7e2605 and see if Crono’s max HP is being read and used elsewhere. This time we get a hit:
The breakpoint triggered while copying Crono’s $50 bytes of data from $7e2600 to $7e9a90. That means his max HP is also being stored at $7e9a95. If the menu is using its own version of Crono’s data at $9a90, let’s find out more about that. Set a Read breakpoint on Crono’s max HP at $7e9a95 and try to equip the Silver Earring. We repeatedly hit the same two breakpoints once per frame:
This code is very interesting! It’s not immediately clear what the value in X represents, but the context tells us something is being added to Crono’s max HP. That’s what we want to see, since we’re trying to figure out how Silver Earring’s HP bonus is applied! Just by following the flow of the code, we can deduce that a bonus of 0, (maxHP / 2), or (maxHP / 4) is being added to Crono’s normal max HP. That sounds a lot like Silver Earring and Gold Earring, which provide 25% and 50% bonuses.
We can confirm our hunch by investigating how X is used in more detail. We have two questions to answer: 1) What does the data loaded from $9aba represent? 2) What do the values $a1 and $a0 represent? It’s very likely $a1 and $a0 represent the Silver and Gold Earrings. With Mauron’s Itemizer plugin for Temporal Flux we can verify those are in fact the item IDs for those two accessories. That means $9aba should be where Crono’s accessory ID is being stored. We can confirm by observing $7e9aba is within $50 bytes of $7e9a90, the address where Crono’s data was copied to. Careful counting tells us $9aba was copied from $7e262a, which Geiger’s RAM map confirms is the address of Crono’s equipped accessory.
There might still be more to the story, but this seems to be exactly the code we were looking for! Crono’s accessory ID is read, and depending on the result either 0%, 25%, or 50% is added to his max HP. So now we’ve found the code that adjusts Crono’s max HP when the Silver or Gold Earring are equipped. How would we get that HP bonus on another accessory?
Hacking
The Muscle Ring is a humble accessory, granting a measly 6 Stamina. Why don’t we add an HP bonus on there to liven it up? Now that we’ve located the right code, it’s just a matter of writing and inserting new instructions. The most obvious strategy is to add another comparison to check for Muscle Ring (ID number $b4) and branch as desired:
This solution won’t work, however. Adding new instructions to detect the Muscle Ring takes 4 bytes of assembly code. Jamming in some new instructions means you’re going to write over the instructions already there in the ROM. That can cause a lot of problems. Writing new instructions in place can be desirable, but it doesn’t look like a good solution for this situation. We will instead jump to another section of the ROM and add our instructions there, then return and pick up where we left off.
There’s several hundred bytes of unused space at file address $027de4 according to Geiger’s NA offsets. That’s the same bank we’re working in, so let’s go ahead and jump there with a JSR. We’ll also add some filler instructions as padding in the original routine to ensure a smooth logical flow to the program.
This solution is very similar to the last one, but now we’ve moved instructions to free space so that there’s room to check if Muscle Ring is equipped. The original routine now has a branch instruction for a seamless flow back into the original code. Notice that the CLC instruction is at address $c292aa as in the original code.
N.B.: If you’re claiming free space in the ROM like this for your project and you’re using Temporal Flux, be sure to add it in the Window > Custom Data menu. Temporal Flux will otherwise use free space until it’s all filled up and cause conflicts.
An alternative would be to find a section marked “junk” to jump to, since Temporal Flux won’t use that space.
This code works perfectly for the menu screen. Unfortunately, the change isn’t yet fully functional. As it turns out, this change only applies to the menu screen! In battle, Crono doesn’t get the bonus max HP.
Hacking Pt. 2
Let's use the debugger to investigate how accessories are used in battle.
Equip Crono with the Muscle Ring, make sure he’s leading the party, then set a Read breakpoint on Crono’s accessory in battle at address $7e5e57 (thanks to Geiger's offsets) and start a battle. The first breakpoint is checking whether the Wallet is equipped, so click Run to see what else we hit. It’s not immediately clear what the second breakpoint is, but it appears to be a loop that reads the item data for each piece of equipment. This isn’t what we want either. The third breakpoint is testing whether the accessory is Silver Earring, though! This is the code we're looking for.
(These breakpoints are followed by code to detect the Berserker and then the Sightscope.)
The pattern of this code should look familiar by now. We’ll add a check for the Muscle Ring and apply the appropriate bonus to Crono’s max HP. I omitted the section of the code that adds Gold Earring’s HP bonus for brevity, but the calculation is written out entirely rather than branching to the first or second LSR like in the code from the menu we looked at.
We can take advantage of the repetition in this code to add handling for Muscle Ring without having to find free space elsewhere in the ROM. We’ll use the same strategy found in the menu code and condense the routine. Editing routines in place like this is often convenient, since you don’t need to worry about conflicts with other modifications quite as much.
The X register is being used as an index to read the PC data here, so we’ll load the accessory ID into the Y register.
We managed to add some logic to detect Muscle Ring while shortening the overall routine, which now returns at address $b3d9. That’s not much new room to work with, since the old routine finished at $b3ea, but at least we know room to accommodate more accessories if we ever want to come back and add the max HP bonus to more items. I’ll typically write $FF to any space I free up, and make a note of what addresses were affected by my edit.
Well, that should do it! We’ve now written code to handle the max HP bonus in the menu preview and in the actual battle data.
I highly recommend the use of an assembler such as asar to inject your code. Its use is beyond the scope of this guide, however. With some elbow grease and determination, you can instead convert your assembly to bytecode and enter it manually with a hex editor. That way is very slow and error prone, but it’s how I started out—which is why I recommend asar.
Loose Ends
Those two changes we made to the code make for a fully functional Muscle Ring with an HP bonus, but there is one subtlety that we haven't addressed. I didn't realize until a player pointed it out to me, but events that restore the party’s HP, such as staying at an inn or using the shining star at the End of Time, don’t respect the Muscle Ring’s HP bonus.
Some things you can only learn by doing, so if you’d like to apply some of this lesson, try to tie up that loose end yourself and fix the bug with HP restore events yourself. It's a good exercise to apply some of what this guide taught.
Think about what the code must be doing to restore the party's HP and try to set a breakpoint that will allow you to inspect that code. You'll be looking for code that reads a PC’s accessory and HP, and compares the accessory to $a0 and $a1 to detect the Silver and Gold Earrings.
I’ve attached a .txt file to this post that can be used with asar to apply all the modifications to the Muscle Belt discussed in this guide, including the fix for the restore point. If you’d like to inspect it or modify the code to your own ends, just open it in an text editor. I recommend Notepad++, which can readily support asar.
Conclusion
Assembly hacking can take a lot of determination, but there’s virtually no limit to what you can accomplish once you’ve added all these tools to your belt. There are excellent modding tools already available for Chrono Trigger, but there’s nothing quite like digging through the game’s systems and making changes to add your own personal touches.
There’s a lot to learn, but there’s also lots of information out there you can learn from. Start small and if you get stuck, take a break, ask for help, and try again with a fresh perspective!
This is a guide to adding the +25% HP bonus that appears on Silver Earring to other accessories. It is intended to double as an assembly hacking tutorial. The guide is targeted at modders who find they want to make changes to the game that aren’t already addressed by the excellent modding tools available for Chrono Trigger. Sometimes the only way to make your change will be to modify the game’s code yourself!
The guide assumes the reader can use debugging tools such as bsnes+ to set breakpoints so the game’s code can be inspected. Some background knowledge about SNES assembly programming and SNES architecture is also assumed.
If you’ve already familiarized yourself with the modding tools available for Chrono Trigger and are looking to take your skills to the next level by learning to modify the game’s code yourself, then this is the guide for you!
Investigating
We begin knowing very little about how the game applies Silver Earring’s HP bonus. It seems to be applied in an ad hoc way and not in the systematic way other item data is processed. That makes it difficult for the creators of modding tools to include it. If we want to design a new accessory with an HP bonus, we’ll have to do it ourselves. So, let’s dive in!
There must be sections of RAM devoted to storing information about the PCs, but where exactly in RAM? Lucky for us, Stephen Geiger, the creator of Temporal Flux, audited the ROM way back in 2007 and that gives us a great starting point (download the Chrono Trigger Database directly from Geiger's website). According to the memory map, each PC has $50 bytes of data starting at $7e2600 in RAM. Crono’s max HP is stored at $7e2605. This is a good place to start when investigating a bonus that grants max HP!
Set a Write breakpoint at $7e2605, Crono’s max HP, and then equip Crono with the Silver Earring.
Nothing happens! Whatever change occurred, it didn’t write Crono’s new max HP where we expected, and the breakpoint wasn’t triggered. Not to worry: the first idea you have isn’t always the right one. It pays to be patient and try different things. It’s maybe not so surprising that the change is happening in another location in memory, since the Equip menu is able to show a stat preview when you’re browsing equipment. The menu code probably works on its own version of Crono’s data.
Let’s instead set a Read breakpoint at $7e2605 and see if Crono’s max HP is being read and used elsewhere. This time we get a hit:
Code: [Select]
Address Instruction Comment
c2/8853 TAX ; Transfer source address to X.
c2/8854 LDY #$9a90 ; Load destination address to Y.
c2/8857 LDA #$004f ; Repeat $4f times.
c2/885a MVN $7e, $7e ; Copy a block of memory. <--- Break
The breakpoint triggered while copying Crono’s $50 bytes of data from $7e2600 to $7e9a90. That means his max HP is also being stored at $7e9a95. If the menu is using its own version of Crono’s data at $9a90, let’s find out more about that. Set a Read breakpoint on Crono’s max HP at $7e9a95 and try to equip the Silver Earring. We repeatedly hit the same two breakpoints once per frame:
Code: [Select]
Address Instruction Comment
c2/9297 LDX $9aba ; Load a memory address to X.
c2/929a LDA $9a95 ; Load max HP. <--- Break
c2/929d CPX #$a1 ; If X’s value is $a1,
c2/929f BEQ $08 ; then branch ahead 8 bytes.
c2/92a1 CPX #$a0 ; If X’s value is $a0,
c2/92a3 BEQ $03 ; then branch ahead 3 bytes.
c2/92a5 LDA #$0000 ; Load zero.
c2/92a8 LSR A ; /2
c2/92a9 LSR A ; /2
c2/92aa CLC
c2/92ab ADC $9a95 ; Add accumulator to max HP. <--- Break
c2/92ae CMP #$03e7 ; If new max HP < 999,
c2/92b1 BCC $03 ; then branch ahead 3 bytes.
c2/92b3 LDA #$03e7 ; Load 999.
c2/92b6 STA $9b25 ; Store new max HP.
This code is very interesting! It’s not immediately clear what the value in X represents, but the context tells us something is being added to Crono’s max HP. That’s what we want to see, since we’re trying to figure out how Silver Earring’s HP bonus is applied! Just by following the flow of the code, we can deduce that a bonus of 0, (maxHP / 2), or (maxHP / 4) is being added to Crono’s normal max HP. That sounds a lot like Silver Earring and Gold Earring, which provide 25% and 50% bonuses.
We can confirm our hunch by investigating how X is used in more detail. We have two questions to answer: 1) What does the data loaded from $9aba represent? 2) What do the values $a1 and $a0 represent? It’s very likely $a1 and $a0 represent the Silver and Gold Earrings. With Mauron’s Itemizer plugin for Temporal Flux we can verify those are in fact the item IDs for those two accessories. That means $9aba should be where Crono’s accessory ID is being stored. We can confirm by observing $7e9aba is within $50 bytes of $7e9a90, the address where Crono’s data was copied to. Careful counting tells us $9aba was copied from $7e262a, which Geiger’s RAM map confirms is the address of Crono’s equipped accessory.
There might still be more to the story, but this seems to be exactly the code we were looking for! Crono’s accessory ID is read, and depending on the result either 0%, 25%, or 50% is added to his max HP. So now we’ve found the code that adjusts Crono’s max HP when the Silver or Gold Earring are equipped. How would we get that HP bonus on another accessory?
Hacking
The Muscle Ring is a humble accessory, granting a measly 6 Stamina. Why don’t we add an HP bonus on there to liven it up? Now that we’ve located the right code, it’s just a matter of writing and inserting new instructions. The most obvious strategy is to add another comparison to check for Muscle Ring (ID number $b4) and branch as desired:
Code: [Select]
Address Instruction Comment
c2/9297 LDX $9aba ; Load accessory ID.
c2/929a LDA $9a95 ; Load max HP.
c2/929d CPX #$a1 ; If Gold Earring is equipped,
c2/929f BEQ $0c ; then branch ahead 12 bytes.
c2/92a1 CPX #$a0 ; If Silver Earring is equipped,
c2/92a3 BEQ $07 ; then branch ahead 7 bytes.
c2/92a5 CPX #$b4 ; If Muscle Ring is equipped, <--- New code
c2/92a7 BEQ $03 ; then branch ahead 3 bytes.
c2/92a9 LDA #$0000 ; Load zero.
c2/92ac LSR A ; /2
c2/92ad LSR A ; /2
c2/92ae CLC
c2/92af ADC $9a95 ; Add accumulator to max HP.
This solution won’t work, however. Adding new instructions to detect the Muscle Ring takes 4 bytes of assembly code. Jamming in some new instructions means you’re going to write over the instructions already there in the ROM. That can cause a lot of problems. Writing new instructions in place can be desirable, but it doesn’t look like a good solution for this situation. We will instead jump to another section of the ROM and add our instructions there, then return and pick up where we left off.
There’s several hundred bytes of unused space at file address $027de4 according to Geiger’s NA offsets. That’s the same bank we’re working in, so let’s go ahead and jump there with a JSR. We’ll also add some filler instructions as padding in the original routine to ensure a smooth logical flow to the program.
Code: [Select]
Address Instruction Comment
c2/9297 LDX $9aba ; Load accessory ID.
c2/929a LDA $9a95 ; Load max HP.
c2/929d JSR $7de4 ; Jump to subroutine in free space.
c2/92a0 BRA $08 ; Branch ahead 8 bytes.
c2/92a2 NOP
c2/92a3 NOP
c2/92a4 NOP
c2/92a5 NOP
c2/92a6 NOP
c2/92a7 NOP
c2/92a8 NOP
c2/92a9 NOP ; No operation x8.
c2/92aa CLC
c2/92ab ADC $9a95 ; Add accumulator to max HP.
[…]
c2/7de4 CPX #$a1 ; If Gold Earring is equipped,
c2/7de6 BEQ $0c ; then branch ahead 12 bytes.
c2/7de8 CPX #$a0 ; If Silver Earring is equipped,
c2/7dea BEQ $07 ; then branch ahead 7 bytes.
c2/7dec CPX #$b4 ; If Muscle Ring is equipped,
c2/7dee BEQ $03 ; then branch ahead 3 bytes.
c2/7df0 LDA #$0000 ; Load zero.
c2/7df3 LSR A ; /2
c2/7df4 LSR A ; /2
c2/7df5 RTS ; Return.
This solution is very similar to the last one, but now we’ve moved instructions to free space so that there’s room to check if Muscle Ring is equipped. The original routine now has a branch instruction for a seamless flow back into the original code. Notice that the CLC instruction is at address $c292aa as in the original code.
N.B.: If you’re claiming free space in the ROM like this for your project and you’re using Temporal Flux, be sure to add it in the Window > Custom Data menu. Temporal Flux will otherwise use free space until it’s all filled up and cause conflicts.
An alternative would be to find a section marked “junk” to jump to, since Temporal Flux won’t use that space.
This code works perfectly for the menu screen. Unfortunately, the change isn’t yet fully functional. As it turns out, this change only applies to the menu screen! In battle, Crono doesn’t get the bonus max HP.
Hacking Pt. 2
Let's use the debugger to investigate how accessories are used in battle.
Equip Crono with the Muscle Ring, make sure he’s leading the party, then set a Read breakpoint on Crono’s accessory in battle at address $7e5e57 (thanks to Geiger's offsets) and start a battle. The first breakpoint is checking whether the Wallet is equipped, so click Run to see what else we hit. It’s not immediately clear what the second breakpoint is, but it appears to be a loop that reads the item data for each piece of equipment. This isn’t what we want either. The third breakpoint is testing whether the accessory is Silver Earring, though! This is the code we're looking for.
Code: [Select]
Address Instructions Comment
fd/b3aa LDA $5e57, X [7e5e57] ; Load equipped accessory ID. <--- Break
fd/b3ad CMP #$a0 ; If Silver Earring is not equipped,
fd/b3af BNE $b3c9 ; Branch ahead to test Gold Earring.
fd/b3b1 REP #$20 ; 16-bit mode A.
fd/b3b3 LDA $5e32, X [7e5e32] ; Load max HP.
fd/b3b6 LSR A ; /2
fd/b3b7 LSR A ; /2
fd/b3b8 CLC
fd/b3b9 ADC $5e32, X [7e5e32] ; Add accumulator to max HP.
fd/b3bc CMP #$03e7
fd/b3bf BCC $b3c4
fd/b3c1 LDA #$03e7 ; 999 ceiling.
fd/b3c4 STA $5e32, X [7e5e32] ; Store new max HP.
fd/b3c7 BRA $b3e7 ; Branch to cleanup.
fd/b3c9 SEP #$20 ; 8-bit mode A.
fd/b3cb LDA 5e57, X [7e5e57] ; Load equipped accessory ID. <--- Break
fd/b3ce CMP #$a1 ; If Gold Earring is not equipped,
fd/b3d0 BNE $b3e7 ; Branch to cleanup.
[…]
[Gold Earring section omitted.]
fd/b3e7 TDC
fd/b3e8 SEP #$20
fd/b3ea RTL ; Return.
(These breakpoints are followed by code to detect the Berserker and then the Sightscope.)
The pattern of this code should look familiar by now. We’ll add a check for the Muscle Ring and apply the appropriate bonus to Crono’s max HP. I omitted the section of the code that adds Gold Earring’s HP bonus for brevity, but the calculation is written out entirely rather than branching to the first or second LSR like in the code from the menu we looked at.
We can take advantage of the repetition in this code to add handling for Muscle Ring without having to find free space elsewhere in the ROM. We’ll use the same strategy found in the menu code and condense the routine. Editing routines in place like this is often convenient, since you don’t need to worry about conflicts with other modifications quite as much.
The X register is being used as an index to read the PC data here, so we’ll load the accessory ID into the Y register.
Code: [Select]
Address Instruction Comment
fd/b3aa LDA $5e57, X ; Load accessory ID.
fd/b3ad TAY ; Transfer to Y.
fd/b3ae REP #$20 ; 16-bit mode A.
fd/b3b0 LDA $5e32, X ; Load max HP.
fd/b3b3 CPY #$00a1 ; If Gold Earring is equipped,
fd/b3b6 BEQ $0d ; then branch ahead 14 bytes.
fd/b3b8 CPY #$00a0 ; If Silver Earring is equipped,
fd/b3bb BEQ $08 ; then branch ahead 08 bytes.
fd/b3bd CPY #$00b4 ; If Muscle Ring is equipped,
fd/b3c0 BEQ $03 ; then branch ahead 03 bytes.
fd/b3c2 LDA #$0000 ; Load zero.
fd/b3c5 LSR A ; /2
fd/b3c6 LSR A ; /2
fd/b3c7 CLC
fd/b3c8 ADC $5e32, X ; Add to max HP.
fd/b3cb CMP #$03e7
fd/b3ce BCC $03
fd/b3d0 LDA #$0e37 ; 999 ceiling.
fd/b3d3 STA $5e32, X ; Store max HP.
fd/b3d6 TDC
fd/b3d7 SEP #$20
fd/b3d9 RTL ; Return.
We managed to add some logic to detect Muscle Ring while shortening the overall routine, which now returns at address $b3d9. That’s not much new room to work with, since the old routine finished at $b3ea, but at least we know room to accommodate more accessories if we ever want to come back and add the max HP bonus to more items. I’ll typically write $FF to any space I free up, and make a note of what addresses were affected by my edit.
Well, that should do it! We’ve now written code to handle the max HP bonus in the menu preview and in the actual battle data.
I highly recommend the use of an assembler such as asar to inject your code. Its use is beyond the scope of this guide, however. With some elbow grease and determination, you can instead convert your assembly to bytecode and enter it manually with a hex editor. That way is very slow and error prone, but it’s how I started out—which is why I recommend asar.
Loose Ends
Those two changes we made to the code make for a fully functional Muscle Ring with an HP bonus, but there is one subtlety that we haven't addressed. I didn't realize until a player pointed it out to me, but events that restore the party’s HP, such as staying at an inn or using the shining star at the End of Time, don’t respect the Muscle Ring’s HP bonus.
Some things you can only learn by doing, so if you’d like to apply some of this lesson, try to tie up that loose end yourself and fix the bug with HP restore events yourself. It's a good exercise to apply some of what this guide taught.
Think about what the code must be doing to restore the party's HP and try to set a breakpoint that will allow you to inspect that code. You'll be looking for code that reads a PC’s accessory and HP, and compares the accessory to $a0 and $a1 to detect the Silver and Gold Earrings.
I’ve attached a .txt file to this post that can be used with asar to apply all the modifications to the Muscle Belt discussed in this guide, including the fix for the restore point. If you’d like to inspect it or modify the code to your own ends, just open it in an text editor. I recommend Notepad++, which can readily support asar.
Conclusion
Assembly hacking can take a lot of determination, but there’s virtually no limit to what you can accomplish once you’ve added all these tools to your belt. There are excellent modding tools already available for Chrono Trigger, but there’s nothing quite like digging through the game’s systems and making changes to add your own personal touches.
There’s a lot to learn, but there’s also lots of information out there you can learn from. Start small and if you get stuck, take a break, ask for help, and try again with a fresh perspective!
2
Chrono Trigger Modification / Re: Chrono Trigger Dialogue Box Gradient?
« on: April 16, 2024, 03:08:10 am »
I haven't dug in to how the gradient is generated myself, but this page in the Encyclopedia discusses it in passing.
https://www.chronocompendium.com/Term/Menu_HDMA_Colors.html
Chickenlump mentions the game generating a table for the dialogue box gradient at runtime as opposed to the menu window colours which are read directly from the ROM. They were able to hijack the routine that reads the gradient and substitute an arbitrary one. I'm guessing the original routine that generates the HDMA table for dialogue boxes is responsible for the behaviour you observed while working in Paint.
https://www.chronocompendium.com/Term/Menu_HDMA_Colors.html
Chickenlump mentions the game generating a table for the dialogue box gradient at runtime as opposed to the menu window colours which are read directly from the ROM. They were able to hijack the routine that reads the gradient and substitute an arbitrary one. I'm guessing the original routine that generates the HDMA table for dialogue boxes is responsible for the behaviour you observed while working in Paint.
3
Chrono Trigger Modification / Re: Chrono Trigger - The Fifth Element
« on: August 23, 2023, 05:51:15 pm »
Here's the routine that detects the personal element defense bonus. It's called three times at the start of battle. Elemental defenses are all set to four, then the PC's bonus defense element gets set to five.
Code: [Select]
Load elemental resistance: LDA.W $AEFF,X ;FDB3FE|BDFFAE |00AEFF; X holds battle ID
CMP.B #$FF ;FDB401|C9FF | ;
BEQ Return ;FDB403|F032 |FDB437;
LDA.B #$04 ;FDB405|A904 | ; Load four
STA.W $5E6C,Y ;FDB407|996C5E |005E6C; Store Lightning defense
STA.W $5E6D,Y ;FDB40A|996D5E |005E6D; Store Shadow defense
STA.W $5E6E,Y ;FDB40D|996E5E |005E6E; Store Water defense
STA.W $5E6F,Y ;FDB410|996F5E |005E6F; Store Fire defense
LDA.W $5E2E,Y ;FDB413|B92E5E |005E2E; Load personal element defense bonus
; | | ;
Test Lightning: BIT.B #$80 ;FDB416|8980 | ;
BEQ Test Shadow ;FDB418|F002 |FDB41C;
BRA Store resistance ;FDB41A|8016 |FDB432;
; | | ;
; | | ;
Test Shadow: BIT.B #$40 ;FDB41C|8940 | ;
BEQ Test Water ;FDB41E|F003 |FDB423;
INY ;FDB420|C8 | ;
BRA Store resistance ;FDB421|800F |FDB432;
; | | ;
; | | ;
Test Water: BIT.B #$20 ;FDB423|8920 | ;
BEQ Test Fire ;FDB425|F004 |FDB42B;
INY ;FDB427|C8 | ;
INY ;FDB428|C8 | ;
BRA Store resistance ;FDB429|8007 |FDB432;
; | | ;
; | | ;
Test Fire: BIT.B #$10 ;FDB42B|8910 | ;
BEQ Return ;FDB42D|F008 |FDB437;
INY ;FDB42F|C8 | ;
INY ;FDB430|C8 | ;
INY ;FDB431|C8 | ;
; | | ;
Store resistance: LDA.B #$05 ;FDB432|A905 | ;
STA.W $5E6C,Y ;FDB434|996C5E |005E6C; Store personal element resistance
; | | ;
Return: RTL ;FDB437|6B | ;
4
Chrono Trigger Modification / Re: Chrono Trigger - The Fifth Element
« on: August 22, 2023, 07:04:27 pm »
The routine starting at $C1EF39 reads elemental defenses. The first section tests the element bitflags and chooses an index to read the corresponding elemental defense.
The next section of the routine reads the elemental defense from the defender's stat block.
There's a bit more processing and then the damage adjustment that follows. So, the elemental defenses are referenced by index as you can see. I don't think there's a battle code disassembly, though I did go through a bunch of it early this year.
Code: [Select]
Weapon Effect 0A: TDC ;C1EF39|7B | ; Magic Attack
LDA.W $B190 ;C1EF3A|AD90B1 |00B190; Load element/AI byte
STA.B $2C ;C1EF3D|852C |00002C;
; | | ;
Test Lightning: BIT.B #$80 ;C1EF3F|8980 | ;
BEQ Test Shadow ;C1EF41|F003 |C1EF46;
TDC ;C1EF43|7B | ; Load zero
BRA Element was detected ;C1EF44|8016 |C1EF5C;
; | | ;
; | | ;
Test Shadow: BIT.B #$40 ;C1EF46|8940 | ;
BEQ Test Water ;C1EF48|F004 |C1EF4E;
LDA.B #$01 ;C1EF4A|A901 | ; Load one
BRA Element was detected ;C1EF4C|800E |C1EF5C;
; | | ;
; | | ;
Test Water: BIT.B #$20 ;C1EF4E|8920 | ;
BEQ Test Fire ;C1EF50|F004 |C1EF56;
LDA.B #$02 ;C1EF52|A902 | ; Load two
BRA Element was detected ;C1EF54|8006 |C1EF5C;
; | | ;
; | | ;
Test Fire: BIT.B #$10 ;C1EF56|8910 | ;
BEQ Return ;C1EF58|F061 |C1EFBB;
LDA.B #$03 ;C1EF5A|A903 | ; Load three
; | | ;
Element was detected: STA.W $B2CD ;C1EF5C|8DCDB2 |00B2CD; Store elemental defense index
The next section of the routine reads the elemental defense from the defender's stat block.
Code: [Select]
Element was detected: STA.W $B2CD ;C1EF5C|8DCDB2 |00B2CD; Store elemental defense index
LDA.B #$04 ;C1EF5F|A904 | ;
STA.W $B2CF ;C1EF61|8DCFB2 |00B2CF; Store damage multiplier numerator
LDA.W $B2CD ;C1EF64|ADCDB2 |00B2CD; Load index
REP #$20 ;C1EF67|C220 | ;
CLC ;C1EF69|18 | ;
ADC.W $B1F6 ;C1EF6A|6DF6B1 |00B1F6; Add index to defender stat block offset
TAX ;C1EF6D|AA | ;
TDC ;C1EF6E|7B | ;
SEP #$20 ;C1EF6F|E220 | ;
LDA.W $5E6C,X ;C1EF71|BD6C5E |005E6C; Load elemental defense
There's a bit more processing and then the damage adjustment that follows. So, the elemental defenses are referenced by index as you can see. I don't think there's a battle code disassembly, though I did go through a bunch of it early this year.
5
Chrono Trigger Modification / Re: Dual/Triple Tech ATB Delay
« on: May 08, 2023, 04:18:13 am »If you don't want any atb penalties, you can just NOP out the STX at $C1BE92 (edit: safer to change to STX #$00).
I took another look at this recently. Rather than targeting the divisor and relying on the error catching in the division routine to return zero, I'd suggest editing where the quotient gets loaded. So write LDA #$00 at $C1BE97 to remove all ATB penalties. (I think your edited suggestion of STX #$00 isn't a valid instruction, by the way.)
My suggestion:
Code: [Select]
$C1/BE92 STX $2A ; Store divisor
$C1/BE94 JSR $C92A ; Division routine
$C1/BE97 >LDA #$00 ; Load zero
$C1/BE99 CLC
$C1/BE9A ADC $AFAB,Y ; Add 0+ATB
6
Chrono Trigger Modification / Re: Not Learning a Triple Tech
« on: March 24, 2023, 03:04:22 pm »
Well done!
7
Chrono Trigger Modification / Re: Not Learning a Triple Tech
« on: March 08, 2023, 05:55:56 pm »
I was able to replicate the issue by changing Marle's Tech prerequisite to learn "Double Cure" from Cure 2 to regular Cure (or by changing the prerequisite for Cure Wave to regular Cure). TF seems to write over ten bytes at $0C27F0--I'd only noticed the five before since it caused the issue with learning 3D Attack.
8
Chrono Trigger Modification / Re: Not Learning a Triple Tech
« on: March 07, 2023, 06:49:55 pm »
I ran into this same problem a while back. Check the five bytes at $0C27F0--they should be 8C 6F 01 9C 28. At some point Temporal Flux wrote FF FF 00 00 00 there while I was mucking around with other dual Techs. Never tracked down exactly what happened.
9
Kajar Laboratories / Re: Enhansa Edition
« on: February 21, 2023, 05:05:43 pm »
Looks like an interesting mod! It's a considerable amount of work to make two mods so large in scope work together though, sorry.
10
Chrono Trigger Modification / Re: Temporal Flux Plugins
« on: January 18, 2023, 03:17:38 pm »
Minor bug report: In Warrior Workshop, unchecking Hexadecimal Display doesn't affect the Evade Growth and Evade Growth 2 displays in the Stat Growth pane. Those two stay as hex with the rest of the window in decimal.
11
Kajar Laboratories / Re: Enhansa Edition
« on: December 04, 2022, 05:28:08 pm »
Would someone kindly move this topic back to Kajar Laboratories? Thank you in advance!
12
Chrono Trigger Modification / Re: Inflicting Poison/Lock/Darkness status on enemies?
« on: November 19, 2022, 07:40:35 pm »Quote
Lock will not shut off the enemies' Techs as you might hope.
So true.
Also, Like in the tutorial series,.....
PoisonBarb(just made out of a random x-d out accessory, adding poison or slow as a status affect....) so when you walk through a trap in EVENT(pc.xy.position) auto equips that accessory, ....VERY USEFUL if in a "MINI-DUNGEON" (where you cannot access the menu, etc.)
~Z
13
Chrono Trigger Modification / Re: Chrono Trigger - Music Expansion
« on: November 13, 2022, 04:52:15 pm »
Cool stuff! Thanks for doing the work to make it play nice with Enhansa Edition, too.
14
Kajar Laboratories / Re: Enhansa Edition
« on: December 23, 2021, 10:42:27 pm »
Enhansa Edition v1.0 is now available, hot and fresh! Check it out at the link below:
https://www.romhacking.net/hacks/6440/
Zeality, if you'd be so kind as to make it a news post again I'd appreciate it.
And Boo, you mentioned the r/chronotrigger subreddit--I've submitted a post there as well.
https://www.romhacking.net/hacks/6440/
Zeality, if you'd be so kind as to make it a news post again I'd appreciate it.
And Boo, you mentioned the r/chronotrigger subreddit--I've submitted a post there as well.
15
Chrono Trigger Modification / Re: Temporal Flux Plugins
« on: December 05, 2021, 03:08:00 am »
Bug report for Hi-Tech. I edited some dual Techs to use different single Techs by changing the effect headers and prerequisites, but the field menu still displays MP costs for the dual Tech as though they use the original single Techs. Everything else seems to work as expected--for example the battle menu displays the intended MP costs.
The field menu is reading the dual Tech requirements from 0C28DB-0C2934 in order to display the MP costs, and changing those values resolves the issue.
The field menu is reading the dual Tech requirements from 0C28DB-0C2934 in order to display the MP costs, and changing those values resolves the issue.