Users browsing this thread: 1 Guest(s)
Breakable Tools - Need Help

#21
Posts: 377
Threads: 34
Thanks Received: 10
Thanks Given: 7
Joined: Dec 2018
Reputation: 18
Status
Moog
(07-07-2021, 05:46 PM)Bropedio Wrote: Edit: On second thought, this will definitely not work out of the box for DP, since it uses BNW's "free turn" handling on successful steal. But the code could be tweaked pretty easily to adjust back to vanilla.

It looks like...
Code:
JSR $3CB8         ; free-turn + load unique bit
...this is the only offending part.  And this fix doesn't overlap code that PowerPanda already wrote for Steal (while Imzogelmo's fix does).  I wasn't able to test edge cases like steal into tool breakage because I'm not sure where to look for a problem like that, but it seemed to work when I compiled it (working as well as the earlier attempt when I let Multisteal overwrite PowerPanda's changes [not to imply that I ran both at the same time]).  I'd say commenting out this $3CB8 (pep-up replacer) is all the code needs for DP compatibility.

EDIT: Oh I'm wrong, I've misunderstood something fundamental about how Bropedio's code handles the inventory replacement.  This will take more study.
  Find
Quote  

#22
Posts: 614
Threads: 49
Thanks Received: 0
Thanks Given: 4
Joined: Feb 2017
Reputation: 25
Status
None
Okay, I've had a chance to look at my "Steal Twice" code, and I remember what I did. Don't feel bad for not understanding it. Even Assassin had to look at it 3 different times to figure out what it was actually doing.

From what I understand, the PHY/PLY has to do with the enemy counterattacking correctly. The problem with where it was placed in the original code is that it blows away the INY at C2/39E0 for which item you're targeting (common or rare). This doesn't matter in vanilla, because 1 successful steal blanks out both slots. However, by moving the PLY to AFTER the "LDA #$FF/STA $3308,Y", the INY from the item slot targeting is retained, and the function to empty that slot simply targets whichever slot you actually stole from.

The only catch was that if you successfully stole, but the slot you were targeting was empty, Y got pushed, but never pulled. Because of that, I put a 2nd PLY at C2/3A00. All other branches to the "Fail to steal" jump to C2/3A01, but that specific case needed a PLY first.

Code:
Steal function

C2/399E: A3 05        LDA $05,S      (Attacker)
C2/39A0: AA           TAX
C2/39A1: A9 01        LDA #$01
C2/39A3: 8D 01 34     STA $3401      (=1) (Sets message to "Doesn't have anything!")
C2/39A6: E0 08        CPX #$08       (Check if attacker is monster)
C2/39A8: B0 5F        BCS $3A09      (Branch if monster)
C2/39AA: C2 20        REP #$20       (Set 16-bit accumulator)
C2/39AC: B9 08 33     LDA $3308,Y    (Target's stolen items)
C2/39AF: 1A           INC
C2/39B0: E2 21        SEP #$21       (Set 8-bit Accumulator AND Carry Flag)
C2/39B2: F0 4D        BEQ $3A01      (Fail to steal if no items)
C2/39B4: EE 01 34     INC $3401      (now = 2) (Sets message to "Couldn't steal!!")
C2/39B7: BD 18 3B     LDA $3B18,X    (Attacker's Level)
C2/39BA: 69 32        ADC #$32       (adding 51, since Carry Flag was set)
C2/39BC: B0 1A        BCS $39D8      (Automatically steal if level >= 205)
C2/39BE: F9 18 3B     SBC $3B18,Y    (Subtract Target's Level, along with an extra 1 because
                                     Carry Flag is unset at this point.  Don't worry; this
                                     cancels out with the extra 1 from C2/39BA.)
                                    (StealValue = [attacker level + 51] - [target lvl + 1]
                                     = Attacker level + 50 - Target level )
C2/39C1: 90 3E        BCC $3A01      (Fail to steal if StealValue < 0)
C2/39C3: 30 13        BMI $39D8      (Automatically steal if StealValue >= 128)
C2/39C5: 85 EE        STA $EE        (save StealValue)
C2/39C7: BD 45 3C     LDA $3C45,X
C2/39CA: 4A           LSR
C2/39CB: 90 02        BCC $39CF      (Branch if no sneak ring)
C2/39CD: 06 EE        ASL $EE        (Double value)
C2/39CF: A9 64        LDA #$64
C2/39D1: 20 65 4B     JSR $4B65      (Random: 0 to 99)
C2/39D4: C5 EE        CMP $EE
C2/39D6: B0 29        BCS $3A01      (Fail to steal if the random number >= StealValue)
C2/39D8: 5A           PHY
C2/39D9: 20 5A 4B     JSR $4B5A      (Random: 0 to 255)
C2/39DC: C9 20        CMP #$20
C2/39DE: 90 01        BCC $39E1      (branch 1/8 of the time, so Rare steal slot
                                     will be checked)
C2/39E0: C8           INY            (Check the 2nd [Common] slot 7/8 of the time)
C2/39E1: B9 08 33     LDA $3308,Y    (Target's stolen item)
*C2/39E4: EA          NOP            (This is not where we restore Y, as that will blow away our item slot targeting)
C2/39E5: C9 FF        CMP #$FF       (If no item)
*C2/39E7: F0 17       BEQ $3A00      (Restore Y and the fail to steal)
C2/39E9: 8D 35 2F     STA $2F35      (save Item stolen for message purposes in
                                     parameter 1, bottom byte)
C2/39EC: 9D F4 32     STA $32F4,X    (Store in "Acquired item")
C2/39EF: BD 18 30     LDA $3018,X
C2/39F2: 0C 8C 3A     TSB $3A8C      (flag character to have any applicable item in
                                     $32F4,X added to inventory when turn is over.)
C2/39F5: A9 FF        LDA #$FF
C2/39F7: 99 08 33     STA $3308,Y    (Set to no item to steal)
*C2/39FA: EE 01 34    INC $3401         (now = 3) (Sets message to "Stole #whatever ")    
*C2/39FD: 7A           PLY              (HERE is where we restore Y, now that we no longer need to hold onto our item slot)
*C2/39FE: 60          RTS
*C2/39FF: EA          NOP             (No function; simply 1 left-over byte)

Restore Y for Counterattack
*C2/3A00: 7A          PLY              (Restore Y and continue on to fail to steal)

Fail to steal
C2/3A01: E2 20        SEP #$20
C2/3A03: A9 00        LDA #$00
C2/3A05: 99 48 3D     STA $3D48,Y    (save Fight as command for counterattack purposes)
C2/3A08: 60           RTS

I'll take a look at Bropedia's code in about an hour.

Looked at Bropedia's code, and added it to my rom. Now I need to figure out how to call it from both branches (The item broke, or the item didn't break).

The item breaking is easy, because it's an exact copy of the Metamorph code.
Code:
***ORIGINAL***
STA $32F4,X    ;  null item index to add to inventory. This means the item will stay deducted from your inventory.
LDA $3018,X
BRA check_break_end
(...)
check_break_end
TSB $3A8C      ;  flag character to have any applicable item in $32F4,X added back to inventory when turn is over.

***CHANGED TO FIT WITH BROPEDIA'S CODE***
XBA               ; store item in B (in this case $FF, Empty)
LDA $3018,X       ; character's unique bit
BRA check_break_end
(...)
check_break_end
JSR SaveItem      ; save new item to buffer

What I don't know iis how to fit this into the No_Break branch:
Code:
no_break:
LDA #$10
TSB $B1        ;  set flag to re-add item to inventory at the end of the character's turn

check_break_end:
TSB $3A8C      ;  !!THIS LINE WAS CHANGED ABOVE TO "JSR SaveItem"!!
PLP
PLA
SBC #$A2       ;  carry was clear, so subtract 163
STA $B6        ;  save unique Tool index.  0 = NoiseBlaster, 1 = Bio Blaster, etc.
RTS

On this branch, XBA never happened. I also don't know what the 4 bytes exclusive to the "no_break" section do.

Oh, one last note: Subtraction, I reverted to a 1 in 32 chance (AND #$1F instead of my bugged AND #$2A).


Projects:
FFVI: Divergent Paths (Completed) - a complete storyline and gameplay hack of FF6 that adds Leo as a playable character
  Find
Quote  

#23
Posts: 377
Threads: 34
Thanks Received: 10
Thanks Given: 7
Joined: Dec 2018
Reputation: 18
Status
Moog
Here's a breakdown of all the code that I believe needs to be changed from the Divergent Paths 1.0 release.  I would've included all of the tool breakage code too, but there's an origin address missing in the first post so I don't know where all those command comparisons are taking place.
Code:
$C112D5:                    [Fix Item return buffer]
   HEX
   E0 50 00

   CODE MEANING
   CPX #$0050       ; The game only clears #$40 for item buffer, but it expects #$50 [Bropedio]

$C20A2B:
    HEX
    20 60 65

    CODE MEANING
    JSR ReturnReserve
    
    
$C239EC:                    [Steal Fix]
    HEX
    EB BD 18 30 20 4B 65 EA EA
    
    CODE MEANING
    XBA               ; store acquired item in B
    LDA $3018,X       ; character's unique bit
    JSR SaveItem      ; save new item to buffer
    NOP #2
    
    
$C23A7C:                    [Metamorph Fix]
    HEX
    EB BD 18 30 20 4B 65 EA EA

    CODE MEANING
   XBA               ; store acquired item in B
   LDA $3018,X       ; character's unique bit
   JSR SaveItem      ; save new item to buffer
   NOP #2

    
$C26490:                    [Breakable Tools]
    HEX
    C9 09 F0 06 C9 01 F0 02 C9 08 60 48 08 20 63 2B C2 10 AA BF 12 50 D8 10 1E 20 5A 4B 29 1F D0 17 A9 08 2C BB 3E D0 10 A9 44 8D 01 34 E2 10 BB A9 FF EB BD 18 30 80 09 E2 10 BB A3 02 EB BD 18 30 20 4B 65 28 68 E9 A2 85 B6 60

    CODE MEANING
    check_command_c2:
    CMP #$09
    BEQ check_command_c2_end
    CMP #$01
    BEQ check_command_c2_end
    CMP #$08
    check_command_c2_end:
    RTS

    check_break:
    PHA
    PHP
    JSR $2B63      ;  Multiply A by 30, size of item data block
    REP #$10       ;  Set 16-bit X and Y
    TAX
    LDA $D85012,X  ;  equipment spell byte.  Bit 7: 1 = remove from inventory upon usage, 0 = nope
    BPL no_break   ;  if the flag is not set, this tool never breaks
    JSR $4B5A
    AND #$1F       ;  1/32 chance of breaking
    BNE no_break
    LDA #$08      
    BIT $3EBB      ;  Check bit 4 of $3EBB (loaded from 1DD0 at the beginning of battle).
    BNE no_break   ;  If set, tools can't be broken (set via event with B8 3B. Clear with B9 3B)
    LDA #$44       ;  "Orge Nix broke!" dialog. Works for most tools but gets clobbered by the Air Anchor "Move and you're dust!"
    STA $3401      
    SEP #$10       ;  Set 8-bit X and Y
    TYX
    LDA #$FF
    XBA                ; Put it into B because we're in 8-bit mode.  This acts like a free scratch variable
    LDA $3018,X
    BRA check_break_end

    no_break:
    SEP #$10       ;  Set 8-bit X and Y
    TYX
    LDA $02,S        ; Load the second item off the stack.  In this instance, it's a copy of the A we pushed, the tool's original item ID.
    XBA                ; Put it into B because we're in 8-bit mode.  This acts like a free scratch variable
    LDA $3018,X       ; character's unique bit


    check_break_end:
    JSR SaveItem      ; save new item to buffer   [This ensures if there's an old item waiting, like a reusable rod, it gets saved]
    PLP
    PLA
    SBC #$A2       ;  carry was clear, so subtract 163
    STA $B6        ;  save unique Tool index.  0 = NoiseBlaster, 1 = Bio Blaster, etc.
    RTS


$C2654B:            [Save Item & Return Reserve]
    HEX
    0C 8C 3A BD F4 32 48 EB 9D F4 32 DA 20 C7 62 FA 68 9D F4 32 60 BD 18 30 0C 8C 3A BD 19 32 60


    CODE MEANING
    SaveItem:           ; 21 bytes
      TSB $3A8C         ; set character's reserve item to be added
      LDA $32F4,X       ; load current reserve item
      PHA               ; save reserve item on stack
      XBA               ; get new item in A
      STA $32F4,X       ; store new item in reserve byte
      PHX               ; save X
      JSR $62C7         ; add reserve to obtained-items buffer
      PLX               ; restore X
      PLA               ; restore previous reserve item
      STA $32F4,X       ; store in reserve item byte again
      RTS

    ReturnReserve:      ; 10 bytes
      LDA $3018,X       ; character's unique bit
      TSB $3A8C         ; return reserve to inventory at turn end
      LDA $3219,X       ; ATB top byte (vanilla code)
      RTS
Essentially, you need to first make sure you've applied ALL of Bropedio's fix, so that Metamorph--which Kappa uses--and Steal/Mug--which Locke uses--are also fixed and don't contribute to the problem [Note the small tweak, the Steal fix is identical to the Metamorph fix in the above code].  THEN, we change the no_break branch to rev up the same restore situation that the break branch does, but with the original item ID in A instead of #$FF.  We do this by taking the second variable on the stack, because it was the second-to-last to be placed in the stack [at the very start of your tool breakage subroutine].  This variable was the original item ID, before any multiplication or shuffling took place.

I tried it up to 14 with tool usage and it appears to work.  I urge you to test it more thoroughly.  Bropedio's code did all the heavy lifting here, all I did was restore the original tool ID before running it (kinda like that earlier fix I proposed, but with the vanilla bug now corrected).

EDIT: IMPORTANT!  Make sure you also fix the item buffer length in C1, or the original bug will still be a problem!  Added as the first line in the code block because it is by far the most essential.

EDIT: CAUTION!  If you took the block of code before 7-8-2021, you need to take it again.  I made a mistake in the assembly... wrote "TBA" instead of "XBA", xKas ignored it, and the code worked as intended.  When I corrected my 'error', it started ADDING tools to the menu.  This implied my earlier approach was not using Bropedio's buffer fix properly, so I ran through the code again and found that the four bytes that were bothering you were indeed a source of problems (they were telling the item to be added twice).  So I removed them and now it seems to be working.
  Find
Quote  
[-] The following 1 user says Thank You to C-Dude for this post:
  • PowerPanda (07-08-2021)

#24
Posts: 18
Threads: 3
Thanks Received: 0
Thanks Given: 0
Joined: Apr 2021
Reputation: 0
Status
None
(07-07-2021, 04:10 PM)PowerPanda Wrote: So, instead of using the Multi-Steal Fix, I'm using Assassin's "Recapture the Glory", which treats each steal attempt with dual weapons as a separate attempt, with each one getting weapon special effects, counter-effects, etc. Because of my changes to Steal, plus the way Recapture the Glory handles things, I actually didn't (previously) see a need for the Multi-Steal fix. I am still hesitant to change the Steal special effect itself, since it is working exactly as I want it to.

Looking at Assassin's notes on Recapture the Glory, it doesn't seem like it does anything to prevent issues arising from multiple steal attempts. So I just performed a test where I mugged 2 Hi-Potions from a Lunaris, and it only gave me one of them. Suppose the steal options were instead Elixir vs Hi-Ether, it would be possible to clobber one with the other depending on which you snagged first.

This could also come up with an Offering+Thief Knife or Offering+Thief Glove combo, if you succeed on a steal attempt against more than one target. This would probably be more likely to come up than the Rare+Common combo, since you can just get the Common more than once with a higher degree of success.
  Find
Quote  

#25
Posts: 614
Threads: 49
Thanks Received: 0
Thanks Given: 4
Joined: Feb 2017
Reputation: 25
Status
None
IT IS WORKING. I REPEAT, IT IS WORKING.

The only oddity is that the Tool gets added back to the inventory before the character uses it; so you can "predict" breakage by checking the item menu with another character. However, that is such a small thing compared to the other issue that I'm comfortable releasing it as-is.

C-Dude and Bropedia, thank you. And thanks also to Subtraction for writing the code in the first place, and Gi Nattak for helping me figure out what was going on. I'm feeling the community love this morning.


Projects:
FFVI: Divergent Paths (Completed) - a complete storyline and gameplay hack of FF6 that adds Leo as a playable character
  Find
Quote  

#26
Posts: 18
Threads: 3
Thanks Received: 0
Thanks Given: 0
Joined: Apr 2021
Reputation: 0
Status
None
(07-08-2021, 08:21 AM)SirNewtonFig Wrote: Looking at Assassin's notes on Recapture the Glory, it doesn't seem like it does anything to prevent issues arising from multiple steal attempts. So I just performed a test where I mugged 2 Hi-Potions from a Lunaris, and it only gave me one of them. Suppose the steal options were instead Elixir vs Hi-Ether, it would be possible to clobber one with the other depending on which you snagged first.

This could also come up with an Offering+Thief Knife or Offering+Thief Glove combo, if you succeed on a steal attempt against more than one target. This would probably be more likely to come up than the Rare+Common combo, since you can just get the Common more than once with a higher degree of success.

Just to follow up on this, I tried this same test with C-Dude's fixes applied, and it worked perfectly – both Hi-Potions were acquired as expected. Onward!
  Find
Quote  
[-] The following 1 user says Thank You to SirNewtonFig for this post:
  • PowerPanda (07-08-2021)

#27
Posts: 377
Threads: 34
Thanks Received: 10
Thanks Given: 7
Joined: Dec 2018
Reputation: 18
Status
Moog
(07-08-2021, 02:16 PM)SirNewtonFig Wrote: Just to follow up on this, I tried this same test with C-Dude's fixes applied, and it worked perfectly – both Hi-Potions were acquired as expected. Onward!

Bropedio's fix.  (All I did was integrate Bropedio's fix into Subtraction's Tool Breakage).

Bropedio's fix is a from-scratch Multisteal fix, which works with Recapture the Glory because of how it hooks into the game.  I should really look into applying both to my game too... if only I hadn't eaten so much C2 space with extra ending names.
  Find
Quote  



Forum Jump:

Users browsing this thread: 1 Guest(s)


Theme by Madsiur2017Custom Graphics by JamesWhite