Past Gen RNG Research

Slashmolder : You have made a mistake :

Instead of :

Code:
2		check #10, else array[6] = 1
10		array[6] = 2

It should be :


Code:
2		array[6] = 1, else check #10
10		array[6] = 2, else array[6] = 0

array[7] and array[10] are set to 0 by default.

EDIT : Zekrom has a set of flags of 0x11 and Kyurem a set of 0x1. Is it normal ?
 
Legendaries are generated as if another Poke is received before them, i.e. 5 additional PIDRNG advances and 13 additional IV frame advances. The particle effects when receiving them have no effect on either RNG (before they are received, anyway).

The above is actually only true for the genies. The other legendaries do not get any fanfare, and are generated in the same way as normal mons, except that the PID is generated as if they are a 100% male gender species for some reason.

So to wrap up...
  • IVs start on frame 8.
  • PID frame starts on the seed's initial PID frame (just as if continuing your game normally) + 1 advancement (presumably when you enter the Isshu link menu).
  • If more than one mon is received at a time:
    • The PID data for each mon is generated one right after the other (either 4 or 5 PIDRNG frames later depending on whether the previous mon was genderless or not).
    • The IVs for each mon are 13 IVRNG frames apart.
    • How legendaries fit in with this scheme is untested, as they have their own slots separate from the normal mons, and I always made sure to have the legendary captured by itself.
    • I'd definitely recommend just RNGing the first mon, since the PID frame of the later ones depend on the genders of all the previous ones.
  • One activation of the IR key swap functionality to view the spinner (first menu choice in the Isshu link menu) advances both PIDRNG and IVRNG by 2.
    • This means that PID and IVs are tied together and therefore the number of useful seeds is far fewer than normal Gen 5 standard abuse.
    • I'm treating each spinner advance as one 'Dream Radar' frame to avoid people aiming for frames they can't hit.
    • The spinner allows you to know in about 3 advances whether you hit your seed or not, so you won't lose your legendary by accident.
  • If receiving a legendary, the gender/ratio is forced to be 100% male regardless of species (e.g. the 4th gen legendaries that I have tested have PIDs generated as if they were 100% male species). I'm guessing it's because while they don't get the fanfare that the genies (100% male species) get, they do sit in the special slots separate from normal mons in the Dream Radar.
  • PID frame structure:

  1. For the first mon only, an unknown RNG call. Subsequent mons start from step 2.
  2. PID (one RNG call for genderless, two for gendered using the standard gender forcing algorithm). Xor with 0x00010000 occurs.
  3. Unknown RNG call
  4. Unknown RNG call
  5. Nature
  • The spinner position you see when you activate the IR key swap function is determined by the highest 3 bits of the RNG value produced in step 1 in the above structure.
  • If receiving a genie, throw out first mon and regenerate (i.e. PIDRNG advanced by 5 additional frames, IVRNG advanced by 13 additional frames).
 
Slashmolder : You have made a mistake :

Instead of :

Code:
2		check #10, else array[6] = 1
10		array[6] = 2

It should be :


Code:
2		array[6] = 1, else check #10
10		array[6] = 2, else array[6] = 0

array[7] and array[10] are set to 0 by default.

EDIT : Zekrom has a set of flags of 0x11 and Kyurem a set of 0x1. Is it normal ?

I should have specified, for the case of this a pass is value = 0. As it is for everything else. If you still think I'm wrong please explain it better because from looking at it it looks right to me.

Relevant assembly:
Code:
MEMORY:021A124A loc_21A124A                             ; CODE XREF: sub_21A11FA+4Aj
MEMORY:021A124A MOVS    R1, #2
MEMORY:021A124C MOVS    R0, R5
MEMORY:021A124E TST     R0, R1
MEMORY:021A1250 BEQ     loc_21A1256
MEMORY:021A1252 MOVS    R0, #1
MEMORY:021A1254 B       loc_21A1262
MEMORY:021A1256 ; ---------------------------------------------------------------------------
MEMORY:021A1256
MEMORY:021A1256 loc_21A1256                             ; CODE XREF: sub_21A11FA+56j
MEMORY:021A1256 MOVS    R0, #0x10
MEMORY:021A1258 TST     R0, R5
MEMORY:021A125A BEQ     loc_21A1260
MEMORY:021A125C STRB    R1, [R4,#6]
MEMORY:021A125E B       loc_21A1264
MEMORY:021A1260 ; ---------------------------------------------------------------------------
MEMORY:021A1260
MEMORY:021A1260 loc_21A1260                             ; CODE XREF: sub_21A11FA+60j
MEMORY:021A1260 MOVS    R0, #0
I believe those flags are for special animations/backgrounds.
 
nidorans and volbeat/illumise breeding aren't done the same way anymore. in bw1, they were done with normal rng call, but in bw2, they use and inline copy of the rng and a different state that is stored in ram along with the daycare pkms. it looks like "01 pkm1 9f 01 pkm2 9f 01 rng state 9f 01 something 9f" as one long block in ram.

i'm still figuring it out, but here's nidoran breeding as an example:

Code:
MEMORY:021BD3F8             ; =============== S U B R O U T I N E =======================================
    MEMORY:021BD3F8
    MEMORY:021BD3F8
    MEMORY:021BD3F8             nidoranCompute                          ; CODE XREF: sub_21BD21C+4Ap
    MEMORY:021BD3F8 38 B5       PUSH    {R3-R5,LR}
    MEMORY:021BD3FA 0D 1C       MOVS    R5, R1
    MEMORY:021BD3FC 14 1C       MOVS    R4, R2
    MEMORY:021BD3FE 00 F0 99 F8 BL      firstPokemonDitto               ; is the first pokemon ditto? if so, return the address of the second one for this calculation
    MEMORY:021BD402 05 21       MOVS    R1, #5
    MEMORY:021BD404 00 22       MOVS    R2, #0
    MEMORY:021BD406 5F F6 6B FC BL      getPKMStat                      ; fetch species
    MEMORY:021BD40A 1D 28       CMP     R0, #0x1D                       ; nido f
    MEMORY:021BD40C 02 D0       BEQ     loc_21BD414                     ; if it is nido f, use special rng
    MEMORY:021BD40E 20 38       SUBS    R0, #0x20 ; ' '                 ; it's not nido f, but is it nido m?
    MEMORY:021BD410 02 28       CMP     R0, #2                          ; nido m is #32, so this restricts this special rng to nido f->nidoking by species values
    MEMORY:021BD412 15 D8       BHI     locret_21BD440
    MEMORY:021BD414
    MEMORY:021BD414             loc_21BD414                             ; CODE XREF: nidoranCompute+14j
    MEMORY:021BD414 A0 68       LDR     R0, [R4,#8]                     ; 6C078965
    MEMORY:021BD416 E1 68       LDR     R1, [R4,#0xC]                   ; 5D588B65
    MEMORY:021BD418 22 68       LDR     R2, [R4]                        ; lower seed
    MEMORY:021BD41A 63 68       LDR     R3, [R4,#4]                     ; upper seed
    MEMORY:021BD41C CF F6 7C EF BLX     mul64Unsigned__
    MEMORY:021BD420 22 69       LDR     R2, [R4,#0x10]                  ; 00269EC3
    MEMORY:021BD422 63 69       LDR     R3, [R4,#0x14]                  ; 00000000
    MEMORY:021BD424 10 18       ADDS    R0, R2, R0                      ; rng add
    MEMORY:021BD426 4B 41       ADCS    R3, R1                          ; rng add
    MEMORY:021BD428 00 21       MOVS    R1, #0                          ; store new lower seed
    MEMORY:021BD42A 20 60       STR     R0, [R4]
    MEMORY:021BD42C D8 0F       LSRS    R0, R3, #0x1F                   ; r0 = u32 >> 31
    MEMORY:021BD42E 49 00       LSLS    R1, R1, #1                      ; this is 0?
    MEMORY:021BD430 63 60       STR     R3, [R4,#4]                     ; store upper seed
    MEMORY:021BD432 01 43       ORRS    R1, R0                          ; r0 | r1, and set state
    MEMORY:021BD434 02 D1       BNE     loc_21BD43C                     ; if it's 1, generate a nido m(go to 21BD43C)
    MEMORY:021BD436 1D 20       MOVS    R0, #0x1D                       ; if it's 0, continue and generate a nido f
    MEMORY:021BD438 28 60       STR     R0, [R5]
    MEMORY:021BD43A 38 BD       POP     {R3-R5,PC}
    MEMORY:021BD43C             ; ---------------------------------------------------------------------------
    MEMORY:021BD43C
    MEMORY:021BD43C             loc_21BD43C                             ; CODE XREF: nidoranCompute+3Cj
    MEMORY:021BD43C 20 20       MOVS    R0, #0x20 ; ' '
    MEMORY:021BD43E 28 60       STR     R0, [R5]
    MEMORY:021BD440
    MEMORY:021BD440             locret_21BD440                          ; CODE XREF: nidoranCompute+1Aj
    MEMORY:021BD440 38 BD       POP     {R3-R5,PC}
    MEMORY:021BD440             ; End of function nidoranCompute




the inline rng call used for nidoran and volbeat is based on a seed generated when you first set up your character on starting the game for the first time. this is due to an error on gamefreak's part, however. each time the game starts, this seed should be unique. this function runs on every boot:

Code:
RAM_ARM9:0200C49C ; =============== S U B R O U T I N E =======================================
RAM_ARM9:0200C49C
RAM_ARM9:0200C49C
RAM_ARM9:0200C49C eggSeed                                 ; CODE XREF: sub_200C3B8+4p
RAM_ARM9:0200C49C                                         ; sub_200C574+10p
RAM_ARM9:0200C49C PUSH    {R4-R6,LR}
RAM_ARM9:0200C49E MOVS    R5, R0
RAM_ARM9:0200C4A0 BL      MersenneTwisterHandler__
RAM_ARM9:0200C4A4 MOVS    R4, R0
RAM_ARM9:0200C4A6 MOVS    R6, #0
RAM_ARM9:0200C4A8 BL      MersenneTwisterHandler__
RAM_ARM9:0200C4AC MOVS    R2, R4
RAM_ARM9:0200C4AE MOVS    R4, #0
RAM_ARM9:0200C4B0 ORRS    R4, R0
RAM_ARM9:0200C4B2 MOVS    R0, 0x1CC
RAM_ARM9:0200C4B6 STR     R4, [R5,R0]
RAM_ARM9:0200C4B8 ORRS    R2, R6
RAM_ARM9:0200C4BA ADDS    R0, R0, #4
RAM_ARM9:0200C4BC STR     R2, [R5,R0]
RAM_ARM9:0200C4BE POP     {R4-R6,PC}
RAM_ARM9:0200C4BE ; End of function eggSeed

and it writes the 8-byte seed to 2225E70. however, right after this, the old seed is read into the same spot. the game reads in the save data into the svc stack and then copies the memory into place, overwriting the new seed with the one that was first created. what should happen is that the egg data and rng state should be loaded from the cart then copied into place THEN that function should run and overwrite the old seed with the new one. they happen in the wrong order and thus, you end up stuck with the same seed every time. this also explains the 2 mersenne twister calls that happen on every boot, causing it to always start at 3.
 
so uh, it's not just illumise and nidoran. everything bred is done with inline rng calls using that rng state that never changes unless you start a new game. inheritance, nature, etc etc etc, everything. the only thing that isn't is the extra rolls for shiny charm and masuda method.

e: turns out it's for everything important except for pids. and thankfully they get it right after the first egg and the game reseeds the egg state from the mersenne twister. not that it matters as generating a second egg throws everything off due to walking around, npcs, etc.
 
so uh, it's not just illumise and nidoran. everything bred is done with inline rng calls using that rng state that never changes unless you start a new game. inheritance, nature, pids, etc etc etc, everything. the only thing that isn't is the extra rolls for shiny charm and masuda method.
So what's that mean?

I hear you're stuck w/ one nidoran or vol/ill "gender", but does that hurt other breeding on BW2... like force people to always get one gender, or always get a particular IV set?

Or am I way off base...
 
So what's that mean?

I hear you're stuck w/ one nidoran or vol/ill "gender", but does that hurt other breeding on BW2... like force people to always get one gender, or always get a particular IV set?

Or am I way off base...

Basically everything but IVs will remain static for your entire game.
 
PIDs are random. There's still 3 calls to the PIDRNG. 2 calls in makePKMN, then PID, then another call in makePKMN.

sub_200C49C actually updates the value of this new rng's seed at 2225E70. It calls MT twice and uses that for values in the seed. After you receive your first egg it is seeded correctly (like it tries to do at boot but fails because they then load a new value to it) and you get the value of the next two MT calls for the seed of it. For the first egg it's the value at frame 16 and 17 of the table (BW2 frames 14 and 15).
 
Slashmolder :

Code:
MEMORY:021A124A loc_21A124A                             ; CODE XREF: sub_21A11FA+4Aj
MEMORY:021A124A MOVS    R1, #2
MEMORY:021A124C MOVS    R0, R5
MEMORY:021A124E TST     R0, R1 ;perform (flags & 2), and update condition codes
MEMORY:021A1250 BEQ     loc_21A1256 ; if Z set, in fact, if (flags & 2) == [b]0[/b] then check bit 10, else array[6] = 1
MEMORY:021A1252 MOVS    R0, #1
MEMORY:021A1254 B       loc_21A1262

For Zekrom, I meant that the 'shiny lock' flag was not set whereas it should have been, and for Kyurem, the 'stationnary' flag was not set wheras it should have been.
 
To finish Hidden Hollow documentation he's a useful chart https://dl.dropbox.com/u/12206225/hollow.htm (credits to Kaphotics)

Basically to sum up what Bond posted on the previous page, the game will loop though every Hidden Hollow (0-19) every 256 steps. If the hollow is empty (lowest bit is not set) then it calls rand(100). If that's less than 5 it goes and generates a hidden hollow.

While generating the game calls rand(4) that determines the sub slot (or group in the chart) 0=A,1=B,2=C,3=D. There's an equal chance for each one.

Then the game calls rand(100)+1. It presumably works exactly like other encounter slots (I've never looked at the assembly for encounter slots so I'm not sure) where if it's in a certain range of values it'll be one slot or another. The chat has the percent chance of each row as well as the possible values of the rand(100) call to get the specific slots.

Then if the slot = 2 it does a check and basically if a certain byte in an array that appears to always be 0x30, isn't 0x30 it jumps back to the start of the slot decision loop. From what I can tell this never happens so Reporter is ignoring that possibility.

Code relevant to this in case we need to research that more later:
Code which loads R7 to be either 1 or 3:
Code:
MEMORY:021C83AE 01 20       MOVS    R0, #1
MEMORY:021C83B0 4B F6 72 FA BL      sub_2013898
MEMORY:021C83B4 07 1C       MOVS    R7, R0

Code:
RAM:02013898             sub_2013898                             ; CODE XREF: 021C83B0p
RAM:02013898 04 49       LDR     R1, =0x2140AC0
RAM:0201389A 8A 7B       LDRB    R2, [R1,#0xE]
RAM:0201389C 30 2A       CMP     R2, #0x30 ; '0'
RAM:0201389E 03 D0       BEQ     locret_20138A8
RAM:020138A0 89 8D       LDRH    R1, [R1,#0x2C]
RAM:020138A2 04 29       CMP     R1, #4
RAM:020138A4 00 DA       BGE     locret_20138A8
RAM:020138A6 80 1C       ADDS    R0, R0, #2
RAM:020138A8
RAM:020138A8             locret_20138A8                          ; CODE XREF: sub_2013898+6j
RAM:020138A8                                                     ; sub_2013898+Cj
RAM:020138A8 70 47       BX      LR

The check inside the loop:
Code:
loc_21C83EC                             ; CODE XREF: hollowFill__+4Cj
MEMORY:021C83EC 02 2C       CMP     R4, #2
MEMORY:021C83EE 02 D9       BLS     loc_21C83F6
MEMORY:021C83F0 76 1C       ADDS    R6, R6, #1
MEMORY:021C83F2 BE 42       CMP     R6, R7
MEMORY:021C83F4 E6 D3       BCC     loc_21C83C4

Then a rand(100) call is made again. This is used to store the gender value. The game does if gender value < chance female then make it female.

Finally it is stored into the array. The top byte is equal to the gender value. The lower byte is is this form (each digit representing a bit):
XXXY YYYZ

Where X is the subslot, the rand(4) call. It should be between 0 and 3.
Y is the value of the slot, after the encounter slot loop. It should be between 0 and 10.
And Z is the is empty bit. Where if it's set to 1 then the hollow is treated as if it has something in it but if it's set to 0 it's treated as empty.

You get some pretty weird stuff and sometimes the error NPC if you give the game values which are normally not possible.
The scripted Minccino encounter sets the value of the array to 0x6400 to force it to be male and be the Pokemon in slot 0, subslot 0.
And yes there is a 0.075% chance of normally getting a hollow with a female Pinsir in White2 and female Heracross in Black2.
 
B2W2 JP DSi / 3DS Nazos

For both versions:
The first two nazo values are the same as on a DS (as Bond697 suspected).
The pattern for the third, fourth, and fifth nazos is the same as on DS (fourth and fifth are both third plus 0x54).

Black 2 JP:
Third nazo: 0x027AA730
vcount: A2
vframe: 8 (JP DSi / 3DS)
timer0: 150D - 1514 (8 values, but I tended to get 1511 - 1513)

White 2 JP:
Third nazo: 0x027AA5F0
vcount: BE
vframe: 8 (JP DSi)
timer0: 18AF - 18B3 (I'm assuming the actual range is wider, but I couldn't hit anything outside this range)

I used mons from two consecutive Dream Radar frames to get my seeds, since the spinner is a great way to quickly recognize whether you've hit your seed or not.

My four-year-old computer is very sorry it took so long.
 
My four-year-old computer is very sorry it took so long.

You sir are amazing thank you.
Next time I can do the searches since my computer are more powerful. I think I finally got OpenCL working and should be able to use my GPUs to make searches even faster.

I wonder why the Timer0s are so far apart.
 
Next time I can do the searches since my computer are more powerful. I think I finally got OpenCL working and should be able to use my GPUs to make searches even faster.

I would be interested to know how it performs on a higher powered GPU (including which of the vectorized implementations is fastest). Have you tested it with actual seed data and verified that it's working correctly?

I wonder why the Timer0s are so far apart.
The timer0 (and vcount) difference is probably related to whatever it is that creates the large difference in the nazos (0x730 vs. 0x5F0). Extra memory allocated for something...
 
I decided to look into Pokemon Channel Jirachi and the results so far aren't too great.

I can't get VBA-M + Dolphin to work correctly no matter how hard I try. It starts the connection, the image of Jirachi displays on my VBA window and both run really slow and then I get a connection error. This makes debugging pretty hard to do. I'd probably have to just open the dol file in IDA and look at the assembly with no debugging to help me.

Using this exact sapphire save file: https://dl.dropbox.com/u/9582930/jirachi.sav and this exact Pokemon Channel save file: https://dl.dropbox.com/u/9582930/jirachi.gci I've managed to get two very different results.
Trial 1: http://www.pokecheck.org/?p=detail&uid=1655679
Trial 2: http://www.pokecheck.org/?p=detail&uid=1656122

The SID and game origin is even different between the two Pokemon. Either there's a list of SIDs and games (possibly one for ruby and one for sapphire) or it generates those as well as the Pokemon.

The only assumption I can make is that it's based off an RNG using the Gamecube's RTC as a seed.

Using the first Jirachi (PID 7C805A75)

I decided to use the PID and test different known RNGs. Here are the only possible seeds which would give the correct PID:
XD Seed: 705DA0FF
Regular Seed: 43F9E475

The only way this is possible is if the upper PID is generated first and then the lower pid. This is consistent with how the bonus disc Jirachi as well as the Pokemon Box Pokemon's PIDs are generated.

If you look at these seeds no where near these RNG values is possible values for the IVs, 3019 or B019 and 4352 or C352. The best assumption I can make in this situation is that we're facing a new RNG. Hopefully it's a LCRNG which I can find with disassemble.
 
And you thought the Emerald PRNG was broken already...

I've just made a discovery that will revolutionize RNG abuse on retail Emerald carts: You can use Battle Videos from the Battle Frontier to save a PRNG state. (tl;dr version at the end of this post)

Any battle that can be saved on the Frontier Pass actually disables the vBlank function from advancing the PRNG. I assume this is so the Battle Video can function simply as a starting seed, the Pokémon, and a set of instructions (like the later gen battle videos). The storage of the starting seed is the key to this whole thing. When you load the battle video the PRNG advances in the exact same way as it did the real battle (one frame advancement right away, then no advancements until move selection) giving about a 10 second window where the PRNG is completely still with 1 frame past the stored value. This gives one ample time to press B to exit the video, and start an external timer (note that the PRNG starts advancing normally again on the 24th video frame after pressing B).

When a battle that can be saved starts the PRNG stops advancing as soon as the screen completely fades to black, and the current PRNG value is stored. So for example, let's say it's holding the PRNG value at frame 1000000 (starting seed of 0 obviously). Win/lose the battle, save the video. When you load the video, even after turning off the game, it will jump to the PRNG value at frame 1000000, and advance once right away. Then one would press B before the first turn begins, and after 23 frames, the PRNG advances normally, starting at frame 1000002.

This clearly has amazing potential - one can instantly jump to a desired PRNG state so they don't have to wait hours just to hope that they pressed the A button (or took a step) at the correct video frame. One can simply store a PRNG value much closer to the actual frame, within 10000 PRNG frames optimally. By making multiple battle videos, one can slowly but surely advance to frames previously thought humanly impossible to within very few frames of the target. That Careful 31/31/31/7/31/31 spread on frame 144187325? That would be easily attainable on a retail cart by using multiple battle videos over a few weeks. It would take a while but one could get to a PRNG that is a reasonable amount of frames away from the target, then do a fairly quick RNG abuse. And then, it can even be used on multiple Pokémon!

Edit: This all came about because I wanted to find out if Anabel's Alakazam had a fixed ability or not. It doesn't. I then noticed the PRNG wasn't advancing while idling in battle. Took me 10 minutes to realize this was for syncing battle videos.

Limitations: One must beat the Pokémon league, and walk outside of the player's house for a certain amount of steps for Scott to call, enabling you to go to the Battle Frontier. This means the roaming Lati cannot be RNG abused with this without cheating, nor can one use the proper seeding of the PRNG from starting a new save file.

Edit 2: To estimate the PRNG value stored by the battle video simply capture a Pokémon (preferably a stationary encounter) multiple times around the same amount of time after exiting the video and search that spread in RNG reporter Method 1 (or H-2 for a wild encounter, maybe H-1 or H-4).

tl;dr - Battle videos can act like "save states" for the PRNG on retail Emerald carts.

Edit 3: Battle videos cannot be used for RNG abusing egg PIDs. Half of the egg PID uses another RNG, which is seeded by a timer that tracks frames since the last boot/SR. There is no way to change it outside of waiting.
 
Did some testing, trying, and it's indeed awesome. I'm not quite sure at which moment it grab's / saves the seed (perhaps I didn't read Hozu's post close enough). But I used VBA + Lua and grabt the seed at the point I'm saving my game before entering the Tower, get defeated and went to Rayquaza's place openend the Battle vid and checked wich frame I landed, and it was about 3000 frames later then from the seed (I entered the seed I grabt into RNGReporter). So it looks like stuff like Regi's or other stuff could be quite easy now.

I'll see if I can find my GBA SP as it don't require batteries.
 
I've found a seed for which the current B2W2 initial PIDRNG frame calc does not work.

Seed: 221222F33BDC030C
Calc says: 59
Actual frame: 55

Verified twice on an actual White 2 cart:

  • Once in a quiet Pokecenter when picking up Keldeo (picked up on frame 55)
  • Once in the first room of Reverse Mountain (captured on frame 56 - something here is advancing the PIDRNG by one frame at startup no matter which seed I hit).
 
I've found a seed for which the current B2W2 initial PIDRNG frame calc does not work.

Seed: 221222F33BDC030C
Calc says: 59
Actual frame: 55

Verified twice on an actual White 2 cart:

  • Once in a quiet Pokecenter when picking up Keldeo (picked up on frame 55)
  • Once in the first room of Reverse Mountain (captured on frame 56 - something here is advancing the PIDRNG by one frame at startup no matter which seed I hit).

I've hit that seed 3 times in a row on an emulator and it's always been frame 59 when I start my game. I'm inside the Nimbasa Pokemon Center. Just for consistency what Pokemon Center are you using? Or even better extract your save file and give it to me.
The first probability table does 8 advances, then there's 3 other advances for various things leaving it at 11.
The second, third, fourth, and fifth probability table calls (all during the loading of the game) bring it to 23, 35, 45, 56 respectively.
Then the final extra call passes after the first set of 3 generations, bringing it to 59.

For verification the value of the PIDRNG seed (64 bit number at 0x21FF5D8) is D240E5800EF091F6. Looking at the researcher that's frame 58, meaning my starting frame is actually 59.
 
I've hit that seed 3 times in a row on an emulator and it's always been frame 59 when I start my game. I'm inside the Nimbasa Pokemon Center. Just for consistency what Pokemon Center are you using? Or even better extract your save file and give it to me.
The first probability table does 8 advances, then there's 3 other advances for various things leaving it at 11.
The second, third, fourth, and fifth probability table calls (all during the loading of the game) bring it to 23, 35, 45, 56 respectively.
Then the final extra call passes after the first set of 3 generations, bringing it to 59.

For verification the value of the PIDRNG seed (64 bit number at 0x21FF5D8) is D240E5800EF091F6. Looking at the researcher that's frame 58, meaning my starting frame is actually 59.

Yeah, I expected this to be the case. I recently did the memory link with my White cart, and I'm assuming that doing that has changed the initial PIDRNG frame for some seeds, while other seeds are the same. It has also changed the initial PIDRNG frame for all seeds for the Dream Radar, which used to be the same as when starting the game normally.

Unfortunately, I don't have the tools to extract my save. I was in the Undella town Pokecenter.

If you have a way to do the memory link, that would definitely be a first step.

Edit:
Here are some seeds and the initial PIDRNG frame when accessing the spinner under the Isshu Link menu. I have not confirmed what the initial frames for these seeds are when starting the game normally.
Code:
Seed              Actual  Calculated
c5371321dcff7673  54      58
5a0bb07414dadd5b  53      56
59d050a90733d878  52      52
8ea4dc2a5c9c297e  47      50
 
Got it that memory link was all I needed thanks. I'm not sure exactly what causes it but instead of doing
ProbabilityTable()
rand() x3
ProbabilityTable()x4
Extra()
It does
ProbabilityTable()
rand() x2
ProbabilityTable()x4
Extra()
 
Pokemon Emerald Safari Zone Encounter slots appear to be off by 1 frame. That means there's an extra RNG call between the generation of the Encounter slot and the PID. I'm not sure what causes this call, I'll look into it later if I can manage to get gbd debugging working correctly.
 
Got it that memory link was all I needed thanks. I'm not sure exactly what causes it but instead of doing
ProbabilityTable()
rand() x3
ProbabilityTable()x4
Extra()
It does
ProbabilityTable()
rand() x2
ProbabilityTable()x4
Extra()

As a follow up to this, if the memory link has not been done, there is an extra PIDRNG advance when entering the Isshu Link menu. There is no advancement if the memory link has been done. This affects the spinner sequence and the nature of a received DR poke, and combined with the difference in the initial PIDRNG frame makes it very likely that a DR seed found before doing a memory link will no longer be useable after unless you get lucky with the sequence of natures.
 
Structure of R/S Egg generation:
The lower PID is generated when you take your step and the egg is generated.
It generates the egg if rand(100) < Compatibility. The compatibility number is 20 if same id different species, 50 if same id same species or different id different species, and 70 if different id same species.
Then it calls rand() to get the lower PID. If this number is 0xFFFE or 0xFFFF the game does pid+2 % 0xFFFF (I believe the actual code is something more efficient than that or it doesn't need to use the mod because it's using 16 bit numbers). One is then added to the pid and it's stored.

The rest of the PID is generated as follows:
rand() for the upper pid
vblank sometimes
rand() x2 for the ivs
rand() % (6-i) for the inheritance slot
vblank
rand() % (6-i) for the inheritance slot
rand()&1 x3 to determine which parent to inherit from for each of the iv slots.
Inheritance calcs are identical to how they are in HG/SS.
 
if it's like emerald(and it probably is in that regard), then it's doing pid half % 0xFFFE in those cases. if i'm understanding what you're saying properly, anyway. instead of adding, they waste a bunch of processing time doing modulus.
 
Back
Top