Past Gen RNG Research

Pokémon Box Ruby and Sapphire

Pokémon Box Ruby and Sapphire doesn't use the same seeding function as the R/S carts when playing your GBA save on the GC/Wii. Likely being seeded by the GC. How unfortunate.

Edit: Doesn't appear to be a 16bit seed either... huh.
Turns out that due to primarily not getting Method 1 spreads I was getting the wrong results. Box seeds the same way as normal, using the GBA RTC. However with alternate spreads, like Method 4 this opens up other possibilities.

Edit: Only some mons seem to be generated by Method 4 always... the rest are normal. Regirock seems to be Method 4, while starters are Method 1. One would have to test which ones always seem to be one method or the other.

Edit 2: For live battery carts even when they're disconnected the R/S Box game seems to keep tracks of it, even across SRing. Meaning that the seeding is exactly the same as your GBA cart.
 
  • Like
Reactions: Edu
Good old Gamefreak, making stuff slower.

Pokemon Channel Jirachi is generated using the same RNG as XD/Colosseum. It's seeded in the same way (based off the RTC of the Wii/GC).

All this is done in sub_8008ec50 and the rng is sub_8010e2d8 using r3 as a parameter to the RNG as the exclusive upper bound for the RNG call. Just like the other games:
seed = seed * 0x343fd + 0x279ec3
result (in r3) = seed * max (the current value of r3) >> 16.
Note: the game's code doesn't exactly do that, also an extra call to clear the top 16 bits is used after most every rng call.

The generation is as follows:
sid
upid
lpid
then a shiny check is done. If the pid 0x80000000 is not shiny then upid = upid ^ 0x8000, else leave the pid alone.
The SID is combined with the static ID (0x9cba for reference) and setup to be sent to the gba.
Then a rand(8) is called and if it's >= 4 salac berry, else ganlon.
A rand(0x10) is called and if it's >= 8 the OT is from ruby, else it's from sapphire.
A rand(0x20) is called and if >= 16 the OT is female if < 16 it's male.
They probably did this to make it more "random", but it could be simplified to if the high bit is 1 do something else do something else.
Code:
loc_8008EDE4:
li        r3, 0x20
bl        __rand_int_max_
li        r5, 0x10
oris      r0, r23, 0xFF
subfc     r4, r5, r3
srwi      r4, r3, 31
srwi      r5, r5, 31
li        r3, 0x80
subfe     r4, r4, r5
ori       r0, r0, 0x20
andc      r4, r3, r4
li        r3, 0x20
or        r0, r0, r4
stw       r0, 0x44(r22)
Then it generates the stats using rand(32) calls (1 for each stat) in the same order as the rest of gen III Pokemon hp atk def spe spa spd.

Code:
sub_8008DA48:
mr        r0, r3
rlwinm    r3, r3, 24,16,23
inslwi    r3, r0, 8,24
rlwimi    r3, r0, 8,8,15
insrwi    r3, r0, 8,0
blr

Picture courtesy of Kaphotics:
channel.png

About the game's RNG:
It's really is identical to XD/Colo rng.
Seeding:
at loc_800363B8 it calls sub_800CE6E4 which runs the command mftb r3 and then the loc stores that value to the seed in memory. That means we'd need to be accurate to the nearest nanosecond to hit seeds.

RNGs:
There's 3 different rng subroutines which are called. They are all next to each other at 8010E250, 8010E280, and 8010E2D8.
 
  • Like
Reactions: Edu
5th Generation & Pickup

zjHnw.png

Pickup only works if you don't run.

Carrying 6 Pickup Mons and defeating a wild poke:
It cycles 7 times after battle if you don't get a pickup, 8 times if one gets a pickup, hence a calc proccing another calc immediately after.

Exiting Seed from the battle is considered the Initial Seed for this post:

Initial
Code:
Advanced Once, 
  if    SEED*100>>32    is < 10
     then [SEED+1]*100>>32 for Pickup Item Value (0-99)
    else, advance once and repeat for next slot.
  end
6 iterations, there is one calc afterwards for something else.

Pickup Table located here, although the placement for the 1%'s is off. Prism Scale is 98 for level 100 (leftovers is 99).

pfRs1.png

Code:
0-29 30-39 40-49 50-59 60-69 70-79 80-89 90-94 95-97 98 99
 30%   10%   10%   10%   10%   10%   10%    5%    3% 1% 1%

5vvpra.png
t5jh9k.png


I think that the percentages for the items are:
Code:
0-29 30-39 40-49 50-59 60-69 70-79 80-89 90-93 94-97 98 99
 30%   10%   10%   10%   10%   10%   10%    4%    4% 1% 1%

The Phanpy in slot 2 picked up a different item to the others even though they should be in the same Item Category. That's the only solution I can think of.
I haven't tested it with other monz because I've spent too much time finding good Pickup Seeds (5 Rare Candies OMG!).


EDIT: I've tried it again with different levels. My level 84 Phanpy picked up a PPup with 94 rather than a Max Revive.
 
so this morning chiizu was asking me about a function in the breeding module that has to do with checking for a ditto then advancing the rng once if one exists. i hadn't had time yet, so i put a copy on pastebin for him(and a copy of the dwAbil function) and fired up ida and we went to work.

turns out that the game checks the ability of the ditto(or mother) and if it's ability 0, the baby has an 80% chance of abil 0, if abil 1 an 80% chance of abil 1, and if it's the dw abil, the percentages become 20/20/60 leaning towards the dw abil.

Code:
RAM_OVL36:021BD6D8             ; =============== S U B R O U T I N E =======================================
RAM_OVL36:021BD6D8
RAM_OVL36:021BD6D8
RAM_OVL36:021BD6D8             abilDecision                            ; CODE XREF: breedingSetup+130p
RAM_OVL36:021BD6D8 70 B5       PUSH    {R4-R6,LR}
RAM_OVL36:021BD6DA 40 68       LDR     R0, [R0,#4]
RAM_OVL36:021BD6DC 1C 1C       MOVS    R4, R3
RAM_OVL36:021BD6DE 0D 1C       MOVS    R5, R1
RAM_OVL36:021BD6E0 5F F6 2A FC BL      getParentAbil
RAM_OVL36:021BD6E4 06 1C       MOVS    R6, R0
RAM_OVL36:021BD6E6 A0 68       LDR     R0, [R4,#8]                     ; num1
RAM_OVL36:021BD6E8 E1 68       LDR     R1, [R4,#0xC]
RAM_OVL36:021BD6EA 22 68       LDR     R2, [R4]                        ; num2
RAM_OVL36:021BD6EC 63 68       LDR     R3, [R4,#4]
RAM_OVL36:021BD6EE CF F6 14 EE BLX     mul64
RAM_OVL36:021BD6F2 22 69       LDR     R2, [R4,#0x10]
RAM_OVL36:021BD6F4 63 69       LDR     R3, [R4,#0x14]
RAM_OVL36:021BD6F6 10 18       ADDS    R0, R2, R0
RAM_OVL36:021BD6F8 4B 41       ADCS    R3, R1
RAM_OVL36:021BD6FA 20 60       STR     R0, [R4]
RAM_OVL36:021BD6FC 63 60       STR     R3, [R4,#4]
RAM_OVL36:021BD6FE 18 1C       MOVS    R0, R3                          ; num1
RAM_OVL36:021BD700 00 21       MOVS    R1, #0
RAM_OVL36:021BD702 64 22       MOVS    R2, #0x64 ; 'd'                 ; num2
RAM_OVL36:021BD704 00 23       MOVS    R3, #0
RAM_OVL36:021BD706 00 24       MOVS    R4, #0
RAM_OVL36:021BD708 CF F6 06 EE BLX     mul64
RAM_OVL36:021BD70C 00 2E       CMP     R6, #0
RAM_OVL36:021BD70E 03 D0       BEQ     loc_21BD718
RAM_OVL36:021BD710 01 2E       CMP     R6, #1
RAM_OVL36:021BD712 09 D0       BEQ     loc_21BD728
RAM_OVL36:021BD714 02 2E       CMP     R6, #2
RAM_OVL36:021BD716 0E D0       BEQ     loc_21BD736
RAM_OVL36:021BD718
RAM_OVL36:021BD718             loc_21BD718                             ; CODE XREF: abilDecision+36j
RAM_OVL36:021BD718 50 29       CMP     R1, #0x50 ; 'P'
RAM_OVL36:021BD71A 02 D2       BCS     loc_21BD722
RAM_OVL36:021BD71C 00 20       MOVS    R0, #0
RAM_OVL36:021BD71E A8 64       STR     R0, [R5,#0x48]
RAM_OVL36:021BD720 70 BD       POP     {R4-R6,PC}
RAM_OVL36:021BD722             ; ---------------------------------------------------------------------------
RAM_OVL36:021BD722
RAM_OVL36:021BD722             loc_21BD722                             ; CODE XREF: abilDecision+42j
RAM_OVL36:021BD722 01 20       MOVS    R0, #1
RAM_OVL36:021BD724 A8 64       STR     R0, [R5,#0x48]
RAM_OVL36:021BD726 70 BD       POP     {R4-R6,PC}
RAM_OVL36:021BD728             ; ---------------------------------------------------------------------------
RAM_OVL36:021BD728
RAM_OVL36:021BD728             loc_21BD728                             ; CODE XREF: abilDecision+3Aj
RAM_OVL36:021BD728 14 29       CMP     R1, #0x14
RAM_OVL36:021BD72A 01 D2       BCS     loc_21BD730
RAM_OVL36:021BD72C AC 64       STR     R4, [R5,#0x48]
RAM_OVL36:021BD72E 70 BD       POP     {R4-R6,PC}
RAM_OVL36:021BD730             ; ---------------------------------------------------------------------------
RAM_OVL36:021BD730
RAM_OVL36:021BD730             loc_21BD730                             ; CODE XREF: abilDecision+52j
RAM_OVL36:021BD730 01 20       MOVS    R0, #1
RAM_OVL36:021BD732 A8 64       STR     R0, [R5,#0x48]
RAM_OVL36:021BD734 70 BD       POP     {R4-R6,PC}
RAM_OVL36:021BD736             ; ---------------------------------------------------------------------------
RAM_OVL36:021BD736
RAM_OVL36:021BD736             loc_21BD736                             ; CODE XREF: abilDecision+3Ej
RAM_OVL36:021BD736 14 29       CMP     R1, #0x14
RAM_OVL36:021BD738 01 D2       BCS     loc_21BD73E
RAM_OVL36:021BD73A AC 64       STR     R4, [R5,#0x48]
RAM_OVL36:021BD73C 70 BD       POP     {R4-R6,PC}
RAM_OVL36:021BD73E             ; ---------------------------------------------------------------------------
RAM_OVL36:021BD73E
RAM_OVL36:021BD73E             loc_21BD73E                             ; CODE XREF: abilDecision+60j
RAM_OVL36:021BD73E 28 29       CMP     R1, #0x28 ; '('
RAM_OVL36:021BD740 02 D2       BCS     loc_21BD748
RAM_OVL36:021BD742 01 20       MOVS    R0, #1
RAM_OVL36:021BD744 A8 64       STR     R0, [R5,#0x48]
RAM_OVL36:021BD746 70 BD       POP     {R4-R6,PC}
RAM_OVL36:021BD748             ; ---------------------------------------------------------------------------
RAM_OVL36:021BD748
RAM_OVL36:021BD748             loc_21BD748                             ; CODE XREF: abilDecision+68j
RAM_OVL36:021BD748 02 20       MOVS    R0, #2
RAM_OVL36:021BD74A A8 64       STR     R0, [R5,#0x48]
RAM_OVL36:021BD74C 70 BD       POP     {R4-R6,PC}
RAM_OVL36:021BD74C             ; End of function abilDecision


here's where it gets sort of interesting. if you have a ditto, the previous function still runs. however, right after it another function runs that checks if you have a ditto. if you do have one, it advances the rng and does u32 >> 31 and stores the result of that calculation as the ability. this limits ditto-based breeding to abil 0/1.


Code:
RAM_OVL36:021BD750             ; =============== S U B R O U T I N E =======================================
RAM_OVL36:021BD750
RAM_OVL36:021BD750
RAM_OVL36:021BD750             dittoAbilFix                            ; CODE XREF: breedingSetup+13Ap
RAM_OVL36:021BD750 F8 B5       PUSH    {R3-R7,LR}
RAM_OVL36:021BD752 05 1C       MOVS    R5, R0
RAM_OVL36:021BD754 28 68       LDR     R0, [R5]
RAM_OVL36:021BD756 0E 1C       MOVS    R6, R1
RAM_OVL36:021BD758 14 1C       MOVS    R4, R2
RAM_OVL36:021BD75A 05 21       MOVS    R1, #5
RAM_OVL36:021BD75C 00 22       MOVS    R2, #0
RAM_OVL36:021BD75E 5F F6 BF FA BL      getPKMStat
RAM_OVL36:021BD762 07 1C       MOVS    R7, R0
RAM_OVL36:021BD764 68 68       LDR     R0, [R5,#4]
RAM_OVL36:021BD766 05 21       MOVS    R1, #5
RAM_OVL36:021BD768 00 22       MOVS    R2, #0
RAM_OVL36:021BD76A 5F F6 B9 FA BL      getPKMStat
RAM_OVL36:021BD76E 84 2F       CMP     R7, #0x84 ; '¦'
RAM_OVL36:021BD770 01 D0       BEQ     loc_21BD776
RAM_OVL36:021BD772 84 28       CMP     R0, #0x84 ; '¦'
RAM_OVL36:021BD774 15 D1       BNE     locret_21BD7A2
RAM_OVL36:021BD776
RAM_OVL36:021BD776             loc_21BD776                             ; CODE XREF: dittoAbilFix+20j
RAM_OVL36:021BD776 A0 68       LDR     R0, [R4,#8]                     ; num1
RAM_OVL36:021BD778 E1 68       LDR     R1, [R4,#0xC]
RAM_OVL36:021BD77A 22 68       LDR     R2, [R4]                        ; num2
RAM_OVL36:021BD77C 63 68       LDR     R3, [R4,#4]
RAM_OVL36:021BD77E CF F6 CC ED BLX     mul64
RAM_OVL36:021BD782 22 69       LDR     R2, [R4,#0x10]
RAM_OVL36:021BD784 63 69       LDR     R3, [R4,#0x14]
RAM_OVL36:021BD786 10 18       ADDS    R0, R2, R0
RAM_OVL36:021BD788 4B 41       ADCS    R3, R1
RAM_OVL36:021BD78A 00 21       MOVS    R1, #0
RAM_OVL36:021BD78C 20 60       STR     R0, [R4]
RAM_OVL36:021BD78E D8 0F       LSRS    R0, R3, #0x1F
RAM_OVL36:021BD790 49 00       LSLS    R1, R1, #1
RAM_OVL36:021BD792 63 60       STR     R3, [R4,#4]
RAM_OVL36:021BD794 01 43       ORRS    R1, R0
RAM_OVL36:021BD796 02 D1       BNE     loc_21BD79E
RAM_OVL36:021BD798 00 20       MOVS    R0, #0
RAM_OVL36:021BD79A B0 64       STR     R0, [R6,#0x48]
RAM_OVL36:021BD79C F8 BD       POP     {R3-R7,PC}
RAM_OVL36:021BD79E             ; ---------------------------------------------------------------------------
RAM_OVL36:021BD79E
RAM_OVL36:021BD79E             loc_21BD79E                             ; CODE XREF: dittoAbilFix+46j
RAM_OVL36:021BD79E 01 20       MOVS    R0, #1
RAM_OVL36:021BD7A0 B0 64       STR     R0, [R6,#0x48]
RAM_OVL36:021BD7A2
RAM_OVL36:021BD7A2             locret_21BD7A2                          ; CODE XREF: dittoAbilFix+24j
RAM_OVL36:021BD7A2 F8 BD       POP     {R3-R7,PC}
RAM_OVL36:021BD7A2             ; End of function dittoAbilFix


all the mul64 calls are for the inlined rng that gets used with breeding.
 
loc_21DC442 is where the moody stat advances are handled. It calls a rand 0x2a (42) which it uses as a pointer into a table of halfwords located at 0x02271dc8. This table consists of pairs of stats, one that's lower and one that's dropped and it does not contain pairs such as 1,1 so that you can't raise and lower the same stat. 1 = Atk, 2 = Def, 3 = SpA, 4 = SpD, 5 = Spe, 6 = accuracy, 7 = evasion. It stores these numbers in R5, the lowered stat, and R6, the raised stat. Also Battle Subway cheating is a total lie as we all expected.
 
everstone always works in b2w2.

Code:
RAM_OVL36:021BD62C             ; =============== S U B R O U T I N E =======================================
RAM_OVL36:021BD62C
RAM_OVL36:021BD62C
RAM_OVL36:021BD62C             ; void __fastcall everstoneHandler(void *pDaycarePKM, void *pEggStruct, u64 *eggSeed)
RAM_OVL36:021BD62C             everstoneHandler
RAM_OVL36:021BD62C
RAM_OVL36:021BD62C             var_20= -0x20
RAM_OVL36:021BD62C             var_1C= -0x1C
RAM_OVL36:021BD62C
RAM_OVL36:021BD62C F8 B5       PUSH    {R3-R7,LR}
RAM_OVL36:021BD62E 82 B0       SUB     SP, SP, #8
RAM_OVL36:021BD630 05 1C       MOVS    R5, R0
RAM_OVL36:021BD632 16 1C       MOVS    R6, R2
RAM_OVL36:021BD634 00 22       MOVS    R2, #0                          ; declare/define bool for pkm1 has estone to false
RAM_OVL36:021BD636 0C 1C       MOVS    R4, R1
RAM_OVL36:021BD638 00 92       STR     R2, [SP]                        ; save bool
RAM_OVL36:021BD63A 28 68       LDR     R0, [R5]                        ; pkm1
RAM_OVL36:021BD63C 06 21       MOVS    R1, #6
RAM_OVL36:021BD63E 00 22       MOVS    R2, #0
RAM_OVL36:021BD640 5F F6 4E FB BL      getPKMStat                      ; get item of first pkm
RAM_OVL36:021BD644 E5 28       CMP     R0, #0xE5 ; 's'
RAM_OVL36:021BD646 01 D1       BNE     pkm2Everstone
RAM_OVL36:021BD648 01 20       MOVS    R0, #1                          ; if pkm has estone, pass true
RAM_OVL36:021BD64A 00 90       STR     R0, [SP]                        ; save true to sp
RAM_OVL36:021BD64C
RAM_OVL36:021BD64C             pkm2Everstone                           ; CODE XREF: everstoneHandler+1Aj
RAM_OVL36:021BD64C 68 68       LDR     R0, [R5,#4]                     ; if the first didn't have estone, come straight here and get the pointer to pkm2
RAM_OVL36:021BD64E 06 21       MOVS    R1, #6
RAM_OVL36:021BD650 00 22       MOVS    R2, #0
RAM_OVL36:021BD652 00 27       MOVS    R7, #0
RAM_OVL36:021BD654 5F F6 44 FB BL      getPKMStat                      ; get item of second pkm
RAM_OVL36:021BD658 E5 28       CMP     R0, #0xE5 ; 's'
RAM_OVL36:021BD65A 00 D1       BNE     pickEverstone                   ; if pkm2 doesn't have estone, drop down to nature grab
RAM_OVL36:021BD65C 01 27       MOVS    R7, #1                          ; r7 = true if it has the estone
RAM_OVL36:021BD65E
RAM_OVL36:021BD65E             pickEverstone                           ; CODE XREF: everstoneHandler+2Ej
RAM_OVL36:021BD65E 28 68       LDR     R0, [R5]                        ; 1st pkm
RAM_OVL36:021BD660 70 21       MOVS    R1, #0x70 ; 'p'
RAM_OVL36:021BD662 00 22       MOVS    R2, #0
RAM_OVL36:021BD664 5F F6 3C FB BL      getPKMStat                      ; get nature of first pkm
RAM_OVL36:021BD668 01 90       STR     R0, [SP,#4]                     ; save nature1 to sp+4
RAM_OVL36:021BD66A 68 68       LDR     R0, [R5,#4]
RAM_OVL36:021BD66C 70 21       MOVS    R1, #0x70 ; 'p'
RAM_OVL36:021BD66E 00 22       MOVS    R2, #0
RAM_OVL36:021BD670 5F F6 36 FB BL      getPKMStat                      ; get nature of pkm2
RAM_OVL36:021BD674 05 1C       MOVS    R5, R0                          ; save nature2 to r5
RAM_OVL36:021BD676 00 98       LDR     R0, [SP]                        ; load 'does pkm1 have estone' bool
RAM_OVL36:021BD678 00 28       CMP     R0, #0                          ; if not, jump past the rand call and set up the nature pass
RAM_OVL36:021BD67A 1D D0       BEQ     pkm1EverstoneCheck
RAM_OVL36:021BD67C 00 2F       CMP     R7, #0                          ; check 'does pkm2 have estone' bool
RAM_OVL36:021BD67E 1B D0       BEQ     pkm1EverstoneCheck              ; if both of these pass, both pkms have everstones.  the game has to determine which nature to use. run the inline rng and take the top bit to pick which nature
RAM_OVL36:021BD680 B0 68       LDR     R0, [R6,#8]                     ; num1
RAM_OVL36:021BD682 F1 68       LDR     R1, [R6,#0xC]
RAM_OVL36:021BD684 32 68       LDR     R2, [R6]                        ; num2
RAM_OVL36:021BD686 73 68       LDR     R3, [R6,#4]                     ; num1
RAM_OVL36:021BD688 CF F6 46 EE BLX     mul64
RAM_OVL36:021BD68C 33 69       LDR     R3, [R6,#0x10]                  ; 00269ec3
RAM_OVL36:021BD68E 72 69       LDR     R2, [R6,#0x14]                  ; 00000000
RAM_OVL36:021BD690 18 18       ADDS    R0, R3, R0                      ; add
RAM_OVL36:021BD692 4A 41       ADCS    R2, R1                          ; add
RAM_OVL36:021BD694 00 21       MOVS    R1, #0                          ; initialize some variable
RAM_OVL36:021BD696 30 60       STR     R0, [R6]                        ; store back the bottom half of the inline seed
RAM_OVL36:021BD698 D0 0F       LSRS    R0, R2, #0x1F                   ; u32 >> 31
RAM_OVL36:021BD69A 49 00       LSLS    R1, R1, #1                      ; 0 << 1, this makes no sense.
RAM_OVL36:021BD69C 72 60       STR     R2, [R6,#4]                     ; store back top half of seed
RAM_OVL36:021BD69E 01 43       ORRS    R1, R0                          ; (u32 >> 31) | (0 << 1), only useful for setting the status bit
RAM_OVL36:021BD6A0 05 D1       BNE     usePKM2
RAM_OVL36:021BD6A2 01 98       LDR     R0, [SP,#4]                     ; if u32 >> 31 is 0, load nature1 into r0
RAM_OVL36:021BD6A4 02 B0       ADD     SP, SP, #8                      ; unwind
RAM_OVL36:021BD6A6 E0 60       STR     R0, [R4,#0xC]                   ; store nature1 to egg struct in nature spot
RAM_OVL36:021BD6A8 01 20       MOVS    R0, #1                          ; bool eStone = TRUE
RAM_OVL36:021BD6AA E0 64       STR     R0, [R4,#0x4C]                  ; set estoneParent1 to true
RAM_OVL36:021BD6AC F8 BD       POP     {R3-R7,PC}
RAM_OVL36:021BD6AE             ; ---------------------------------------------------------------------------
RAM_OVL36:021BD6AE
RAM_OVL36:021BD6AE             usePKM2                                 ; CODE XREF: everstoneHandler+74j
RAM_OVL36:021BD6AE 01 20       MOVS    R0, #1                          ; bool eStone = TRUE
RAM_OVL36:021BD6B0 02 B0       ADD     SP, SP, #8                      ; unwind
RAM_OVL36:021BD6B2 E5 60       STR     R5, [R4,#0xC]                   ; store nature2 to egg struct in nature spot
RAM_OVL36:021BD6B4 20 65       STR     R0, [R4,#0x50]                  ; set estoneParent2 to true
RAM_OVL36:021BD6B6 F8 BD       POP     {R3-R7,PC}
RAM_OVL36:021BD6B8             ; ---------------------------------------------------------------------------
RAM_OVL36:021BD6B8
RAM_OVL36:021BD6B8             pkm1EverstoneCheck                      ; CODE XREF: everstoneHandler+4Ej
RAM_OVL36:021BD6B8                                                     ; everstoneHandler+52j
RAM_OVL36:021BD6B8 00 98       LDR     R0, [SP]                        ; load 'does pkm1 have estone' bool
RAM_OVL36:021BD6BA 00 28       CMP     R0, #0                          ; if it doesn't, jump past
RAM_OVL36:021BD6BC 05 D0       BEQ     pkm2EverstoneCheck
RAM_OVL36:021BD6BE 01 98       LDR     R0, [SP,#4]                     ; if bool is true, load nature1 into r0
RAM_OVL36:021BD6C0 02 B0       ADD     SP, SP, #8                      ; unwind
RAM_OVL36:021BD6C2 E0 60       STR     R0, [R4,#0xC]                   ; store nature1 to egg struct in nature spot
RAM_OVL36:021BD6C4 01 20       MOVS    R0, #1                          ; bool eStone = TRUE
RAM_OVL36:021BD6C6 E0 64       STR     R0, [R4,#0x4C]                  ; set estoneParent1 to true
RAM_OVL36:021BD6C8 F8 BD       POP     {R3-R7,PC}
RAM_OVL36:021BD6CA             ; ---------------------------------------------------------------------------
RAM_OVL36:021BD6CA
RAM_OVL36:021BD6CA             pkm2EverstoneCheck                      ; CODE XREF: everstoneHandler+90j
RAM_OVL36:021BD6CA 00 2F       CMP     R7, #0                          ; r7 is the 'does pkm2 have estone' bool
RAM_OVL36:021BD6CC 02 D0       BEQ     return                          ; if this is false, neither pkm has an everstone.  finish.
RAM_OVL36:021BD6CE 01 20       MOVS    R0, #1                          ; bool eStone = TRUE
RAM_OVL36:021BD6D0 E5 60       STR     R5, [R4,#0xC]                   ; store nature2 to egg struct in nature spot
RAM_OVL36:021BD6D2 20 65       STR     R0, [R4,#0x50]                  ; set estoneParent2 to true
RAM_OVL36:021BD6D4
RAM_OVL36:021BD6D4             return                                  ; CODE XREF: everstoneHandler+A0j
RAM_OVL36:021BD6D4 02 B0       ADD     SP, SP, #8                      ; unwind
RAM_OVL36:021BD6D6 F8 BD       POP     {R3-R7,PC}
RAM_OVL36:021BD6D6             ; End of function everstoneHandler
RAM_OVL36:021BD6D6

the egg will always get the nature of the pkm with the everstone. if both have an everstone, the egg with get the nature that follows u32 >> 31, 0 being nature 1(daycare pkm1) and 1 being nature2(daycare pkm2). no one bothered to look, thinking the rand call in the function was for the 50/50 on the everstone.
 
Gen 3 Pokerus:


get a random number 0-0xFFFF and check if it's equal to 0x4000, 0x8000, or 0xC000. if it's equal to any of the 3, pick a pkm party slot via rand() % 6. check to be sure that slot is filled, repeating the process to pick a new one if it's not. once they're sure it is, call rand again and do rand() & 0xFF. take the byte and do & 7 and store the result, repeating the process if it results in 0. once they have a non-zero result, take the byte and do & 0xF0. store this result if it's non-zero. at this point, they take the byte, & 0xF3 and add 1. this result is stored to the pkm file as field 0x22.


Code:
ROM:0806DCB4             @ =============== S U B R O U T I N E =======================================
ROM:0806DCB4
ROM:0806DCB4
ROM:0806DCB4             @ void __fastcall pokerusHandler(void *pPartyBlock)
ROM:0806DCB4             pokerusHandler:
ROM:0806DCB4
ROM:0806DCB4             var_14          = -0x14
ROM:0806DCB4
ROM:0806DCB4 70 B5                       PUSH    {R4-R6,LR}
ROM:0806DCB6 81 B0                       SUB     SP, SP, #4
ROM:0806DCB8 06 1C                       MOVS    R6, R0
ROM:0806DCBA 01 F0 87 FC                 BL      rand__
ROM:0806DCBE 00 04                       LSLS    R0, R0, #0x10
ROM:0806DCC0 05 0C                       LSRS    R5, R0, #0x10
ROM:0806DCC2 80 20 C0 01                 MOVS    R0, 0x4000
ROM:0806DCC6 85 42                       CMP     R5, R0
ROM:0806DCC8 07 D0                       BEQ     pick_pkm
ROM:0806DCCA 80 20 00 02                 MOVS    R0, 0x8000
ROM:0806DCCE 85 42                       CMP     R5, R0
ROM:0806DCD0 03 D0                       BEQ     pick_pkm
ROM:0806DCD2 C0 20 00 02                 MOVS    R0, 0xC000
ROM:0806DCD6 85 42                       CMP     R5, R0
ROM:0806DCD8 4A D1                       BNE     return
ROM:0806DCDA
ROM:0806DCDA             pick_pkm:                               @ CODE XREF: pokerusHandler+14j
ROM:0806DCDA                                                     @ pokerusHandler+1Cj ...
ROM:0806DCDA 01 F0 77 FC                 BL      rand__
ROM:0806DCDE 00 04                       LSLS    R0, R0, #0x10
ROM:0806DCE0 00 0C                       LSRS    R0, R0, #0x10
ROM:0806DCE2 06 21                       MOVS    R1, #6          @ y
ROM:0806DCE4 79 F2 7C FF                 BL      doMod__
ROM:0806DCE8 00 04                       LSLS    R0, R0, #0x10
ROM:0806DCEA 05 0C                       LSRS    R5, R0, #0x10
ROM:0806DCEC 64 20                       MOVS    R0, #0x64
ROM:0806DCEE 68 43                       MULS    R0, R5
ROM:0806DCF0 34 18                       ADDS    R4, R6, R0
ROM:0806DCF2 20 1C                       MOVS    R0, R4
ROM:0806DCF4 0B 21                       MOVS    R1, #0xB
ROM:0806DCF6 00 22                       MOVS    R2, #0
ROM:0806DCF8 FC F7 0E FC                 BL      getPKMData
ROM:0806DCFC 00 28                       CMP     R0, #0
ROM:0806DCFE EC D0                       BEQ     pick_pkm
ROM:0806DD00 20 1C                       MOVS    R0, R4
ROM:0806DD02 2D 21                       MOVS    R1, #0x2D
ROM:0806DD04 00 22                       MOVS    R2, #0
ROM:0806DD06 FC F7 07 FC                 BL      getPKMData
ROM:0806DD0A 00 28                       CMP     R0, #0
ROM:0806DD0C E5 D1                       BNE     pick_pkm
ROM:0806DD0E 1A 49                       LDR     R1, =unk_832A328
ROM:0806DD10 A8 00                       LSLS    R0, R5, #2
ROM:0806DD12 40 18                       ADDS    R0, R0, R1
ROM:0806DD14 01 78                       LDRB    R1, [R0]
ROM:0806DD16 30 1C                       MOVS    R0, R6
ROM:0806DD18 00 F0 64 F8                 BL      sub_806DDE4
ROM:0806DD1C 00 06                       LSLS    R0, R0, #0x18
ROM:0806DD1E 00 28                       CMP     R0, #0
ROM:0806DD20 26 D1                       BNE     return
ROM:0806DD22 07 24                       MOVS    R4, #7
ROM:0806DD24
ROM:0806DD24             set_strain:                             @ CODE XREF: pokerusHandler+84j
ROM:0806DD24 01 F0 52 FC                 BL      rand__
ROM:0806DD28 00 06                       LSLS    R0, R0, #0x18
ROM:0806DD2A 00 0E                       LSRS    R0, R0, #0x18
ROM:0806DD2C 69 46                       MOV     R1, SP
ROM:0806DD2E 08 70                       STRB    R0, [R1,#0x14+var_14]
ROM:0806DD30 02 1C                       MOVS    R2, R0
ROM:0806DD32 11 1C                       MOVS    R1, R2
ROM:0806DD34 21 40                       ANDS    R1, R4
ROM:0806DD36 00 29                       CMP     R1, #0
ROM:0806DD38 F4 D0                       BEQ     set_strain
ROM:0806DD3A F0 20                       MOVS    R0, #0xF0
ROM:0806DD3C 10 40                       ANDS    R0, R2
ROM:0806DD3E 00 28                       CMP     R0, #0
ROM:0806DD40 01 D0                       BEQ     make_pkrs_and_write
ROM:0806DD42 68 46                       MOV     R0, SP
ROM:0806DD44 01 70                       STRB    R1, [R0,#0x14+var_14]
ROM:0806DD46
ROM:0806DD46             make_pkrs_and_write:                    @ CODE XREF: pokerusHandler+8Cj
ROM:0806DD46 68 46                       MOV     R0, SP
ROM:0806DD48 00 78                       LDRB    R0, [R0,#0x14+var_14]
ROM:0806DD4A 01 01                       LSLS    R1, R0, #4
ROM:0806DD4C 08 43                       ORRS    R0, R1
ROM:0806DD4E 00 06                       LSLS    R0, R0, #0x18
ROM:0806DD50 00 0E                       LSRS    R0, R0, #0x18
ROM:0806DD52 69 46                       MOV     R1, SP
ROM:0806DD54 08 70                       STRB    R0, [R1,#0x14+var_14]
ROM:0806DD56 F3 21                       MOVS    R1, #0xF3
ROM:0806DD58 01 40                       ANDS    R1, R0
ROM:0806DD5A 68 46                       MOV     R0, SP
ROM:0806DD5C 01 70                       STRB    R1, [R0,#0x14+var_14]
ROM:0806DD5E 01 31                       ADDS    R1, #1
ROM:0806DD60 01 70                       STRB    R1, [R0,#0x14+var_14]
ROM:0806DD62 64 20                       MOVS    R0, #0x64
ROM:0806DD64 68 43                       MULS    R0, R5
ROM:0806DD66 30 18                       ADDS    R0, R6, R0
ROM:0806DD68 22 21                       MOVS    R1, #0x22
ROM:0806DD6A 6A 46                       MOV     R2, SP
ROM:0806DD6C FC F7 9E FF                 BL      writePKMData
ROM:0806DD70
ROM:0806DD70             return:                                 @ CODE XREF: pokerusHandler+24j
ROM:0806DD70                                                     @ pokerusHandler+6Cj
ROM:0806DD70 01 B0                       ADD     SP, SP, #4
ROM:0806DD72 70 BC                       POP     {R4-R6}
ROM:0806DD74 01 BC                       POP     {R0}
ROM:0806DD76 00 47                       BX      R0
ROM:0806DD76             @ End of function pokerusHandler
ROM:0806DD76
ROM:0806DD76             @ ---------------------------------------------------------------------------
ROM:0806DD78 28 A3 32 08 off_806DD78:    .long unk_832A328       @ DATA XREF: pokerusHandler+5Ar

that top bit that looks kind of odd is basically just:

int pkrs = rand();

if(pkrs == 0x4000 || pkrs == 0x8000 || pkrs == 0xC000)
{*generate pokerus here*}


and no, there's no check for an egg or anything else. anything can be infected with or spread pokerus. also, it can spread to either pokemon surrounding the infected one, not just the next one in line like i see people saying occasionally.

correction: eggs cannot be infected with pokerus in any gen 3 game. they can, however, have it spread to them from another party member.
 
so the ability being 80% biased toward the mother's ability also exists in bw1.

Code:
021C3D34 B5F8     push    {r3-r7,r14}
021C3D36 1C05     mov     r5,r0
021C3D38 6868     ldr     r0,[r5,#0x4]
021C3D3A 1C0C     mov     r4,r1
021C3D3C 9200     str     r2,[sp]
021C3D3E 2105     mov     r1,#0x5
021C3D40 2200     mov     r2,#0x0
021C3D42 F654F879 bl      #0x2017E38
021C3D46 1C06     mov     r6,r0
021C3D48 6868     ldr     r0,[r5,#0x4]
021C3D4A 216F     mov     r1,#0x6F
021C3D4C 2200     mov     r2,#0x0
021C3D4E F654F873 bl      #0x2017E38
021C3D52 1C07     mov     r7,r0
021C3D54 6868     ldr     r0,[r5,#0x4]
021C3D56 210A     mov     r1,#0xA
021C3D58 2200     mov     r2,#0x0
021C3D5A F654F86D bl      #0x2017E38
021C3D5E 1C02     mov     r2,r0
021C3D60 0430     lsl     r0,r6,#0x10
021C3D62 0439     lsl     r1,r7,#0x10
021C3D64 0412     lsl     r2,r2,#0x10
021C3D66 9B00     ldr     r3,[sp]
021C3D68 0C00     lsr     r0,r0,#0x10
021C3D6A 0C09     lsr     r1,r1,#0x10
021C3D6C 0C12     lsr     r2,r2,#0x10
021C3D6E F000FBE9 bl      #0x21C4544
021C3D72 1C05     mov     r5,r0
021C3D74 2064     mov     r0,#0x64
021C3D76 F641FCD7 bl      #0x2005728
021C3D7A 2D00     cmp     r5,#0x0
021C3D7C D003     beq     #0x21C3D86
021C3D7E 2D01     cmp     r5,#0x1
021C3D80 D009     beq     #0x21C3D96
021C3D82 2D02     cmp     r5,#0x2
021C3D84 D00F     beq     #0x21C3DA6
021C3D86 2850     cmp     r0,#0x50
021C3D88 D202     bcs     #0x21C3D90
021C3D8A 2000     mov     r0,#0x0
021C3D8C 64E0     str     r0,[r4,#0x4C]
021C3D8E BDF8     pop     {r3-r7,r15}
021C3D90 2001     mov     r0,#0x1
021C3D92 64E0     str     r0,[r4,#0x4C]
021C3D94 BDF8     pop     {r3-r7,r15}
021C3D96 2814     cmp     r0,#0x14
021C3D98 D202     bcs     #0x21C3DA0
021C3D9A 2000     mov     r0,#0x0
021C3D9C 64E0     str     r0,[r4,#0x4C]
021C3D9E BDF8     pop     {r3-r7,r15}
021C3DA0 2001     mov     r0,#0x1
021C3DA2 64E0     str     r0,[r4,#0x4C]
021C3DA4 BDF8     pop     {r3-r7,r15}
021C3DA6 2814     cmp     r0,#0x14
021C3DA8 D202     bcs     #0x21C3DB0
021C3DAA 2000     mov     r0,#0x0
021C3DAC 64E0     str     r0,[r4,#0x4C]
021C3DAE BDF8     pop     {r3-r7,r15}
021C3DB0 2828     cmp     r0,#0x28
021C3DB2 D202     bcs     #0x21C3DBA
021C3DB4 2001     mov     r0,#0x1
021C3DB6 64E0     str     r0,[r4,#0x4C]
021C3DB8 BDF8     pop     {r3-r7,r15}
021C3DBA 2002     mov     r0,#0x2
021C3DBC 64E0     str     r0,[r4,#0x4C]
021C3DBE BDF8     pop     {r3-r7,r15}

it's probably not something we ever even thought about since most people breed with dittos unless they're going for a dw ability, which is just a straight 20/20/60 if the mother has it and dittos have their own special ability fixing function.
 
just to sum up all the stuff we were talking about in irc:



if the mother has ability 0:

if rand(100) < 80, set abil 0. if >= 80, set abil 1.

if the mother has ability 1:

if rand(100) < 20, set abil 0. if >= 20, set abil 1.

if the mother has ability 2(dw abil):

if rand(100) < 20, set abil 0. if < 40, set abil 1. if >= 40, set ability 2(dw abil).


**however, it turns out the game never actually uses the result of all that work it does. the ability still seems to be pid >> 16 & 1, even though all of that other code runs and selects a pid based on the mother's ability. it's unused code that actually does run, which doesn't make much sense at all.

basically, it does getPKMStat(egg, ABILITY, 0) which gets the ability using pid >> 16 & 1, it doesn't refer to the stored ability at all.
-----------------------------------------------------

any nido except nidorina and nidoqueen will cause the nidoran compute function to run. it checks for a species from 0x1D to 0x22 excluding 1E and 1F.

-----------------------------------------------------

if you're using a ditto to breed, the previous calc will still happen. however, right afterward there is another check to see if a ditto is involved. if so, the game does rand(2) to pick which ability to use. the 0 and 1 results directly correspond to the possible abilities.
 
swarms in gen 5:

rand(17)(19 in bw2) to pick the route and then store the result to 0x223D6CC + 0x30(0x223D6EC + 0x30)(white/black1)

e:

in bw1: 0x200D440
in bw2: 0x200DD20
(set swarm route)

this happens just after midnight and on loading the save to pick a new swarm.
 
i found something by accident last night. it's only relevant to gen 4 wondercards so it has no real application, but is interesting trivia nonetheless. so, gen 4 wondercard pids are made from a combo of a counter and a timer0 value. no one really knew what that value was though. turns out it's part of "OSi_TickCount", a volatile 64-bit number that holds the current value of the tick system for the ds.

most ds games have a function that runs as the very first thing once system control is passed to main() and this function is usually called "SystemInit" and it turns on systems that the game will use, allocates system memory, stuff like that. in SystemInit, gamefreak turns on the tick system(OS_InitTick), turns on the graphics system, the fixed point math system, the alarm system, starts pxi, initializes the os, etc. OS_InitTick sets OSi_TickCount to 0, turns on timer0, sets OSi_UseTick to true(bool variable that indicates the system is on), sets OSi_NeedResetTimer to false(bool var that says whether or not the tick counter should be reset to 0), and sets the timer0 interrupt callback to OSi_CountUpTick() to insure that OSi_TickCount increments.

Code:
RAM_ARM9:0207B7AE 06 49                       LDR     R1, =0x207B7D9  ; OSi_CountUpTick
RAM_ARM9:0207B7B0 08 20                       MOVS    R0, #8
RAM_ARM9:0207B7B2 FE F7 3B F9                 BL      OS_SetIrqFunction
RAM_ARM9:0207B7B6 08 20                       MOVS    R0, #8
RAM_ARM9:0207B7B8 FE F7 E0 F9                 BL      OS_EnableIrqMask

So there's a callback to increment this variable, but when does the callback run? It runs when timer0 overflows. when timer0 hits 0xFFFF and resets to 0x0000, an interrupt fires and OSi_CountUpTick runs. it does OSi_TickCount++ and some housekeeping and that's it.

what does this have to do with pokemon? when a 4th gen wondercard is created, OS_GetTick is called. it makes a number using OSi_TickCount and the current value of timer0 that looks like this:

Code:
*(vu16*)REG_T0Dat = 0x4000100;

volatile u16 tickLow;
volatile u64 tickHigh;

tickhigh = OSi_TickCounter & 0xFFFFFFFFFFFFULL;
tickLow = REG_T0Dat;

return ((tickhigh << 16) | tickLow);  //(this is returning a 64-bit number, the lower half in r0)


so the exact pids for gen 4 wondercards are the lowest 16 bits of the tick counter << 16 and then OR-ed with timer0. gamefreak is getting back a 64-bit number and taking the lower half as the pid, basically. if they used the upper half, wondercard pids would be rng-able.


in white, the tick system enabled bool is at 2151350, 2151354 is the bool for resetting the counter, and 2151358-215135F(215135C then 2151358) is the actual tick counter.

in hgss the starting value is 21E19D4.

and just as an idea of how fast this stuff is: timer0 moves(does one full interval of 0-FFFF) at F/64 seconds, where F is the CPU speed of the ARM7 CPU. 0x100 ticks(which is 0x100/256d overflows of timer0) takes all of roughly 7.5 video frames, a little over 1/10th of a second or about .15 seconds total.

so the first pid is ((counter << 16) | timer0) * 6C078965 + 1.

also, since i'm talking about gen 4 wondercards, the pid value on the card has 3 states. if it's greater than 1, then the pid = that number. if the pid value on the card is 1, the pid is generated dynamically. if the value on the card is 0 the pid is also generated dynamically, but the shiny check never happens. so if there's a card out there with a 0 for the pid value, it can be shiny. i've not ever seen one, but who knows.
 
the nazos for b2w2 english are:


white:
209AF28
2039E15
2200050
22000A4
22000A4


black:
209AEE8
2039DE9
2200010
2200064
2200064


the rng for b2w2 is at 0x021FFC58(w)\0x021FFC18(b)
 
Here's the missing nazo for 3DS/DSi:
White2:
0x27a5e90
timer0 = 167e, vcount = ad, vframe = 8
Black2:
0x27a5f70
timer0 = 168a, vcount = ad, vframe = 8

Credits to chiizu for making the searcher, helping me make it compile on my end, and actually finding the black2 parameters.
Future searches should be much faster since now I have GPU acceleration working correctly.
 
Vending Machine Bonus

777DT.png


if high32<0x08000000, then give extra drink. rand(32) = 0

Comes out to 3.125% chance. Drink doesn't matter.

Rand call happens right after you dismiss the "put in the Medicine Case". No wandering NPC advancements occur when you're interacting with the vending machine.
 
French Black2 Nazos for DS Lite:
0x209AF08
0x2039DF9
0x2200030
0x2200084
0x2200084

White2
0x209AF28
0x2039E25
0x2200050
0x22000A4
0x22000A4

credits to xfr
I need DS Lite nazos to run my DSi/3DS searches.
 
Another german white 2 on a german 3DS:

MAC Address: D8-6B-F7-20-AA-62
First pokemon: No chatot PID 0xF4F1A4E4
Second pokemon: 1 chatot PID 0x2A723827

Caught on 12. November 2011 (wasn't sure if 12. Nov or 11. Dec was meant) at Virbank City Complex (not the interior), started game 10:15:25. Used sweet scent.

Edit: Added the PIDs
Edit 2: Updated format:

Game: German White 2
Console: German 3DS
Mac Address: D86BF720AA62
Date Started: November 12th, 2011 (!!)
Time Started: 10:15:25
First Pokemon: https://www.pokecheck.org/?p=detail&uid=2207280
Second Pokemon: https://www.pokecheck.org/?p=detail&uid=2210845
 
With all credit to xfr, here are the other European DS nazos:

Italian Black 2:
0209ADE8
02039D69
021FFF10
021FFF64
021FFF64

Italian White 2:
0209AE28
02039D95
021FFF50
021FFFA4
021FFFA4

Spanish Black 2:
0209AEA8
02039DB9
021FFFD0
02200024
02200024

Spanish White 2:
0209AEC8
02039DE5
021FFFF0
02200044
02200044
 
Not sure if it's still needed, but by the time I saw chiizu's new post I already did it, so might as well post regardless.

3DS MAC Address: A4-C0-E1-00-D4-F6

Had the same doubt Roflumilast had, so did both dates just to play it safe.
No chatter flip: http://www.pokecheck.org/?p=detail&uid=2212207
With 1 chatter flip: http://www.pokecheck.org/?p=detail&uid=2212208

No chatter flip: http://www.pokecheck.org/?p=detail&uid=2212213
With 1 chatter flip: http://www.pokecheck.org/?p=detail&uid=2212215

Both from Italian Black 2, don't have White. :\
 
Not sure if it's still needed, but by the time I saw chiizu's new post I already did it, so might as well post regardless.

We still need this data for the various games. What I and Slashmolder posted above are the details for DS / DS Lite. The data you are providing will be used to work out the necessary details to support the games on DSi / 3DS.
 
Back
Top