News: 11 March 2016 - Forum Rules
Current Moderators - DarkSol, KingMike, MathOnNapkins, Azkadellia, Danke

Poll

Patching Mysidian Tower Orbs Behavior: http://www.romhacking.net/forum/index.php?topic=29704.msg388989#msg388989

Leave it, flawed as it is; the remakes retained this behavior after all
3 (13.6%)
Keep the random single-character bonus, but remove the 4th character from the RNG
4 (18.2%)
Grant the bonus to all characters, giving them a much-earned buff at this point in the game.
15 (68.2%)

Total Members Voted: 22

Author Topic: Final Fantasy II Restored  (Read 29265 times)

redmagejoe

  • Full Member
  • ***
  • Posts: 185
    • View Profile
Re: Final Fantasy II Restored
« Reply #160 on: January 25, 2020, 05:03:15 pm »
I'd still like to take a look at what the game does (or doesn't do) about multiple equips that give stat bonuses. At most, it should be possible for one to gain +10 Spirit (only 1 Spirit chestpiece), +10 Intellect (only 1 Intellect chestpiece), +30 Strength (there are helms, gloves, and chestpieces that give +10 Strength), and +30 Agility (helms, gloves, and chestpieces). In the cases of Agility and Strength (which judging by the code, it doesn't even really care what the stats are), we want to take into account 1, 2, or 3 of these pieces being equipped at the same time.

  • Ripper appears to display incorrect damage values, which was fixed in remakes. Investigate cause of display and actual damage differing.

Code: [Select]
; control flow target (from $B096)
0x0330B2|$0C:$B0A2:18      CLC
0x0330B3|$0C:$B0A3:A5 44    LDA $44
0x0330B5|$0C:$B0A5:69 14    ADC #$14
0x0330B7|$0C:$B0A7:85 44    STA $44
0x0330B9|$0C:$B0A9:A5 45    LDA $45
0x0330BB|$0C:$B0AB:69 00    ADC #$00
0x0330BD|$0C:$B0AD:85 45    STA $45

Also, this only ADC #$14 (+20) in the code may be related to the Ripper bug, displaying 20 more damage x number of hits in combat, while not actually adding this bonus damage.
« Last Edit: January 25, 2020, 05:18:32 pm by redmagejoe »

Cyneprepou4uk

  • Sr. Member
  • ****
  • Posts: 325
  • I am the baldest romhacker
    • View Profile
Re: Final Fantasy II Restored
« Reply #161 on: January 25, 2020, 06:42:11 pm »
Quote
based on what you posted, we can't make that determination

I disagree. There is CMP at the end of the loop, so he definetly has to clear C from the beginning.

Quote
Anything I missed?

Comparing to original, your new loop will not execute its body with X = #$00, and it has excess execution with X = #$06.
iromhacker.ru - NES ROM hacking tutorials for beginners. Please use Google Translate browser extension

redmagejoe

  • Full Member
  • ***
  • Posts: 185
    • View Profile
Re: Final Fantasy II Restored
« Reply #162 on: January 25, 2020, 07:01:11 pm »
Had to take my eye off of the stat gear issue for a moment due to a bug resulting from combining the combat counter fix with the Firion Spirit Enemy Magic fix. I'm going to bundle them together for compatibility after I tweak the code to account for the new behavior. Freed up a bit more space in the process. Fixed the issue. I'd done some math wrong, and also caught some other oversights. Enemy target-all magic on the party now properly increments the "hit by magic" counters for all party members and does the overflow comparison, while single-target magic had failed to check against the new overflow protection, but is now properly pointed to the sub-routine. Similarly, the wrong counters were being updated for being hit by magic and being hit physically because of a math error on my part.

These two patches have been merged into one, and the first post has been updated accordingly.

Comparing to original, your new loop will not execute its body with X = #$00, and it has excess execution with X = #$06.

I think I see what you mean. Since I removed those two CLCs, I have the 2 bytes I need to revert it to its previous behavior.

Code: [Select]
0x003F0F|$00:$BEFF:A2 00    LDX #$00
0x003F11|$00:$BF01:B5 44    LDA $44,X
0x003F13|$00:$BF03:85 5E    STA $5E
0x003F15|$00:$BF05:B5 45    LDA $45,X
0x003F17|$00:$BF07:85 5F    STA $5F
0x003F19|$00:$BF09:A0 04    LDY #$04
0x003F1B|$00:$BF0B:B1 5E    LDA ($5E),Y
0x003F1D|$00:$BF0D:30 16    BMI $BF25
0x003F1F|$00:$BF0F:18      CLC
0x003F20|$00:$BF10:69 10    ADC #$10
0x003F22|$00:$BF12:A8      TAY
0x003F23|$00:$BF13:B1 7A    LDA ($7A),Y
0x003F25|$00:$BF15:69 0A    ADC #$0A
0x003F27|$00:$BF17:48      PHA
0x003F28|$00:$BF18:98      TYA
0x003F29|$00:$BF19:69 10    ADC #$10
0x003F2B|$00:$BF1B:A8      TAY
0x003F2C|$00:$BF1C:68      PLA
0x003F2D|$00:$BF1D:C9 64    CMP #$64
0x003F2F|$00:$BF1F:90 02    BCC $BF23
0x003F31|$00:$BF21:A9 63    LDA #$63
0x003F33|$00:$BF23:91 7A    STA ($7A),Y
0x003F35|$00:$BF25:E8      INX
0x003F36|$00:$BF26:E8      INX
0x003F37|$00:$BF27:E0 06    CPX #$06
0x003F39|$00:$BF29:D0 D8    BNE $BF01
0x003F3B|$00:$BF2B:60      RTS
« Last Edit: January 26, 2020, 08:20:52 pm by redmagejoe »

Cyneprepou4uk

  • Sr. Member
  • ****
  • Posts: 325
  • I am the baldest romhacker
    • View Profile
Re: Final Fantasy II Restored
« Reply #163 on: January 25, 2020, 09:48:21 pm »
No, I meant that your loop is not properly configured. But reverting to original works as well.
iromhacker.ru - NES ROM hacking tutorials for beginners. Please use Google Translate browser extension

redmagejoe

  • Full Member
  • ***
  • Posts: 185
    • View Profile
Re: Final Fantasy II Restored
« Reply #164 on: January 25, 2020, 09:53:39 pm »
I'm going to leave that block as WIP, since I'd like to figure out the stacking of gears before I commit that. Snooped into Ripper behavior, possibly Mysidian Orbs behavior, abw was working on RNG improvement last, and I still haven't gotten around to that Evasion / MDef delay. I need to focus on putting the finishing touches on my project so I can sort my thoughts and sit down and tackle one thing at a time.

Disch

  • Hero Member
  • *****
  • Posts: 2770
  • NES Junkie
    • View Profile
Re: Final Fantasy II Restored
« Reply #165 on: January 26, 2020, 01:38:09 am »
EDIT:  Misread something.  Ignore me!

redmagejoe

  • Full Member
  • ***
  • Posts: 185
    • View Profile
Re: Final Fantasy II Restored
« Reply #166 on: January 26, 2020, 07:40:18 pm »
And my work project is finished. I'll be back to work on this tomorrow. :)

Code: [Select]
0x0399B5|$0E:$99A5:AF A1 ; $0E:$A1AF   << bottom left orb, Fire Crystal, +10 Strength
0x0399B7|$0E:$99A7:B3 A1 ; $0E:$A1B3   << bottom right orb, Wind Crystal, +10 Agility
0x0399B9|$0E:$99A9:B7 A1 ; $0E:$A1B7   << top left orb, Earth Crystal, +10 Spirit
0x0399BB|$0E:$99AB:BB A1 ; $0E:$A1BB   << top right orb, Water Crystal, +10 Intellect

...

; indirect control flow target (via $99A5)
0x03A1BF|$0E:$A1AF:A9 10    LDA #$10                 << Strength offset: 6110
0x03A1C1|$0E:$A1B1:D0 0A    BNE $A1BD 
; indirect control flow target (via $99A7)
0x03A1C3|$0E:$A1B3:A9 11    LDA #$11                 << Agility offset: 6111
0x03A1C5|$0E:$A1B5:D0 06    BNE $A1BD 
; indirect control flow target (via $99A9)
0x03A1C7|$0E:$A1B7:A9 14    LDA #$14                 << Spirit offset: 6114
0x03A1C9|$0E:$A1B9:D0 02    BNE $A1BD 
; indirect control flow target (via $99AB)
0x03A1CB|$0E:$A1BB:A9 13    LDA #$13                 << Intellect offset: 6113
; control flow target (from $A1B1, $A1B5, $A1B9)
0x03A1CD|$0E:$A1BD:85 80    STA $80                  << store offset in $80 based on which orb and thus stat is being increased
0x03A1CF|$0E:$A1BF:A5 F0    LDA $F0                  << load A with whatever's in $F0 (RNG output to determine character?)
0x03A1D1|$0E:$A1C1:29 C0    AND #$C0                 << bitwise AND against $F0 (???? ????) with #$C0 (1100 0000)
0x03A1D3|$0E:$A1C3:05 80    ORA $80                  << bitwise OR with resultant A value from AND above against $80 (stat offset $10, $11, $13, or $14)
0x03A1D5|$0E:$A1C5:AA      TAX                      << store this A value in X to be used as the determined offset for which character gets the bonus
0x03A1D6|$0E:$A1C6:BD 00 61 LDA $6100,X          << load A with baseline for character stats, X as offset
0x03A1D9|$0E:$A1C9:18      CLC       
0x03A1DA|$0E:$A1CA:69 0A    ADC #$0A                 << adds 10 to the appropriate stat
0x03A1DC|$0E:$A1CC:C9 64    CMP #$64                 << prevent stat from going above 99, compare to 100
0x03A1DE|$0E:$A1CE:90 02    BCC $A1D2                << does not exceed cap, proceed to store new stat value
0x03A1E0|$0E:$A1D0:A9 63    LDA #$63                 << set stat to 99 if >99
; control flow target (from $A1CE)
0x03A1E2|$0E:$A1D2:9D 00 61 STA $6100,X          << store new value of stat, baseline for character stats, X as offset
0x03A1E5|$0E:$A1D5:BD 10 61 LDA $6110,X          << base character stats that display in stat window (base + equipment bonuses), X as offset
0x03A1E8|$0E:$A1D8:18      CLC       
0x03A1E9|$0E:$A1D9:69 0A    ADC #$0A                 << add 10 to window stats as well
0x03A1EB|$0E:$A1DB:C9 64    CMP #$64                 << prevent stat from going above 99, compare to 100
0x03A1ED|$0E:$A1DD:90 02    BCC $A1E1                << does not exceed cap, proceed to store new stat value
0x03A1EF|$0E:$A1DF:A9 63    LDA #$63                 << set stat to 99 if >99
; control flow target (from $A1DD)
0x03A1F1|$0E:$A1E1:9D 10 61 STA $6110,X          << store new value of stat, baseline for character's window stats, X as offset
0x03A1F4|$0E:$A1E4:A4 A0    LDY $A0   
0x03A1F6|$0E:$A1E6:20 07 99 JSR $9907 
0x03A1F9|$0E:$A1E9:AD 00 7B LDA $7B00 
0x03A1FC|$0E:$A1EC:60      RTS

This appears to be related to the orbs at the top of the Mysidian Tower. Not trying to lose sight of individual goals, but deciphering the disassembly is also beneficial.

So having looked at playthroughs on YouTube of all versions, it seems that in every version, NES, GBA, WonderSwan, GBA, PSP, the orbs randomly assign the bonus to a single character. I guess the question now is: Since this is not listed as a bug, but a possible improvement, what everyone's opinion on this adjustment? Disrespecting the legacy and precedent of the game, or a sensible improvement upon the original concept? A friend provided me with two suggestions: My personal bias is towards giving all 4 characters the stat bonuses, though that may be TOO much of an improvement, or at the least limiting the randomly chosen character to the permanent 3.

EDIT: I believe I've deciphered this routine sufficiently, with the only uncertainty being $F0, which I can only assume is what's responsible for choosing the character to randomly get the bonus. Looking at $F0 in RAM watch, it's clearly related to the RNG. I may come back to this, as much as I know about it now, when I have a more solid idea of HOW I would want to change this, rather than WHAT to change.



I still need to make more sense of what's happening in my code block above, namely with the memory addresses and what they represent being loaded and moved around ($5E, $5F, $7A, $44, $45). I'm going through the menu with stepping through and breakpoints on reading $44 and $45, and going through the control flow, but I'm just having a difficult time understanding the context of everything and what the actual values I'm seeing mean. I'll try to focus my mind and jot notes and observations here that may allow other more savvy and experienced romhackers to offer insight.
« Last Edit: January 26, 2020, 09:48:18 pm by redmagejoe »

Disch

  • Hero Member
  • *****
  • Posts: 2770
  • NES Junkie
    • View Profile
Re: Final Fantasy II Restored
« Reply #167 on: January 26, 2020, 09:52:18 pm »
Quote
Looking at $F0 in RAM watch, it's clearly related to the RNG.

F0/F1 look like a frame counter to me.

Which, yeah drawing from the frame counter is usually either linked to animation or RNG.

redmagejoe

  • Full Member
  • ***
  • Posts: 185
    • View Profile
Re: Final Fantasy II Restored
« Reply #168 on: January 26, 2020, 09:56:47 pm »
F0/F1 look like a frame counter to me.

Which, yeah drawing from the frame counter is usually either linked to animation or RNG.

Yeah, I should have clarified, sorry. What I meant by "clearly" was that it was rapidly cycling from 00 to FF and repeating, in a rate that must have been at least if not higher than 60 Hertz. So frame counter, yeah. I'm assuming that would only be important to the RNG unless there's some other nuanced application I'm not thinking of (maybe timing checks in other games like Final Fantasy VI or fighting games?). So I guess in the case of the orbs, there's no arbitrarily manipulated RNG like in some games that are based on inputs. The character chosen for the orb bonus is apparently primarily determined by what frame upon which you activate it.

Either way, I'd like to set this aside until I have taken care of the game's bugs first. Hopefully my commenting will at least be useful to abw's progress on his disassembly.

Modified 99 Cap Patch
Code: [Select]
; control flow target (from $98BE)
0x003EF8|$00:$BEE8:A0 10    LDY #$10   
; control flow target (from $BEFD)
0x003EFA|$00:$BEEA:B1 7A    LDA ($7A),Y
0x003EFC|$00:$BEEC:48      PHA       
0x003EFD|$00:$BEED:98      TYA       
0x003EFE|$00:$BEEE:18      CLC       
0x003EFF|$00:$BEEF:69 10    ADC #$10   
0x003F01|$00:$BEF1:A8      TAY       
0x003F02|$00:$BEF2:68      PLA       
0x003F03|$00:$BEF3:91 7A    STA ($7A),Y
0x003F05|$00:$BEF5:C8      INY       
0x003F06|$00:$BEF6:98      TYA       
0x003F07|$00:$BEF7:38      SEC       
0x003F08|$00:$BEF8:E9 10    SBC #$10   
0x003F0A|$00:$BEFA:A8      TAY       
0x003F0B|$00:$BEFB:C0 15    CPY #$15   
0x003F0D|$00:$BEFD:D0 EB    BNE $BEEA
0x003F0F|$00:$BEFF:A2 00    LDX #$00
; control flow target (from $BF10)
0x003F11|$00:$BF01:B5 44    LDA $44,X
0x003F13|$00:$BF03:85 5E    STA $5E
0x003F15|$00:$BF05:B5 45    LDA $45,X
0x003F17|$00:$BF07:85 5F    STA $5F
0x003F19|$00:$BF09:A0 04    LDY #$04
0x003F1B|$00:$BF0B:B1 5E    LDA ($5E),Y
0x003F1D|$00:$BF0D:30 10    BMI $BF1F
0x003F1F|$00:$BF0F:18      CLC
0x003F20|$00:$BF10:69 20    ADC #$20
0x003F22|$00:$BF12:A8      TAY
0x003F23|$00:$BF13:B1 7A    LDA ($7A),Y
0x003F25|$00:$BF15:69 0A    ADC #$0A
0x003F27|$00:$BF17:C9 64    CMP #$64
0x003F29|$00:$BF19:90 02    BCC $BF23
0x003F2B|$00:$BF1B:A9 63    LDA #$63
0x003F2D|$00:$BF1D:91 7A    STA ($7A),Y
0x003F2F|$00:$BF1F:E8      INX
0x003F30|$00:$BF20:E8      INX
0x003F31|$00:$BF21:E0 06    CPX #$06
0x003F33|$00:$BF23:D0 DC    BNE $BF01
0x003F35|$00:$BF25:60      RTS
0x003F36|$00:$BF26:EA      NOP
0x003F37|$00:$BF27:EA      NOP
0x003F38|$00:$BF28:EA      NOP
0x003F39|$00:$BF29:EA      NOP
0x003F3A|$00:$BF2A:EA      NOP
0x003F3B|$00:$BF2B:EA      NOP

I think I see the problem watching RAM. When I try to equip a second piece of equipment and the execution breaks, once it arrives at $BF13, the value loaded is $6110 @ $45 (69 Strength), which is the base Strength for Firion. As such it's performing the math that sets the value of $6120 (window/effective Strength) based upon the base Strength, rather than evaluating what $6120 is from the beginning. So it's not that they're deliberately not stacking, it's that the arithmetic is done in such a way that it always assumes your effective stat is the same as your base stat any time you put on one of these pieces of equipment. Let's see if we can't modify that...

EDIT: I cannot BELIEVE what an easy fix that was. And it doesn't APPEAR to have any drawbacks, as the subtraction routine operates properly even with this change. I even anticipated the case of "what does it do when one of the equips pushes you up to 99 when it would usually go over?" and it still seems to by default revert the stat to the correct amount rather than docking you an extra point (i.e. 90 -> 99 -> 90 rather than 89). Updated code block above, trying to figure out what to do with these 6 new bytes I've created. I feel like when this is all said and done, some code shuffling may be in order to make use of the free space we're creating. If you think you can get that RNG fix you wanted to squish down to 6 bytes instead of 12, abw, we can stick it in these bytes I just freed up. :)



The return of... the Evasion/Magic Defense Level Up Delay! ::)

At this rate, I've delayed fixing this almost as long as the delay bug itself.

Code: [Select]
; level up Evasion
0x01660B|$05:$A5FB:A9 7D    LDA #$7D    ; $7D37; Character #1 counter for times physically attacked by enemy
0x01660D|$05:$A5FD:85 45    STA $45   
0x01660F|$05:$A5FF:A9 37    LDA #$37    ; $7D37; Character #1 counter for times physically attacked by enemy
0x016611|$05:$A601:85 44    STA $44   
0x016613|$05:$A603:AD 37 AC LDA $AC37  ; base Evasion credit for being physically attacked
0x016616|$05:$A606:85 46    STA $46    ; base credit amount for being attacked at all
0x016618|$05:$A608:A0 30    LDY #$30    ; Skill offset for Evasion level
0x01661A|$05:$A60A:84 47    STY $47   
0x01661C|$05:$A60C:20 42 A8 JSR $A842  ; level up Evasion/Magic Resist if applicable
; level up Magic Resist
0x01661F|$05:$A60F:A9 7D    LDA #$7D    ; $7D3B; Character #1 counter for times magically attacked by enemy
0x016621|$05:$A611:85 45    STA $45   
0x016623|$05:$A613:A9 3B    LDA #$3B    ; $7D3B; Character #1 counter for times magically attacked by enemy
0x016625|$05:$A615:85 44    STA $44   
0x016627|$05:$A617:AD 38 AC LDA $AC38  ; base Magic Resist credit for being magically attacked
0x01662A|$05:$A61A:85 46    STA $46    ; base credit amount for being attacked at all
0x01662C|$05:$A61C:A0 32    LDY #$32    ; Skill offset for Magic Resist level
0x01662E|$05:$A61E:84 47    STY $47   
0x016630|$05:$A620:20 42 A8 JSR $A842  ; level up Evasion/Magic Resist if applicable

Code: [Select]
; level up Evasion/Magic Resist if applicable
; control flow target (from $A60C, $A620)
0x016852|$05:$A842:A4 9E    LDY $9E    ; Character index
0x016854|$05:$A844:B1 44    LDA ($44),Y ; counter for times physically/magically attacked
0x016856|$05:$A846:F0 24    BEQ $A86C  ; no pain => no gain
0x016858|$05:$A848:18      CLC       
0x016859|$05:$A849:65 22    ADC $22    ; battle rank?
0x01685B|$05:$A84B:65 46    ADC $46    ; base credit amount for being attacked at all
0x01685D|$05:$A84D:A4 47    LDY $47    ; offset for Evasion/Magic Resist skill level, whichever one we're dealing with at the moment
0x01685F|$05:$A84F:F1 7E    SBC ($7E),Y ; Evasion/Magic Resist skill level
0x016861|$05:$A851:E9 0A    SBC #$0A    ; your first 10 points don't count for anything
0x016863|$05:$A853:90 17    BCC $A86C  ; not enough pain => no gain
0x016865|$05:$A855:C8      INY        ; offset for Evasion/Magic Resist skill experience, whichever one we're dealing with at the moment
0x016866|$05:$A856:71 7E    ADC ($7E),Y ; Evasion/Magic Resist skill experience
0x016868|$05:$A858:C9 64    CMP #$64   
0x01686A|$05:$A85A:90 0E    BCC $A86A  ; if experience < 100, just update experience, otherwise increase level
0x01686C|$05:$A85C:88      DEY        ; offset for Evasion/Magic Resist skill level, whichever one we're dealing with at the moment
0x01686D|$05:$A85D:B1 7E    LDA ($7E),Y ; Evasion/Magic Resist skill level
0x01686F|$05:$A85F:AA      TAX       
0x016870|$05:$A860:E8      INX        ; level++
0x016871|$05:$A861:20 6D A8 JSR $A86D  ; cap X at 15
0x016874|$05:$A864:8A      TXA       
0x016875|$05:$A865:91 7E    STA ($7E),Y ; save new Evasion/Magic Resist skill level
0x016877|$05:$A867:C8      INY        ; offset for Evasion/Magic Resist skill experience, whichever one we're dealing with at the moment
0x016878|$05:$A868:A9 00    LDA #$00    ; reset experience to zero
; control flow target (from $A85A)
0x01687A|$05:$A86A:91 7E    STA ($7E),Y ; save new Evasion/Magic Resist skill experience
; control flow target (from $A846, $A853)
0x01687C|$05:$A86C:60      RTS

Code: [Select]
; cap X at 15
; control flow target (from $A5D0, $A861, $A97A)
0x01687D|$05:$A86D:E0 10    CPX #$10   
0x01687F|$05:$A86F:90 02    BCC $A873 
0x016881|$05:$A871:A2 0F    LDX #$0F   
; control flow target (from $A86F)
0x016883|$05:$A873:60      RTS 

Neither $7D7D (Firion's combat temporary MDef level holder) nor $612C (Firion's permanent MDef level stat) are updated from 07 to 08 until a piece of equipment is changed or a battle is entered. Despite the STA ($7E),Y at $A865, $612C is not being immediately updated. The question then becomes where is this value being stored, and what instruction is executed to "refresh" or update stats in either of these cases? Would it not make more sense to save to $612C immediately?
« Last Edit: January 29, 2020, 01:34:10 am by redmagejoe »

Grimoire LD

  • Sr. Member
  • ****
  • Posts: 415
    • View Profile
Re: Final Fantasy II Restored
« Reply #169 on: January 29, 2020, 08:18:05 am »
Hmm... do the Mysidian Orbs actually work right? The code looks solid enough, but I recall seeing HCBailly's ancient Let's Play of Final Fantasy II and I distinctly recall that he had "A1" intelligence on one of his characters.

Ah, found it. In the video his Firion has A1 Soul after using the Orbs. https://youtu.be/XcNNK2I_NVM?list=PL31D24C1307A71BD4&t=409

abw

  • Sr. Member
  • ****
  • Posts: 351
    • View Profile
Re: Final Fantasy II Restored
« Reply #170 on: January 29, 2020, 08:31:10 am »
If you think you can get that RNG fix you wanted to squish down to 6 bytes instead of 12, abw, we can stick it in these bytes I just freed up. :)
Except that your new free space is in bank 0, so I'd have to add code to swap that bank in and out to reach the free space :P. Once I get around to figuring out possible value ranges on the 2 RNG calls that use calculated lower and upper bounds, hopefully it'll be safe to assume that the bounds make sense and I can scrap the bounds checking code, which will free up plenty of space. I'm just worried that in a game where so many upper bounds don't get checked, the fact that they added checking code here might mean they really need it for something.

In other news, I've updated both versions of my disassembly with more labels and comments including redmagejoe's findings.

redmagejoe

  • Full Member
  • ***
  • Posts: 185
    • View Profile
Re: Final Fantasy II Restored
« Reply #171 on: January 29, 2020, 09:10:10 am »
Hmm... do the Mysidian Orbs actually work right? The code looks solid enough, but I recall seeing HCBailly's ancient Let's Play of Final Fantasy II and I distinctly recall that he had "A1" intelligence on one of his characters.

Ah, found it. In the video his Firion has A1 Soul after using the Orbs. https://youtu.be/XcNNK2I_NVM?list=PL31D24C1307A71BD4&t=409

It's likely that came from equipment, not the orbs, due to the bug we just recently fixed. There's a compare to 100, and if so, set to 99 set of instructions already in the Mysidian Orb code. EDIT: Yeah, he has White Robe on Firion, meaning he has 91 base Spirit, and then that robe is giving him +10 Spirit. The orbs work fine by default it looks like. It also checks both base stat and effective stat and raises them both by 10, checking and adjusting them as necessary. So if Firion had gotten the Spirit bonus, his Spirit would have been set back to 99. Of course without the bug fix, it would just become A9 once he unequipped and re-equipped the robe. :P
« Last Edit: January 29, 2020, 09:15:56 am by redmagejoe »

Grimoire LD

  • Sr. Member
  • ****
  • Posts: 415
    • View Profile
Re: Final Fantasy II Restored
« Reply #172 on: January 29, 2020, 09:20:54 am »
Ah, I see. I was unaware that it was the equipment that allowed for this breaking of parameters. Thank you for the succinct explanation.

Vanya

  • Hero Member
  • *****
  • Posts: 1536
    • View Profile
Re: Final Fantasy II Restored
« Reply #173 on: January 29, 2020, 09:36:25 pm »
Hey all. I just wanted to pop in and say how awesome it is that you guys are working on this project.
FFII is a pretty underappreciated game, and it has a lot of potential as a basis for hacking.
Thank you all for your hard work!

redmagejoe

  • Full Member
  • ***
  • Posts: 185
    • View Profile
Re: Final Fantasy II Restored
« Reply #174 on: January 29, 2020, 09:43:58 pm »
The positive feedback is enough to make me want to keep going. I feel like I'm the wrong person to tackle such a project, honestly, with how inexperienced I am compared to the big names behind other such ambitious projects. Still, it's been a learning experience, I didn't want to keep begging for someone to fix it up when I felt I could roll up my sleeves and take a crack at it, and it's really, really rewarding when I manage to figure out how the game ticks enough to fix another bug.

While this started from my own desires, everyone's support is super appreciated and makes this project all the more worthwhile to me. :)

Leviathan Mist

  • Jr. Member
  • **
  • Posts: 41
    • View Profile
Re: Final Fantasy II Restored
« Reply #175 on: January 30, 2020, 03:27:30 am »
The positive feedback is enough to make me want to keep going. I feel like I'm the wrong person to tackle such a project, honestly, with how inexperienced I am compared to the big names behind other such ambitious projects. Still, it's been a learning experience, I didn't want to keep begging for someone to fix it up when I felt I could roll up my sleeves and take a crack at it, and it's really, really rewarding when I manage to figure out how the game ticks enough to fix another bug.

While this started from my own desires, everyone's support is super appreciated and makes this project all the more worthwhile to me. :)

You gotta start somewhere. Just think of this as the beginning of your ROM hacking career. ASM hacking opens up a whole new realm of possibilities.

Disch

  • Hero Member
  • *****
  • Posts: 2770
  • NES Junkie
    • View Profile
Re: Final Fantasy II Restored
« Reply #176 on: January 30, 2020, 01:31:58 pm »
+1

There is no better way to expand your skills and grow as a person than to immerse yourself in a project that you enjoy.

redmagejoe

  • Full Member
  • ***
  • Posts: 185
    • View Profile
Re: Final Fantasy II Restored
« Reply #177 on: January 30, 2020, 04:45:06 pm »
Seems like the current popular vote is for giving the bonus to all 4 characters. I'll leave the poll going until all the bugs are fixed and work on that down the line.

I'm stumped regarding the Evasion/MDef delay again though. I just don't know what address is being referenced by STA ($7E),Y, but it's clearly neither of the addresses that SHOULD be holding Evasion or MDef level. Stats should be refreshed, I think, the moment that a character's stat window is opened, rather than when something forces it to update. I'll have to look into what routine is running to refresh stats when you change equipment or anything of that nature.

So watching the relevant addresses in RAM for MDef in the case I'm testing (7D7D for Firion's MDef in combat and 612C for what appears in stat window), it appears to break upon leaving combat here,

Code: [Select]
03D3C8:91 82     STA ($82),Y @ $7D7D = #$07
in what looks like combat stats are being stored before it returns to the overworld with no further breaks. So it doesn't actually store the new value in 612C until something prompts it. Strangely though, stats are not handled in this way, as they immediately write to the relevant permanent stat addresses the moment they increase. As such rather than tampering with that routine and causing potentially harmful side-effects, I should see if I can't simply insert a JSR to the routine that refreshes stats. I'll see what I can do about either putting that at the end of a battle, or having it run the moment the menu screen opens.

I think 0x0018B2 is what I want to JSR to when the menu screen opens, as it is run everytime one tries to change equipment, enters a battle (when these stats get refreshed), and appears to be what's in charge of refreshing stats. I just have to figure out where in code the menu screen opening is handled...

So I just spent the last hour or two chasing down control flow and setting breakpoints, and FINALLY found the routine that handles going to the pause menu. It's at 0x03ACD4 in the disassembly, fortuitously right below the routine that handles spell levels off of which I shaved 3 bytes (just enough for a JSR!) with the Spell Max Level Fix. I also determined precisely where to point a JSR if I want stats to be refreshed, 0x001890. Alas, likely again due to fixed bank, I cannot use JSR $9880, as it points to 0x039890 instead of 0x001890. How frustrating... Anyone can think of a workaround? Also, more specifically, the very beginning of this entire rabbit hole starts the moment the Start button is hit at

Code: [Select]
0x03C175|$0F:$C165:A9 00    LDA #$00
Another solution I'm looking at is if I could have this stat refresh apply immediately at the end of a battle, or at least where there's stat gains. I'll see if I made enough room with changes to the stat ups to fit a JSR in, or if it will even be able to point to the correct bank. I tried moving my first fix, which had some blank space inside it, around a bit, and stick a JSR inside the evasion/mdef up code. Alas, still limited by banks. I'm stumped on how or where to stick this stat refreshing function call currently, so I'm going to start looking into some of the other bugs on the list.



Quote
  • Investigate possible overflow on Evasion % when Agility/Evasion level and Shield equipped modifier add up.

I believe that the issue here is that the code does not take two shields into account, and it is simply setting the character's Evasion to whatever bonus the second shield gives, rather than attempting to ADC it to current evasion and then comparing the new value to 99.

Code: [Select]
; control flow target (from $9A19)
0x001A4B|$00:$9A3B:18      CLC       
0x001A4C|$00:$9A3C:A5 56    LDA $56   
0x001A4E|$00:$9A3E:65 6F    ADC $6F   
0x001A50|$00:$9A40:85 56    STA $56   
0x001A52|$00:$9A42:A5 57    LDA $57   
0x001A54|$00:$9A44:69 00    ADC #$00   
0x001A56|$00:$9A46:85 57    STA $57   
0x001A58|$00:$9A48:A0 01    LDY #$01   
0x001A5A|$00:$9A4A:18      CLC       
0x001A5B|$00:$9A4B:B1 44    LDA ($44),Y
0x001A5D|$00:$9A4D:71 46    ADC ($46),Y
0x001A5F|$00:$9A4F:71 48    ADC ($48),Y
0x001A61|$00:$9A51:85 58    STA $58   
0x001A63|$00:$9A53:A9 00    LDA #$00   
0x001A65|$00:$9A55:69 00    ADC #$00   
0x001A67|$00:$9A57:85 59    STA $59   
0x001A69|$00:$9A59:38      SEC       
0x001A6A|$00:$9A5A:A5 56    LDA $56   
0x001A6C|$00:$9A5C:E5 58    SBC $58   
0x001A6E|$00:$9A5E:85 56    STA $56   
0x001A70|$00:$9A60:A5 57    LDA $57   
0x001A72|$00:$9A62:E5 59    SBC $59   
0x001A74|$00:$9A64:85 57    STA $57   
0x001A76|$00:$9A66:B0 04    BCS $9A6C 
0x001A78|$00:$9A68:A9 00    LDA #$00   
0x001A7A|$00:$9A6A:85 56    STA $56   
; control flow target (from $9A66)
0x001A7C|$00:$9A6C:A0 2B    LDY #$2B   
0x001A7E|$00:$9A6E:A5 56    LDA $56   
0x001A80|$00:$9A70:20 84 9B JSR $9B84  ; cap A at 99
0x001A83|$00:$9A73:91 7A    STA ($7A),Y     <<< Evasion is being set here, rather than added and capped

...

; cap A at 99
; control flow target (from $9949, $995E, $9A70, $9AC1)
0x001B94|$00:$9B84:C9 64    CMP #$64
0x001B96|$00:$9B86:90 02    BCC $9B8A
0x001B98|$00:$9B88:A9 63    LDA #$63
; control flow target (from $9B86)
0x001B9A|$00:$9B8A:60      RTS
« Last Edit: January 30, 2020, 10:53:57 pm by redmagejoe »

BlazeHeatnix

  • Full Member
  • ***
  • Posts: 122
    • View Profile
Re: Final Fantasy II Restored
« Reply #178 on: January 31, 2020, 01:14:10 am »
I don't know if it's been mentioned in this thread, but here's a possible inclusion for a Restored-esque update to the game: more music. The Origins-exclusive extra boss themes could be added to the game, adding the extra sections to the Prelude or Chocobo theme (it desperately needs it), or perhaps even the unused music that Uematsu wrote but ultimately discarded.

https://youtu.be/Xj7a91dlI4c?t=1379
« Last Edit: January 31, 2020, 01:19:46 am by BlazeHeatnix »

redmagejoe

  • Full Member
  • ***
  • Posts: 185
    • View Profile
Re: Final Fantasy II Restored
« Reply #179 on: January 31, 2020, 01:22:24 am »
I don't know if it's been mentioned in this thread, but here's a possible inclusion for a Restored-esque update to the game: more music. The Origins-exclusive extra boss themes could be added to the game, or perhaps even the unused music that Uematsu wrote but ultimately discarded.

https://youtu.be/Xj7a91dlI4c?t=1379

I have consulted with Leviathan Mist about the feasibility of new music, space-wise, and it's certainly not outside the realm of possibility from what he explained to me. Having said that, whether he decides to actually take a crack at it or not is completely up to him, and I don't wish to impose upon him one way or the other. Battle Scene 3 might be neat to use specifically for the Behemoth encounter in Coliseum, though I was also toying with the idea of a demake of the Dawn of Souls / Anniversary boss music to replace the current boss music, which is used only for the final boss of the game. Ideally that would be the same case for this patch. The prelude would be the most feasible, requiring only at most 80 bytes. The major limitation on our available free space is the MMC1 mapper, I think. I don't know enough about mappers though to speak with any real authority on that matter.

Like this, but only with the RP2A03: https://www.youtube.com/watch?v=2Yqtrvc71ns

I would like to get the bugs hammered out before I look into enhancements. As such I'm holding off on the Mysidian Orbs improvement (which I know what needs to be done, just not quite the how), I'm at a standstill on the Evasion/MDef delay (again, know the what, just a matter of the how), and I don't know as much as I'd like to about that code handling the shield equipping and evasion going down rather than up or staying where it is.

I've decided to start looking at the spell bugs, because abw actually did an excellent job labeling those and it was very easy to find their locations in the disassembly. I'm doing some RAM watching and testing right now to see if I can't fix Protect. The offset from $7D7A (combat stats) for bonus defense from Protect is $27, and indeed only Guy's increases. Locating where it's written to, I can see that there are no writes to other character's offsets.

Code: [Select]
Protect $7E01 Breaks
0x33478
0x3357E
0x334BF
0x33518

Breaks to writing at $7E01 (Guy/Char3's bonus defense from Protect) show that during the animation for cast-all, these 4 breaks trigger on every character "handled" by the spell. So it is not an issue of repeating, but rather adjusting the offset. My theory is that it should be reading in the target of the spell, but it is only reading in the caster's character index. I'll put up the relevant code surrounding these addresses momentarily. It cycles through the following code 1 time per character cast upon.

Code: [Select]
; control flow target (from $B3EA)
0x03341D|$0C:$B40D:A0 25    LDY #$25
0x03341F|$0C:$B40F:B1 9F    LDA ($9F),Y
0x033421|$0C:$B411:85 29    STA $29
0x033423|$0C:$B413:A5 6C    LDA $6C
0x033425|$0C:$B415:AA      TAX
0x033426|$0C:$B416:CA      DEX
0x033427|$0C:$B417:8A      TXA
0x033428|$0C:$B418:85 6C    STA $6C
0x03342A|$0C:$B41A:18      CLC
0x03342B|$0C:$B41B:69 64    ADC #$64
0x03342D|$0C:$B41D:85 E4    STA $E4
0x03342F|$0C:$B41F:A5 6C    LDA $6C
0x033431|$0C:$B421:85 00    STA $00
0x033433|$0C:$B423:A9 07    LDA #$07
0x033435|$0C:$B425:85 02    STA $02
0x033437|$0C:$B427:A9 00    LDA #$00
0x033439|$0C:$B429:85 01    STA $01
0x03343B|$0C:$B42B:85 03    STA $03
; call to code in a different bank ($0F:$FC98)
0x03343D|$0C:$B42D:20 98 FC JSR $FC98  ; 16-bit multiplication (little endian): $00-$01 * $02-$03, product stored in $04-$07; leaves X at #$00, Y not changed
0x033440|$0C:$B430:A5 04    LDA $04
0x033442|$0C:$B432:69 D9    ADC #$D9
0x033444|$0C:$B434:85 44    STA $44
0x033446|$0C:$B436:A5 05    LDA $05
0x033448|$0C:$B438:69 85    ADC #$85
0x03344A|$0C:$B43A:85 45    STA $45
0x03344C|$0C:$B43C:A0 00    LDY #$00
0x03344E|$0C:$B43E:B1 44    LDA ($44),Y
0x033450|$0C:$B440:85 5E    STA $5E
0x033452|$0C:$B442:C8      INY
0x033453|$0C:$B443:B1 44    LDA ($44),Y
0x033455|$0C:$B445:85 46    STA $46
0x033457|$0C:$B447:C8      INY
0x033458|$0C:$B448:B1 44    LDA ($44),Y
0x03345A|$0C:$B44A:85 47    STA $47
0x03345C|$0C:$B44C:C8      INY
0x03345D|$0C:$B44D:B1 44    LDA ($44),Y
0x03345F|$0C:$B44F:85 48    STA $48
0x033461|$0C:$B451:C8      INY
0x033462|$0C:$B452:B1 44    LDA ($44),Y
0x033464|$0C:$B454:85 49    STA $49
0x033466|$0C:$B456:C8      INY
0x033467|$0C:$B457:B1 44    LDA ($44),Y
0x033469|$0C:$B459:8D B1 7C STA $7CB1
0x03346C|$0C:$B45C:C8      INY
0x03346D|$0C:$B45D:B1 44    LDA ($44),Y
0x03346F|$0C:$B45F:8D B0 7C STA $7CB0
0x033472|$0C:$B462:A0 26    LDY #$26
0x033474|$0C:$B464:A2 00    LDX #$00
; control flow target (from $B46E)
0x033476|$0C:$B466:B5 46    LDA $46,X
0x033478|$0C:$B468:91 9F    STA ($9F),Y    <<< 1st break
0x03347A|$0C:$B46A:C8      INY
0x03347B|$0C:$B46B:E8      INX
0x03347C|$0C:$B46C:E0 04    CPX #$04
0x03347E|$0C:$B46E:D0 F6    BNE $B466
0x033480|$0C:$B470:A5 6C    LDA $6C
0x033482|$0C:$B472:C9 14    CMP #$14
0x033484|$0C:$B474:B0 08    BCS $B47E
0x033486|$0C:$B476:A0 12    LDY #$12
0x033488|$0C:$B478:20 51 B5 JSR $B551
0x03348B|$0C:$B47B:4C 87 B4 JMP $B487

; control flow target (from $B474)
0x03348E|$0C:$B47E:C9 28    CMP #$28
0x033490|$0C:$B480:B0 05    BCS $B487
0x033492|$0C:$B482:A0 13    LDY #$13
0x033494|$0C:$B484:20 51 B5 JSR $B551
; control flow target (from $B40A, $B47B, $B480)
0x033497|$0C:$B487:20 76 AF JSR $AF76
0x03349A|$0C:$B48A:29 C0    AND #$C0
0x03349C|$0C:$B48C:F0 0D    BEQ $B49B
0x03349E|$0C:$B48E:A5 6C    LDA $6C
0x0334A0|$0C:$B490:C9 15    CMP #$15
0x0334A2|$0C:$B492:F0 07    BEQ $B49B
0x0334A4|$0C:$B494:C9 17    CMP #$17
0x0334A6|$0C:$B496:F0 03    BEQ $B49B
0x0334A8|$0C:$B498:4C 73 BE JMP $BE73

; control flow target (from $B48C, $B492, $B496)
0x0334AB|$0C:$B49B:A5 A6    LDA $A6
0x0334AD|$0C:$B49D:F0 12    BEQ $B4B1
0x0334AF|$0C:$B49F:A0 26    LDY #$26
0x0334B1|$0C:$B4A1:B1 9F    LDA ($9F),Y
0x0334B3|$0C:$B4A3:85 70    STA $70
0x0334B5|$0C:$B4A5:4A      LSR
0x0334B6|$0C:$B4A6:91 9F    STA ($9F),Y
0x0334B8|$0C:$B4A8:C8      INY
0x0334B9|$0C:$B4A9:B1 9F    LDA ($9F),Y
0x0334BB|$0C:$B4AB:85 71    STA $71
0x0334BD|$0C:$B4AD:4A      LSR
0x0334BE|$0C:$B4AE:4A      LSR
0x0334BF|$0C:$B4AF:91 9F    STA ($9F),Y    <<< 3rd break
; control flow target (from $B49D)
0x0334C1|$0C:$B4B1:20 76 AF JSR $AF76
0x0334C4|$0C:$B4B4:29 C0    AND #$C0
0x0334C6|$0C:$B4B6:F0 0B    BEQ $B4C3
0x0334C8|$0C:$B4B8:A5 6C    LDA $6C
0x0334CA|$0C:$B4BA:C9 15    CMP #$15
0x0334CC|$0C:$B4BC:F0 05    BEQ $B4C3
0x0334CE|$0C:$B4BE:C9 17    CMP #$17
0x0334D0|$0C:$B4C0:F0 01    BEQ $B4C3
0x0334D2|$0C:$B4C2:60      RTS

; control flow target (from $B4B6, $B4BC, $B4C0)
0x0334D3|$0C:$B4C3:A5 6C    LDA $6C
0x0334D5|$0C:$B4C5:C9 14    CMP #$14
0x0334D7|$0C:$B4C7:B0 03    BCS $B4CC
0x0334D9|$0C:$B4C9:20 12 BC JSR $BC12
; control flow target (from $B4C7)
0x0334DC|$0C:$B4CC:A0 28    LDY #$28
0x0334DE|$0C:$B4CE:B1 9F    LDA ($9F),Y
0x0334E0|$0C:$B4D0:A0 17    LDY #$17
0x0334E2|$0C:$B4D2:31 A1    AND ($A1),Y
0x0334E4|$0C:$B4D4:F0 03    BEQ $B4D9
0x0334E6|$0C:$B4D6:4C FB BC JMP $BCFB

; control flow target (from $B4D4)
0x0334E9|$0C:$B4D9:A5 5E    LDA $5E
0x0334EB|$0C:$B4DB:0A      ASL
0x0334EC|$0C:$B4DC:18      CLC
0x0334ED|$0C:$B4DD:69 8A    ADC #$8A
0x0334EF|$0C:$B4DF:85 44    STA $44
0x0334F1|$0C:$B4E1:A9 00    LDA #$00
0x0334F3|$0C:$B4E3:69 BE    ADC #$BE
0x0334F5|$0C:$B4E5:85 45    STA $45
0x0334F7|$0C:$B4E7:A0 00    LDY #$00
0x0334F9|$0C:$B4E9:B1 44    LDA ($44),Y
0x0334FB|$0C:$B4EB:85 46    STA $46
0x0334FD|$0C:$B4ED:C8      INY
0x0334FE|$0C:$B4EE:B1 44    LDA ($44),Y
0x033500|$0C:$B4F0:85 47    STA $47
0x033502|$0C:$B4F2:20 87 BE JSR $BE87
0x033505|$0C:$B4F5:A0 0A    LDY #$0A
0x033507|$0C:$B4F7:B1 9F    LDA ($9F),Y
0x033509|$0C:$B4F9:C8      INY
0x03350A|$0C:$B4FA:11 9F    ORA ($9F),Y
0x03350C|$0C:$B4FC:D0 06    BNE $B504
0x03350E|$0C:$B4FE:A0 08    LDY #$08
0x033510|$0C:$B500:A9 80    LDA #$80
0x033512|$0C:$B502:91 9F    STA ($9F),Y
; control flow target (from $B4FC)
0x033514|$0C:$B504:A5 71    LDA $71
0x033516|$0C:$B506:A0 27    LDY #$27
0x033518|$0C:$B508:91 9F    STA ($9F),Y     <<< 4th break
0x03351A|$0C:$B50A:88      DEY
0x03351B|$0C:$B50B:A5 70    LDA $70
0x03351D|$0C:$B50D:91 9F    STA ($9F),Y
0x03351F|$0C:$B50F:A5 4A    LDA $4A
0x033521|$0C:$B511:85 00    STA $00
0x033523|$0C:$B513:A5 4B    LDA $4B
0x033525|$0C:$B515:85 01    STA $01
0x033527|$0C:$B517:A9 86    LDA #$86
0x033529|$0C:$B519:85 03    STA $03
0x03352B|$0C:$B51B:A9 9F    LDA #$9F
0x03352D|$0C:$B51D:85 02    STA $02
0x03352F|$0C:$B51F:20 FC 8F JSR $8FFC
0x033532|$0C:$B522:90 08    BCC $B52C
0x033534|$0C:$B524:A9 86    LDA #$86
0x033536|$0C:$B526:85 4B    STA $4B
0x033538|$0C:$B528:A9 9F    LDA #$9F
0x03353A|$0C:$B52A:85 4A    STA $4A
; control flow target (from $B522)
0x03353C|$0C:$B52C:A5 4A    LDA $4A
0x03353E|$0C:$B52E:85 9A    STA $9A
0x033540|$0C:$B530:85 AE    STA $AE
0x033542|$0C:$B532:A5 4B    LDA $4B
0x033544|$0C:$B534:85 9B    STA $9B
0x033546|$0C:$B536:85 AF    STA $AF
0x033548|$0C:$B538:A0 0A    LDY #$0A
0x03354A|$0C:$B53A:B1 A1    LDA ($A1),Y
0x03354C|$0C:$B53C:C8      INY
0x03354D|$0C:$B53D:11 A1    ORA ($A1),Y
0x03354F|$0C:$B53F:D0 0D    BNE $B54E
0x033551|$0C:$B541:20 76 AF JSR $AF76
0x033554|$0C:$B544:A0 2C    LDY #$2C
0x033556|$0C:$B546:91 A1    STA ($A1),Y
0x033558|$0C:$B548:A0 08    LDY #$08
0x03355A|$0C:$B54A:09 80    ORA #$80
0x03355C|$0C:$B54C:91 A1    STA ($A1),Y
; control flow target (from $B53F)
0x03355E|$0C:$B54E:4C 9A BF JMP $BF9A

; control flow target (from $B478, $B484)
0x033561|$0C:$B551:B1 9F    LDA ($9F),Y
0x033563|$0C:$B553:85 48    STA $48
0x033565|$0C:$B555:A0 24    LDY #$24
0x033567|$0C:$B557:38      SEC
0x033568|$0C:$B558:F1 9F    SBC ($9F),Y
0x03356A|$0C:$B55A:B0 02    BCS $B55E
0x03356C|$0C:$B55C:A9 00    LDA #$00
; control flow target (from $B55A)
0x03356E|$0C:$B55E:18      CLC
0x03356F|$0C:$B55F:65 46    ADC $46
0x033571|$0C:$B561:A0 26    LDY #$26
0x033573|$0C:$B563:91 9F    STA ($9F),Y
0x033575|$0C:$B565:A5 48    LDA $48
0x033577|$0C:$B567:4A      LSR
0x033578|$0C:$B568:4A      LSR
0x033579|$0C:$B569:18      CLC
0x03357A|$0C:$B56A:65 47    ADC $47
0x03357C|$0C:$B56C:A0 27    LDY #$27
0x03357E|$0C:$B56E:91 9F    STA ($9F),Y    <<< 2nd break
0x033580|$0C:$B570:60      RTS

In particular, it runs through that 4-time loop on the first break for each character, so I'm not sure what it's meant to be doing. At first I thought it was running 4 times for target all, but it does that per single target. I'm not sure why but it cycles from the bonus defense byte through the $28, the $29 (supposedly command), and the $2A (supposedly target high bit).
« Last Edit: January 31, 2020, 02:37:07 am by redmagejoe »