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

#11
Posts: 2,548
Threads: 98
Thanks Received: 147
Thanks Given: 156
Joined: Aug 2009
Reputation: 52
Status
Nattak\'d
I can confirm the same results as well, bugged items still added to the inventory on the 13th non-break usage. Sad


We are born, live, die and then do the same thing over again.
Quote  

#12
Posts: 377
Threads: 34
Thanks Received: 10
Thanks Given: 7
Joined: Dec 2018
Reputation: 18
Status
Moog
Dang, you're right.  Even with my code change it still causes the problem; Mimic must have been resetting the count.

Okay, that's the extent of what I can come up with for the problem.  Seibaby suggested in Discord that the 'add back to inventory' routine has some bugs in it, addressed in a Multisteal fix patch and a 'cast without breaking' item patch (I know about the former, I've never seen or heard of the latter).  That would be the next place to look.


EDIT: Interesting note... I was wondering about what Gi said... before I fixed the pointer, it was breaking tools 100% of the time but not causing item index bleed.
So..
Code:
SEP #$10       ;  Set 8-bit X and Y
TYX
LDA #$FF
STA $32F4,X    ;  null item index to add to inventory. This means the item will stay deducted from your inventory.
LDA $3018,X

I tried removing this part by making it branch over, and it stopped the item index bleed, but... introduced a separate problem.
With two tool users, the tool does not get added back to the inventory in time.  Which means if you input too fast, you lose a tool when it didn't break... even if it's an unbreakable tool.
Getting closer to the source of the problem, but not close enough.

Well, the solution has been found.  Thank Sir Newton Fig for breaking down what was going wrong and pointing to Bropedio, who already had a fix for the problem.

Sir Newton Fig Wrote:So here's the problem as far as I can tell

There's a buffer at $2E72 that the game stores some item data in for the purpose of adding items to inventory. There's also a list at $602D that is used for gaining items during battle. There's a routine that copies the 5 bytes at $2E72 to the appropriate slot in the queue at $602D ($64DA is the index into this queue). Each time a tool doesn't break, it's still incrementing the queue of items to be received. Eventually, it overflows, and Weird Shit Happens.

That said, there's also $64DB, which keeps track of the items that have been added back to your inventory. It gets incremented to match $64DA after that piece of bookkeeping gets done. Hypothetically, one could hack this thing to make the queue circular so that it doesn't go past its bounds.

I'm assuming this is what Bropedio did in BNW to make weapon switching not add a bunch of Healing Shivs to the inventory or whatever.

I assume that this Tool bug is also going to have implications on weapon switching, Stealing, and Metamorphing, and that cracking Rods will also help escalate it, though I haven't confirmed any of this.

(actually, scratch that bit about weapon switching at the end there, forgot it doesn't use the item queue in vanilla, that's a BNW thing)

So the problem is actually a vanilla bug that has nothing to do with the code you have.  The buffer of 'item to add back into the inventory' wasn't cleared enough by Vanilla, which causes it to overflow before it is supposed to and add garbage items.

Bropedio Wrote:There are two different buffer position markers, 64DA and 64DB. 64DA tracks the buffer position to add the next item to, and 64DB tracks the buffer position to start at when copying to inventory on each turn
Usually, it's something like this:

1. 64DA and 64DB both point to 0.
2. Steal from enemy, store in slot 0. Now 64DA points to 1
3. On next turn, start at 64DB (0) and copy to inventory until you see 0xFF (empty buffer slot)
4. Now 64DA and 64DB both point to slot 1

But since vanilla forgets to clear 0x41-0x50 in the buffer, at some point step 3 will behave unexpectedly
It will see a non-0xFF value in the buffer, and will keep copying until it reaches another 0xFF, which is likely to be at the slot it started, which will be at least 1 behind 64DA
Since 64DA is ahead, the items it writes from then on will never be seen by 64DB ,since it's stuck on a 0xFF
The bug will resolve if another 16 items are added to the buffer between those points in time, as 64DA will finally catch up to 64DB.
This presumes that the other item-on-reserve issue has been fixed already -- that one happens in C2, and is related to reserve items being overwritten under some conditions (at $32F4,X)


Here's the solution.  From the original version of your tool break code (NOT the code block that I shared with you)

(1) Apply Imzogelmo's Multisteal fix, which I've attached to this post.
(2) Go to $C112D5 in a hex editor and change the value from E0 40 00 to E0 50 00

And that's it.  Give it a try; as far as I could tell this was the only change necessary to make the code work.  Presto, Divergent Paths' "sketch bug" be squashed, thank you Sir Newton Fig and Bropedio.


Attached Files
.zip  Multi-Steal-Fix (Imzogelmo).zip (30.87 KB, 3 downloads)
  Find
Quote  
[-] The following 1 user says Thank You to C-Dude for this post:
  • PowerPanda (07-06-2021)

#13
Posts: 18
Threads: 3
Thanks Received: 0
Thanks Given: 0
Joined: Apr 2021
Reputation: 0
Status
None
^ I just noticed that C-Dude's post about the fix to this issue got merged into his previous post, so I'm just gonna drop this little note in here to make sure @PowerPanda gets alerted about it.
  Find
Quote  

#14
Posts: 614
Threads: 49
Thanks Received: 0
Thanks Given: 4
Joined: Feb 2017
Reputation: 25
Status
None
Thank you so, so, sooooo much. 

One question. The Multi-Steal fix conflicts with other changes that I have made in C2/399E to C2/3A0E. Is it just the custom function that I need, which in the readme is C2/6565?


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

#15
Posts: 16
Threads: 3
Thanks Received: 0
Thanks Given: 0
Joined: May 2019
Reputation: 2
Status
None
As far as I know, the multisteal patch is not necessary to fix the bug you were encountering. All the multisteal patch does is allow multiple steals per turn. There *are* some underlying issues with reserve items that can cause issues, but I don't think those underlying issues are addressed with the multisteal patch. I'm not familiar with your tool patch, but some potential issues to test might be:

1. Edgar uses Tool, it breaks. Edgar dies, is revived, then uses an Item.
2. Edgar has thief knife equipped, breaks a Tool, then counters (and steals an item) before Tool is returned to inventory.

Again, I'm not familiar with how your Tools patch works, but if it's using the reserve item byte `32F4`, these situations may cause the Tool to be lost.
  Find
Quote  

#16
Posts: 51
Threads: 5
Thanks Received: 2
Thanks Given: 0
Joined: Apr 2018
Reputation: 8
Status
Shell
I know it's not the point of this thread, but there's no way this is correct:
Code:
JSR $4B5A
AND #$2A       ;  1/42 chance of breaking
BNE no_break

$4B5A sets the accumulator to a random number from 0–255.
ANDing that with 42 doesn't give you a 1/42 chance. It gives you a 1/8 chance.

2A has 3 bits that are 1. ANDing sets all bits in the accumulator to except those 3. If the accumulator is now 0, the branch will be taken. The chance of those 3 bits being 0 is 1/2^3 = 1/8.

ANDing like this only works when the denominator is a power of 2. If you actually want a 1/42 chance, you need to do this:

Code:
LDA #$2A
JSR $4B65       ; set A to a random number between 0 and A-1
BNE no_break
  Find
Quote  

#17
Posts: 18
Threads: 3
Thanks Received: 0
Thanks Given: 0
Joined: Apr 2021
Reputation: 0
Status
None
(07-07-2021, 10:31 AM)Bropedio Wrote: As far as I know, the multisteal patch is not necessary to fix the bug you were encountering. All the multisteal patch does is allow multiple steals per turn. There *are* some underlying issues with reserve items that can cause issues, but I don't think those underlying issues are addressed with the multisteal patch. I'm not familiar with your tool patch, but some potential issues to test might be:

1. Edgar uses Tool, it breaks. Edgar dies, is revived, then uses an Item.
2. Edgar has thief knife equipped, breaks a Tool, then counters (and steals an item) before Tool is returned to inventory.

Again, I'm not familiar with how your Tools patch works, but if it's using the reserve item byte `32F4`, these situations may cause the Tool to be lost.

The breakable tools functionality in DP uses the routine at `$4D89` for the Tools command to put the Tool on reserve when the command is entered. Then, during the execution of the tool action, it does a series of checks to determine if the tool breaks. If it does, it dummies out the item ID for the reserve item. Unless there are measures added in other places to flush the reserve item to the add item buffer (e.g. if character dies, before proccing Steal on a counterattack, others?), it seems to me it would indeed be susceptible to reserve item interference as you describe.

Maybe a `JSR $62C7` flush somewhere in the neighborhood of `$C2/06E4` would be an apt fix to the case of a reserve item getting clobbered by getting KOd? Not sure what the best fix would be for a Mug counter though. Seems like you're familiar with some fixes to these issues already though, Bro – what's your recommendation here?

That all said, according to the documentation, DP also makes it possible to Steal both the common and rare steal from each enemy, so the Multi-Steal fix, if not already in use, should be relevant. Otherwise, if Locke is dual-wielding and Mugs something, triggering two successful Steals will clobber one of the steal attempts (and potentially display the wrong message for one of them). @PowerPanda, if you would like to share your modified `$C2/399E`, maybe we can help you figure out how to splice the Multi Steal adjustments into it?
  Find
Quote  

#18
Posts: 614
Threads: 49
Thanks Received: 0
Thanks Given: 4
Joined: Feb 2017
Reputation: 25
Status
None
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.

My steal changes are all in-line, and are as follows. I'm sorry it's not commented code, and that it's straight hex.
Quote:;Presented with the original value, and the value to change it to underneath, marked with "->"

C2/39E4:
   7A
-> EA

C2/39E7
   F0 18
-> F0 17

C2/39FA
   99 09 33 EE 01 34 60
-> EE 01 34 7A 60 EA 7A

And once again, thank you everyone for the help. I'm burned out on hacking, but I need to get this bug fixed before I can go into hibernation.

EDIT: Attaching "Recapture the Glory"


Attached Files
.zip  Recapture the Glory Fix - Assassin.zip (21.16 KB, 3 downloads)


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

#19
Posts: 377
Threads: 34
Thanks Received: 10
Thanks Given: 7
Joined: Dec 2018
Reputation: 18
Status
Moog
I'll annotate the raw hex so that the assembly programmers can work with it.

Code:
Vanilla
C2/39E4:
7A                    PLY

PowerPanda
-> EA                NOP                {I don't understand what's accomplished by pushing the stack pull down}


Vanilla
C2/39E7:
F0 18                BEQ $3A01      (Fail to steal)

PowerPanda
-> F0 17            BEQ $3A00        {The common slot erasure seems to have been removed, this pointer compensates for the pushback}


Vanilla
C2/39FA:
99 09 33             STA $3309,Y    (in both slots)
EE 01 34             INC $3401      (now = 3) (Sets message to "Stole #whatever ")
60                   RTS

PowerPanda
-> EE 01 34            INC $3401      (now = 3) (Sets message to "Stole #whatever ")
7A                    PLY
60                    RTS
EA                    NOP
7A                    PLY                {This gets followed by vanilla fail to steal code}
                                    {which sets Fight as the command for counterattack purposes}

Other than keeping the common item from being overwritten, I can't quite follow what your code is going for here.  I'm going to look at Imzogelmo's multisteal fix and see if the two can be blended, though.
  Find
Quote  

#20
Posts: 16
Threads: 3
Thanks Received: 0
Thanks Given: 0
Joined: May 2019
Reputation: 2
Status
None
Code:
hirom
;header

; BNW - Item Overwrite Fix (v.2)
; Bropedio (July 20, 2019)
;
; Changelog
; v.2 - Correct JMP op to JSR
;
; Stealing an item while the Item or Weapon Swap commands
; are pending will overwrite the pending item or swap-in
; weapon. Similarly, if a character steals more than one
; item in a turn, only the last item stolen will be added
; to inventory.
;
; If a character dies before executing a queued Item or
; Weapon Swap command, the pending item will be lost if
; the character queues another Item, Weapon Swap, or Steal
; command executes prior to the end of battle.

!free_c2 = $C2654B ; 31 bytes

; ###############################################
; Return reserve items to inventory on queue wipe

org $C20A2B
ReserveCheck:
  JSR ReturnReserve

; ###############################################
; Immediately add Stolen items to inventory, preserving
; any existing reserve item.

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

org $C239EC
Steal:
  XBA               ; store acquired item in B
  JSR $3CB8         ; free-turn + load unique bit
  JSR SaveItem      ; save new item to buffer
  NOP #2

; ###############################################
; New Code (in C2)

org !free_c2
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

This is the patch I have in BNW to address the reserve item issue. I'm not sure whether it would work with DP right out of the box, but it might (assuming you update the freespace address).

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.
  Find
Quote  
[-] The following 1 user says Thank You to Bropedio for this post:
  • C-Dude (07-07-2021)



Forum Jump:

Users browsing this thread: 1 Guest(s)


Theme by Madsiur2017Custom Graphics by JamesWhite