Users browsing this thread: 1 Guest(s)
Assembly Programming

#31
Posts: 3,969
Threads: 279
Thanks Received: 236
Thanks Given: 57
Joined: Oct 2011
Reputation: 65
Status
Tissue-aware
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:

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.

  Find
Quote  

#32
Posts: 3,969
Threads: 279
Thanks Received: 236
Thanks Given: 57
Joined: Oct 2011
Reputation: 65
Status
Tissue-aware
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):

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)
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)
  Find
Quote  

#33
Posts: 3,969
Threads: 279
Thanks Received: 236
Thanks Given: 57
Joined: Oct 2011
Reputation: 65
Status
Tissue-aware
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.

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.
  Find
Quote  

#34
Posts: 2,768
Threads: 88
Thanks Received: 24
Thanks Given: 87
Joined: Jun 2009
Reputation: 25
Status
None
now that is an impressive mod for the offering

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
Quote  

#35
Posts: 3,969
Threads: 279
Thanks Received: 236
Thanks Given: 57
Joined: Oct 2011
Reputation: 65
Status
Tissue-aware
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:

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 ファイナルファンタジー 修正
  Find
Quote  

#36
Posts: 32
Threads: 4
Thanks Received: 0
Thanks Given: 0
Joined: Mar 2012
Reputation: 0
Status
None
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.
  Find
Quote  

#37
Posts: 281
Threads: 18
Thanks Received: 13
Thanks Given: 8
Joined: Mar 2014
Reputation: 8
Status
None
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.
  Find
Quote  

#38
Posts: 1
Threads: 0
Thanks Received: 0
Thanks Given: 0
Joined: Sep 2016
Reputation: 0
Status
None
(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.
  Find
Quote  



Forum Jump:

Users browsing this thread: 1 Guest(s)


Theme by Madsiur2017Custom Graphics by JamesWhite