Users browsing this thread: 1 Guest(s)
Assembly Programming
Edit: Due to a non-extensive testing there was a problem with the float check and thanks to someone on romhacking.net I became aware of the problem and fixed it. The command has been now tested with all the status plus multiple status. I haven'T done ALL the possibilities but enough to be sure it fully work. I updated the code and the download link.
I created a new event command that checks if status X (passed as a parameter) is set on the party leader of th active party. If the status is set, the game will branch at the offset passed a a second parameter and if not, it will continue the event after the command. I used command 83 which had no purpose prior to that. I'll try to explain what I have done:
The first thing is to change the pointer of the command and make a jump where there is empty space, like in the F1 bank:
The next part load the character position (a value from thr RAM), and then get the party number of the character and compare it to the active party number. It's the way to know if the character is in the active party. Then the character position is compared to a value and depending of the result of the check, it will end up storing the actor number (0 to 15) of character who is in slot 1. If nobody is in slot 1, it will take slot 2. This process is repeated 16 times to check every character:
Once we have the actor number of the leader, we perform a status check by comparing the status set for that character in his data in the RAM to a status number passed as a parameter. If none f the status is set , it loads in differents parameters a value of 000005, which represent the jump to continue the event right after the command and parameters. If a status is checked, it will load the offset of the jump passed as parameters 2, 3 and 4. In both case it will jump to the same subroutine in bank CO which will perform the appropriate jump:
Here are the values used for the first parameter:
I made a patch available here. (download link updated)
Here's an example:http://www.youtube.com/watch?v=GNeQqGZM5k8
I'm planning to make other commands based on this model to check other infos related to one character or the whole party. There is a couple of other unused event command.
I created a new event command that checks if status X (passed as a parameter) is set on the party leader of th active party. If the status is set, the game will branch at the offset passed a a second parameter and if not, it will continue the event after the command. I used command 83 which had no purpose prior to that. I'll try to explain what I have done:
The first thing is to change the pointer of the command and make a jump where there is empty space, like in the F1 bank:
Code:
C0/9960 9B DF (Action 83 pointer)
C0/DF9B 5C 00 A0 F1 JMP $F1A000 (jump to offset F1/A000)
The next part load the character position (a value from thr RAM), and then get the party number of the character and compare it to the active party number. It's the way to know if the character is in the active party. Then the character position is compared to a value and depending of the result of the check, it will end up storing the actor number (0 to 15) of character who is in slot 1. If nobody is in slot 1, it will take slot 2. This process is repeated 16 times to check every character:
Code:
F1/A000 A9 20 LDA #$20 (Load #$20 in A)
F1/A002 85 1A STA $1A (Store #$20 in $1A)
F1/A004 A4 00 LDY $00 (Load $00 in Y)
F1/A006 BB TYX (Transfer Y to X, to zero X)
F1/A007 B9 50 18 LDA $1850,Y (Load place of the Actor Y in the parties)
F1/A00A 29 07 AND #$07 (Get Actor's party number)
F1/A00C CD 6D 1A CMP $1A6D (compare with active party number)
F1/A00F D0 0D BNE $A01E (Branch if not the current party)
F1/A011 B9 50 18 LDA $1850,Y (Load place of the Actor Y in the active party)
F1/A014 29 18 AND #$18
F1/A016 C5 1A CMP $1A (Check if the Actor is the leader of the party)
F1/A018 B0 04 BCS $A01E (Branch if not)
F1/A01A 85 1A STA $1A (Store A in $1A)
F1/A01C 86 1E STX $1E (Store character number in $1E)
F1/A01E E8 INX (increment X by 1)
F1/A01F C8 INY (Increment Y by 1)
F1/A020 C0 10 00 CPY #$0010 (Y - 16)
F1/A023 D0 E2 BNE $A007 (branch if we didn't looped 16 times)
Once we have the actor number of the leader, we perform a status check by comparing the status set for that character in his data in the RAM to a status number passed as a parameter. If none f the status is set , it loads in differents parameters a value of 000005, which represent the jump to continue the event right after the command and parameters. If a status is checked, it will load the offset of the jump passed as parameters 2, 3 and 4. In both case it will jump to the same subroutine in bank CO which will perform the appropriate jump:
Code:
F1/A025 A5 1E LDA $1E (Load party Leader actor number in A)
F1/A027 8D 02 42 STA $4202 (store as multiplier A)
F1/A02A A9 25 LDA #$25 (character data length)
F1/A02C 8D 03 42 STA $4203 (store as multiplier B)
F1/A02F C2 20 REP #$20 (16 bit accum./memory)
F1/A031 EA NOP (wait for the multiplication to be done)
F1/A032 EA NOP (wait for the multiplication to be done)
F1/A033 EA NOP (wait for the multiplication to be done)
F1/A034 A4 16 42 LDY $4216 (store the result of the multiplication in Y)
F1/A037 E2 20 SEP #$20 (8 bit accum./memory)
F1/A039 B9 14 16 LDA $1614,Y (load byte 1 of status set)
F1/A03C 24 EB BIT $EB (compare to parameter)
F1/A03E D0 21 BNE $A061 (branch if status match)
F1/A040 B9 15 16 LDA $1615,Y (load byte 4 of status set)
F1/A043 89 80 BIT #$80 (check if float is set)
F1/A045 F0 06 BEQ $A04D (Branch if float not set)
F1/A047 69 40 ADC #$40 (Add #$40 to A)
F1/A049 24 EB BIT $EB (are we looking for float?)
F1/A04B D0 14 BNE $A061 (branch if not equal to parameter)
F1/A04D C2 21 REP #$21
F1/A04F A5 E5 LDA $E5 (Load low and middle byte of current offset)
F1/A051 69 05 00 ADC #$0005 (Command + parameters length)
F1/A054 85 E5 STA $E5 (Save in $E5)
F1/A056 7B TDC (Transfer D to C)
F1/A057 E2 20 SEP #$20 (8 bit accum./memory)
F1/A059 65 E7 ADC $E7 (Add to A $E7)
F1/A05B 85 E7 STA $E7 (Store A in $E7)
F1/A05D 5C 6D 9A C0 JMP $C09A6D (Make a 5 bytes jump from the command number in the event)
F1/A061 C2 20 REP #$20 (16 bit accum./memory)
F1/A063 A6 EC LDX $EC (Load parameter 2 and 3)
F1/A065 86 E5 STX $E5 (store the low and middle byte of the offset in $E5)
F1/A067 E2 20 SEP #$20 (8 bit accum./memory)
F1/A069 A5 EE LDA $EE (Load parameter 4)
F1/A06B 18 CLC (clear carry)
F1/A06C 69 CA ADC #$CA (Add #$CA to the high byte of the offset)
F1/A06E 85 E7 STA $E7 (Stre high byte of the offset in $E7)
F1/A070 5C 6D 9A C0 JMP $C09A6D (Make the event branching/jumping effective)
Here are the values used for the first parameter:
Code:
Blind 01
Zombie 02
Poison 04
magitek 08
Vanish 10
Imp 20
Petrify 40
Wounded 80
Float C0
I made a patch available here. (download link updated)
Here's an example:http://www.youtube.com/watch?v=GNeQqGZM5k8
I'm planning to make other commands based on this model to check other infos related to one character or the whole party. There is a couple of other unused event command.
Well another week and another event command!
This one check if all the active party members have levels equal or higher than level X (passed as the first parameter of the command). The rest is similar to the other command I did, parameters 2, 3 and 4 are the offset you jump to if the levels meet the requirement. It works with 1 to 4 characters in the party since it checks all 16 characters. It's based on the same model that my command that check for status, except this one check if the level is higher for all the members of the party. Here's the code (that could be optimized I'm sure but I don't have the skills for that yet):
Edit: Why is my code always twisted. Why doesn't it align itself properly ???
If you want that command badly, you have enough there to inspire you to write it. Here's a little (and boring) example:
Event Command 6D (previously unused)
This one check if all the active party members have levels equal or higher than level X (passed as the first parameter of the command). The rest is similar to the other command I did, parameters 2, 3 and 4 are the offset you jump to if the levels meet the requirement. It works with 1 to 4 characters in the party since it checks all 16 characters. It's based on the same model that my command that check for status, except this one check if the level is higher for all the members of the party. Here's the code (that could be optimized I'm sure but I don't have the skills for that yet):
Code:
F1/A080 A6 00 LDX $00 (zero X)
F1/A082 9B TXY (zero Y)
F1/A083 48 PHA (Push #$00 in the stack)
F1/A084 85 1B STA $1B (zero $1B)
F1/A086 7B TDC (zero A)
F1/A087 B9 67 08 LDA $0867,Y (current character's party)
F1/A08A E2 20 REP #$20 (8 bit)
F1/A08C 29 07 AND #$07 (check which party)
F1/A08E CD 6D 1A CMP $1A6D (compare A to the value of the active party stored in $1A6D)
F1/A091 D0 29 BNE $A0BC (branch if not the current party)
F1/A093 A5 1B LDA $1B (load number of member in the party so far)
F1/A095 1A INC (increment party members number by 1)
F1/A096 85 1B STA $1B (save number of members in $1B)
F1/A098 8E 02 42 STX $4202 (store character number as multiplier A)
F1/A09B A9 25 LDA #$25 (character data length)
F1/A09D 8D 03 42 STA $4203 (store character data length as multiplier B)
F1/A0A0 C2 20 REP #$20 (16 bit accum./memory)
F1/A0A2 EA NOP (wait for the multiplication to be done)
F1/A0A3 EA NOP (wait for the multiplication to be done)
F1/A0A4 EA NOP (wait for the multiplication to be done)
F1/A0A5 AC 16 42 LDY $4216 (store the result of the multiplication in A)
F1/A0A8 B9 08 16 LDA $1608,Y (load current level of the character)
F1/A0AB E2 20 SEP #$20 (8 bit accum./memory)
F1/A0AD C5 EB CMP $EB (compare to parameter)
F1/A0AF F0 08 BEQ $A0B9 (Branch to if level was initially equal or higher than parameter)
F1/A0B1 C9 01 CMP #$01 (check if it looped down to level 1)
F1/A0B3 F0 07 BEQ $A0BC (branch to if level was never equal or higher than parameter)
F1/A0B5 3A DEC (decrement level by 1)
F1/A0B6 4C AD A0 JMP $A0AD (Loop as long has the character'S level is not equal to parameter or level = 1)
F1/A0B9 68 PLA (pull number of party member who have a level higher than parameter)
F1/A0BA 1A INC (Add 1 to that number)
F1/A0BB 48 PHA (push back that number in the stack)
F1/A0BC E8 INX (Increment X by 1)
F1/A0BD 8A TXA (Transfer X to A)
F1/A0BE 89 10 BIT #$10 (Have we checked all 16 characters?)
F1/A0C0 F0 08 BEQ $A0CA (Branch if we have not checked all the characters)
F1/A0C2 68 PLA (pull number of party member with a level equal or higher than parameter)
F1/A0C3 C5 1B CMP $1B (compare to number of members in the party)
F1/A0C5 F0 2A BEQ $A0F1 (Branch if all characters level are equal or higher than parameter)
F1/A0C7 4C DD A0 JMP $A0DD (Jump if one or more character level is below parameter)
F1/A0CA 8E 02 42 STX $4202 (store next character number as multiplier A)
F1/A0CD A9 29 LDA #$29 (character data lenght)
F1/A0CF 8D 03 42 STA $4203 (store character data length as multiplier B)
F1/A0D2 C2 20 REP #$20 (16 bit accum./memory)
F1/A0D4 EA NOP (wait for the multiplication to be done)
F1/A0D5 EA NOP (wait for the multiplication to be done)
F1/A0D6 EA NOP (wait for the multiplication to be done)
F1/A0D7 AC 16 42 LDY $4216 (store the result of the multiplication in A)
F1/A0DA 4C 86 A0 JMP $A086 (Jump back to character's party check)
F1/A0DD C2 21 REP #$21
F1/A0DF A5 E5 LDA $E5 (Load low and middle byte of current offset)
F1/A0E1 69 05 00 ADC #$0005 (Command + parameters length)
F1/A0E4 85 E5 STA $E5 (Save in $E5)
F1/A0E6 7B TDC (Transfer D to C)
F1/A0E7 E2 20 SEP #$20 (8 bit accum./memory)
F1/A0E9 65 E7 ADC $E7 (Add to A $E7)
F1/A0EB 85 E7 STA $E7 (Store A in $E7)
F1/A0ED 5C 6D 9A C0 JMP $C09A6D (Make a 5 bytes jump from the command number in the event)
F1/A0F1 7B TDC (Transfer D to C)
F1/A0F2 A6 EC LDX $EC (Load parameter 2 and 3)
F1/A0F4 86 E5 STX $E5 (store the low and middle byte of the offset in $E5)
F1/A0F6 A5 EE LDA $EE (Load parameter 4)
F1/A0F8 18 CLC (clear carry)
F1/A0F9 69 CA ADC #$CA (Add #$CA to the high byte of the offset)
F1/A0FB 85 E7 STA $E7 (Store high byte of the offset in $E7)
F1/A0FD 5C 6D 9A C0 JMP $C09A6D (Make the event branching/jumping effective)
If you want that command badly, you have enough there to inspire you to write it. Here's a little (and boring) example:
Event Command 6D (previously unused)
03-25-2012, 04:32 AM
I just finished making the Offering behave like the Dragon Horn. With this modification, would will have 68.75% chances of dealing 2 hits, 25% chance of dealing 3 hits and 6.25% chances of dealing 4 hits.
Here are the code modifications. There might be a patch released soon and Gi Nattak is testing (and enjoying) the patch right now.
I put the code at C2/FAA4, but this space might be used by other patches, I haven't checked. I could somehow be optimized maybe because of the many NOP and the consecutives INC. Maybe there would be a better way to code this by loading either #$01, #$03, #$05 or #$07 in one of the registers and work it that way, instead of multiple INC, I'm not sure.
These are the main reasons why I'm not releasing a patch yet.
Anyone with very basic ASM understanding could move the code where he wants, this is not a problem.
Here's a video showing the result.
I'm only sure that #$07 stored in $3A70 equals 4 hits, #$01 equals probably 1 hit and for the rest I took a chance because #$02, #$03 or #$04 stored in $3A70 resulted in one or two hits instead of two to four hits. I think the odds are respected however.
Edit: Equipped with the Genji Glove, the character will deal either 4, 6 or 8 hits. It seems the game take the lowest or highest number of hit and multiply by two. I haven't looked at the code to change it to 4, 5, 6, 7, or 8 hits and I don't know if it is easy to change that way.
Here are the code modifications. There might be a patch released soon and Gi Nattak is testing (and enjoying) the patch right now.
I put the code at C2/FAA4, but this space might be used by other patches, I haven't checked. I could somehow be optimized maybe because of the many NOP and the consecutives INC. Maybe there would be a better way to code this by loading either #$01, #$03, #$05 or #$07 in one of the registers and work it that way, instead of multiple INC, I'm not sure.
These are the main reasons why I'm not releasing a patch yet.
Anyone with very basic ASM understanding could move the code where he wants, this is not a problem.
Here's a video showing the result.
Code:
C2/1620: 20 A4 FA JSR $FAA4
C2/1623: EA NOP
C2/1624: EA NOP
C2/1625: EA NOP
C2/1626: EA NOP
C2/1627: EA NOP
C2/1628: EA NOP
I'm only sure that #$07 stored in $3A70 equals 4 hits, #$01 equals probably 1 hit and for the rest I took a chance because #$02, #$03 or #$04 stored in $3A70 resulted in one or two hits instead of two to four hits. I think the odds are respected however.
Code:
C2/FAA4: A9 01 LDA #$01
C2/FAA6: 8D 70 3A STA $3A70 (Store 1 hit)
C2/FAA9: 90 1D BCC $FAC8 (branch to RTS if no offering)
C2/FAAB: 20 5A 4B JSR $4B5A (Random number from 0 to 255)
C2/FAAE: EE 70 3A INC $3A70
C2/FAB1: EE 70 3A INC $3A70 (Incremented to 2 hits ?)
C2/FAB4: C9 40 CMP #$40
C2/FAB6: B0 10 BCS $FAC8 (Branch 75% of the times)
C2/FAB8: EE 70 3A INC $3A70
C2/FABB: EE 70 3A INC $3A70 (incremented to 3 hits ?)
C2/FABE: C9 10 CMP #$10
C2/FAC0: B0 06 BCS $FAC8 (Branch 25% of the times)
C2/FAC2: EE 70 3A INC $3A70
C2/FAC5: EE 70 3A INC $3A70 (incremented to 4 hits ?)
C2/FAC8: 60 RTS (return to C2/1623)
Edit: Equipped with the Genji Glove, the character will deal either 4, 6 or 8 hits. It seems the game take the lowest or highest number of hit and multiply by two. I haven't looked at the code to change it to 4, 5, 6, 7, or 8 hits and I don't know if it is easy to change that way.
03-25-2012, 01:05 PM
now that is an impressive mod for the offering
awesome job bro
awesome job bro
"Sometimes ninjas do wrong to each other, and in dat way the force of tha earf' comes around da moon - and at that presence, da dirt, it overshadows the grass, so you're like, I can't cut dis grass, there's no sun comin' through. So in order to enable each other the two fruits have to look each other in da eye and understand we can only be right, as da ripe is wrong, you know what I mean?"
-HNIC
04-20-2012, 01:56 AM
Here I put an idea of Angelo in practice. I made Terra gain 4 new commands replacing the old ones when she morph. She can't revert and has the morph status for the rest of the battle. She regain her default commands after battle. The code I modified is the portion when the morph/revert command is switched. Since for the purpose of the hack we don't have to consider revert anymore, I focused only on switching the commands. This is the original code:
I simply wrote NOPs to all that segment and I did a JSR to C2/6470. I'm looping four time checking if the current command is one of the four that Terra has. If there is a match, the command is replaced by another one. Simple idea that as usual could be optimized I'm sure:
Here'S a small demonstration: http://www.youtube.com/watch?v=x6pXqHXa0Sc ファイナルファンタジー 修正
Code:
C2/0AD1: BD 2E 20 LDA $202E,X (get contents of menu slot)
C2/0AD4: C5 EE CMP $EE
C2/0AD6: D0 05 BNE $0ADD (if Morphed and menu item isn't Morph(3), branch -OR-
if not Morphed and menu item isn't Revert(4), branch)
C2/0AD8: 49 07 EOR #$07
C2/0ADA: 9D 2E 20 STA $202E,X (toggle menu item between Morph(3) and Revert(4) )
C2/0ADD: E8 INX
C2/0ADE: E8 INX
C2/0ADF: E8 INX
C2/0AE0: 88 DEY
C2/0AE1: D0 EE BNE $0AD1 (loop for all 4 menu items)
I simply wrote NOPs to all that segment and I did a JSR to C2/6470. I'm looping four time checking if the current command is one of the four that Terra has. If there is a match, the command is replaced by another one. Simple idea that as usual could be optimized I'm sure:
Code:
C2/6470: BD 2E 20 LDA $202E,X (get contents of menu slot)
C2/6473: C9 00 CMP #$00 (fight)
C2/6475: F0 12 BEQ $6489 (Branch if fight)
C2/6477: C9 01 CMP #$01 (Item)
C2/6479: F0 12 BEQ $648D (Branch if item)
C2/647B: C9 02 CMP #$02 (magic)
C2/647D: F0 12 BEQ $6491 (branch if magic)
C2/647F: C9 03 CMP #$03 (morph)
C2/6481: F0 02 BEQ $6485 (branch if morph)
C2/6483: 80 11 BRA $6496 (branch to next menu item if none of the four)
C2/6485: 69 07 ADC #07 (change morph to runic)
C2/6487: 80 0A BRA $6493 (branch to set new menu item)
C2/6489: 69 15 ADC #$16 (change fight to jump)
C2/648B: 80 06 BRA $6493 (branch to set new menu item)
C2/648D: 69 06 ADC #$06 (change item to throw)
C2/648F: 80 02 BRA $6493 (branch to set new menu item)
C2/6491: 69 14 ADC #$15 (change magic to X-magic)
C2/6493: 9D 2E 20 STA $202E,X (set new menu item)
C2/6496: E8 INX (Increase three times because
C2/6497: E8 INX the 4 commands are at
C2/6498: E8 INX $202E,X - $2031,X - 2034,X and $2037,X)
C2/6499: 88 DEY (We have finished another command)
C2/649A: D0 D4 BNE $6470 (loop for all 4 menu items)
C2/649C: 60 RTS
Here'S a small demonstration: http://www.youtube.com/watch?v=x6pXqHXa0Sc ファイナルファンタジー 修正
08-16-2016, 11:17 AM
One thing I really liked about FF5 was that certain weapons or items increased the power of magic spells depending on a shared element, such as the Fire Rod boosting the power of Fire elemental spells. I've toyed with the idea of adapting this to the Earring attribute, but I lack the ASM skills necessary to successfully implement it and have given up on using it for my own hack any way. But I think it'd be a fun challenge for others to tinker with.
Funny you should mention that, @"Marketa Lazarova". I believe the origin of the elemental-enhancing equipment in later games was a bug in FF1 that caused enemy elemental weakness to be loaded from the weapon elemental properties of the attacker's weapon instead of from the enemy data when magic was cast.
So...it should be pretty simple to "reinstate" that bug in FFVI, by hooking the code below to a new function that inserts a check for attacker's weapon elemental attack ($3B90,X) in addition to the check for enemy weakness ($3BE0,Y).
Edit: wait, that's pretty dumb. Something that simple would make elemental weapons always do double damage with their own attacks, too. Though I suppose that could easily be solved by adding a check to see if the attack is magical, and skip the weapon elemental stuff if it is.
So...it should be pretty simple to "reinstate" that bug in FFVI, by hooking the code below to a new function that inserts a check for attacker's weapon elemental attack ($3B90,X) in addition to the check for enemy weakness ($3BE0,Y).
Code:
C2/0C0E: B9 E0 3B LDA $3BE0,Y (Weak elements)
Edit: wait, that's pretty dumb. Something that simple would make elemental weapons always do double damage with their own attacks, too. Though I suppose that could easily be solved by adding a check to see if the attack is magical, and skip the weapon elemental stuff if it is.
09-24-2016, 03:55 PM
(08-16-2016, 01:21 PM)seibaby Wrote: Funny you should mention that, @"Marketa Lazarova". I believe the origin of the elemental-enhancing equipment in later games was a bug in FF1 that caused enemy elemental weakness to be loaded from the weapon elemental properties of the attacker's weapon instead of from the enemy data when magic was cast.
So...it should be pretty simple to "reinstate" that bug in FFVI, by hooking the code below to a new function that inserts a check for attacker's weapon elemental attack ($3B90,X) in addition to the check for enemy weakness ($3BE0,Y).
Code:C2/0C0E: B9 E0 3B LDA $3BE0,Y (Weak elements)
Edit: wait, that's pretty dumb. Something that simple would make elemental weapons always do double damage with their own attacks, too. Though I suppose that could easily be solved by adding a check to see if the attack is magical, and skip the weapon elemental stuff if it is.
Or reduce the attack power of the elemental weapons to compensate for the doubling effect.
« Next Oldest | Next Newest »
Users browsing this thread: 1 Guest(s)