Zelda II: The Adventure of Link/Luck Manipulation

From Red Candle
Revision as of 18:10, 8 May 2015 by Neil (Talk | contribs) (Practical Consequences)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

Summary

The Zelda II RNG changes with every frame. In the NES version, the counter starts when SDA timing starts. Generally that doesn't matter, since things will never happen at the same time, but the one key exception is that in any category where the North Palace Magic Container is done first, a 50 point bag can be manipulated.

Opening 50 PBag

Here is a chart of the Zelda II RNG at the start of the game, with a 10 frame moving average. Each bar represents the numbered frame, and the 9 frames preceding.

zelda2-droprate-movingaverage.png

For the P Bag drop, the two key windows are the ones at about 1600 frames, and at about 1920 frames. Hit either of those windows reliably, and P Bag drops go from the usual 1/8 chance, to much higher.

Practical Consequences

There are a few known ways of getting a PBag that are much better than random at getting the drop.

Error72 has a strategy that is fast and effective, however the "low beam" techniques used in the strategy make it difficult to execute.

Simpoldood has a variant of that visible at the start of this PB run that is easier to do, but has some hitches and timing that make it less reliable.

My strategy exists and I've had a lot of success with it. It's slower by about 2 seconds than Error's, and it has a timed hit, but I've personally had the best success with it because I hate low beams. It also sometimes gives a bad encounter pattern on the way to Rauru, requiring a slight hesitation on the way out of the cave, to avoid that.

Technical details

The following comes courtesy of __sdfg on the SDA forums, with permission.

Here's a bucket of FCEUX for a small drop:

003612: A:01 X:01 Y:01 S:EF P:nvUBdIzc                 $E899:FE DE 05  INC $05DE,X @ $05DF = #$05  ; Increment 6-count, this time for a small drop
003612: A:01 X:01 Y:01 S:EF P:nvUBdIzc                 $E89C:BD DE 05  LDA $05DE,X @ $05DF = #$06  ; And then load that value
003612: A:06 X:01 Y:01 S:EF P:nvUBdIzc                 $E89F:C9 06     CMP #$06  ; And see if it's 6 yet
003612: A:06 X:01 Y:01 S:EF P:nvUBdIZC                 $E8A1:D0 1C     BNE $E8BF
003612: A:06 X:01 Y:01 S:EF P:nvUBdIZC                 $E8A3:A9 00     LDA #$00  ; It is!  Zero the counter for next time
003612: A:00 X:01 Y:01 S:EF P:nvUBdIZC                 $E8A5:9D DE 05  STA $05DE,X @ $05DF = #$06
003612: A:00 X:01 Y:01 S:EF P:nvUBdIZC                 $E8A8:A6 10     LDX $0010 = #$04  ; Load Memory Table Index into X.  It's 4 here
003612: A:00 X:04 Y:01 S:EF P:nvUBdIzC                 $E8AA:7E 14 04  ROR $0414,X @ $0418 = #$01  ; ???
003612: A:00 X:04 Y:01 S:EF P:NvUBdIzC                 $E8AD:BD 1B 05  LDA $051B,X @ $051F = #$82  ; Read RNG byte 4
003612: A:82 X:04 Y:01 S:EF P:NvUBdIzC                 $E8B0:29 07     AND #$07  ; Actually, we just need the 3 low bits
003612: A:02 X:04 Y:01 S:EF P:nvUBdIzC                 $E8B2:C0 02     CPY #$02  ; This is a small drop, so skip to E8B8
003612: A:02 X:04 Y:01 S:EF P:NvUBdIzc                 $E8B4:D0 02     BNE $E8B8
003612: A:02 X:04 Y:01 S:EF P:NvUBdIzc                 $E8B8:A8        TAY  ; Load the drop at position 2 this time (A=2)
003612: A:02 X:04 Y:02 S:EF P:nvUBdIzc                 $E8B9:B9 70 E8  LDA $E870,Y @ $E872 = #$8A  ; 8A = 50-bag.  Nice!
003612: A:8A X:04 Y:02 S:EF P:NvUBdIzc                 $E8BC:9D 8E 04  STA $048E,X @ $0492 = #$00
003612: A:8A X:04 Y:02 S:EF P:NvUBdIzc                 $E8BF:A6 10     LDX $0010 = #$04  ; And now we're past the drop code

And for a large drop:

029149: A:02 X:02 Y:02 S:F1 P:nvUBdIzc               $E899:FE DE 05  INC $05DE,X @ $05E0 = #$05  ; Increment large 6-count
029149: A:02 X:02 Y:02 S:F1 P:nvUBdIzc               $E89C:BD DE 05  LDA $05DE,X @ $05E0 = #$06
029149: A:06 X:02 Y:02 S:F1 P:nvUBdIzc               $E89F:C9 06     CMP #$06  ; Which is a 6
029149: A:06 X:02 Y:02 S:F1 P:nvUBdIZC               $E8A1:D0 1C     BNE $E8BF
029149: A:06 X:02 Y:02 S:F1 P:nvUBdIZC               $E8A3:A9 00     LDA #$00  ; So we zero it
029149: A:00 X:02 Y:02 S:F1 P:nvUBdIZC               $E8A5:9D DE 05  STA $05DE,X @ $05E0 = #$06
029149: A:00 X:02 Y:02 S:F1 P:nvUBdIZC               $E8A8:A6 10     LDX $0010 = #$04  ; Enemy Table Index value is 4 again
029149: A:00 X:04 Y:02 S:F1 P:nvUBdIzC               $E8AA:7E 14 04  ROR $0414,X @ $0418 = #$07
029149: A:00 X:04 Y:02 S:F1 P:NvUBdIzC               $E8AD:BD 1B 05  LDA $051B,X @ $051F = #$D0  ; The low 3 RNG bits are 0
029149: A:D0 X:04 Y:02 S:F1 P:NvUBdIzC               $E8B0:29 07     AND #$07
029149: A:00 X:04 Y:02 S:F1 P:nvUBdIZC               $E8B2:C0 02     CPY #$02  ; This is a large drop, so we skip the branch...
029149: A:00 X:04 Y:02 S:F1 P:nvUBdIZC               $E8B4:D0 02     BNE $E8B8
029149: A:00 X:04 Y:02 S:F1 P:nvUBdIZC               $E8B6:69 07     ADC #$07  ; ...and add 8 (carry is set) to use a different array
029149: A:08 X:04 Y:02 S:F1 P:nvUBdIzc               $E8B8:A8        TAY
029149: A:08 X:04 Y:08 S:F1 P:nvUBdIzc               $E8B9:B9 70 E8  LDA $E870,Y @ $E878 = #$91  ; Item 0 in that array is a red jar
029149: A:91 X:04 Y:08 S:F1 P:NvUBdIzc               $E8BC:9D 8E 04  STA $048E,X @ $0492 = #$00
029149: A:91 X:04 Y:08 S:F1 P:NvUBdIzc               $E8BF:A6 10     LDX $0010 = #$04

If X is 1 entering this block of code, you get a small drop. If it's 2, you get a large drop. I think it's skipped entirely if the enemy's not supposed to drop something. I haven't looked into the code preceding it much.

As noted above, 3 bits from the RNG are used as an index into a drop array. In a standard NES ROM with a 16-byte header, you can find the small drop array at offset 1e880 and the large array at 1e888. Here they are:

Small = 9090 8a90 9090 9090
Large = 918c 918c 8c91 8c91

8a = 50-point bag
9c = 200-point bag
90 = Blue jar
91 = Red jar

I made a spreadsheet using the RNG table that powerofthepowerofthe posted (Editor's note: Here are RNG output tables created by powerofthepowerofthe). It seemed to work pretty well: I'd check for updates to $0492, and on the frame I saw the update, I could use the RNG value to check which drop I'd get.

Then I started fighting a bunch of bots in a weak encounter over and over and noticed that the drops weren't going into $0492 anymore. It seems the RNG is bigger than two bytes, and the enemy table index decides both which address should receive the drop and which address should be read to decide the drop. When I kept killing enemies, the enemy table index would change.

The RNG does update on every frame, so I don't think this will help you manipulate anything unless there's some clump of good drops that you can target by playing at a specific speed. It does teach us that the P-bag probabilities are 1/8 and 1/2, though, unless the sequence for some of the RNG bytes is really wack. Maybe knowing that is enough.