The PokéCommunity Forums Fan Games ROM Hacking Research & Development
Development I'm Fixin' It: Emerald's Broken PRNG

Research & Development Got a well-founded knack with ROM hacking? Love reverse-engineering the Pokémon games? Or perhaps you love your assembly language. This is the spot for polling and gathering your ideas, and then implementing them! Share your hypothesis, get ideas from others, and collaborate to create!

Reply
 
Thread Tools
  #1    
Old May 1st, 2010 (6:35 AM).
HackMew's Avatar
HackMew HackMew is offline
Mewtwo Strikes Back
 
Join Date: Jun 2006
Posts: 1,314

Brief Intro


As probably most of you are aware of already, Emerald has a faulty PRNG implementation. The game does not take care of reseeding during the startup, leading to the fact it can be easily abused to get perfect IVs and similar.

Description


While it can be useful, it's indeed a major glitch. Since the whole game randomness is affected, it definitely needs to be fixed. Taking a look at Ruby's code, I found out that the initial reseeding happens as soon as the game starts (i.e. when the boot screen shows up). R/S use their internal clook to generate a 16-bit seed. In Emerald, of course, this part is totally missing. So I decided to emulate the R/S approach by porting their reseeding routine to Emerald. Here's the outcome:

Code:
.text .align 2 .thumb .thumb_func .global EmeraldPrngFix main: push {lr} ldr r1, .GET_CLOCK bl bx_r1 lsr r1, r0, #0x10 lsl r0, r0, #0x10 lsr r0, r0, #0x10 eor r0, r1 ldr r1, .UPDATE_SEED bl bx_r1 ldr r0, .UNK_RAM1 mov r4, #0x0 strb r4, [r0, #0x0] pop {pc} bx_r1: bx r1 .align 2 .UNK_RAM1: .word 0x03002700 .GET_CLOCK: .word 0x0802F664|1 .UPDATE_SEED: .word 0x0806F5F8|1
In order to apply the fix, assemble the routine and insert it somewhere where there's enough free space (if you never done it before, you better check my ASM tutorials). Take note of the address you used, and then replace 02 24 04 70 with FE 46 00 47, and 00 27 00 03 with XX XX XX XX, where XX XX XX XX represents the pointer to the routine's address + 1. For the respective offsets, see below.

The Offsets


  • Emerald US v1.0

    Code:
    0x402 0x478

This research document is Copyright © 2010 by HackMew.
You are not allowed to copy, modify or distribute it without permission.
__________________
Reply With Quote

Relevant Advertising!

  #2    
Old December 19th, 2011 (11:35 PM).
ArmoredGuns ArmoredGuns is offline
 
Join Date: Jan 2010
Posts: 12
Can someone please make an IPS patch of this fix? It seems pretty important, and it seems it requires more than just hex editing... I would love to have this fix but I'm no programmer
Reply With Quote
  #3    
Old December 21st, 2011 (7:38 PM).
esperance esperance is online now
 
Join Date: Mar 2010
Location: Ohio
Age: 20
Gender: Male
Nature: Relaxed
Posts: 3,775
Quote:
Originally Posted by ArmoredGuns View Post
Can someone please make an IPS patch of this fix? It seems pretty important, and it seems it requires more than just hex editing... I would love to have this fix but I'm no programmer
Okay, here you go... However, I really recommend you learn to apply simple hacks like this.
Download.
*Note: Routine inserted at 0x9C0D00*
__________________

A Pokemon that is discriminated!
Support squirtle and make it everyone's favourite.
Reply With Quote
  #4    
Old December 23rd, 2011 (12:19 AM).
Bond697 Bond697 is offline
 
Join Date: Oct 2008
Gender:
Posts: 28
just FYI, the code to seed emerald's prng actually does exist in the game. all you would need to do is branch to this(and maybe turn on timer1 if it's not already, but that's easy) at some point and you're set. it was going to work exactly like fire red and leaf green.

it's just never used:


Code:
ROM:08000560             @ =============== S U B R O U T I N E =======================================
ROM:08000560
ROM:08000560
ROM:08000560             @ void __fastcall seedRNG__()
ROM:08000560             seedRNG__:
ROM:08000560 10 B5                       PUSH    {R4,LR}         @ this function never runs
ROM:08000562 06 48                       LDR     R0, =0x4000104  @ Timer1Data
ROM:08000564 04 88                       LDRH    R4, [R0]
ROM:08000566 20 1C                       MOVS    R0, R4          @ Timer1Data to r0
ROM:08000568 6F F0 46 F8                 BL      setRNG__        @ set rng state (0x3005D80) to result of timer1
ROM:0800056C 04 49                       LDR     R1, =0x4000106  @ T1CNT
ROM:0800056E 00 20                       MOVS    R0, #0
ROM:08000570 08 80                       STRH    R0, [R1]        @ turn off timer1
ROM:08000572 04 48                       LDR     R0, =0x2020000
ROM:08000574 04 80                       STRH    R4, [R0]        @ store the result of timer1 to 0x2020000
ROM:08000576 10 BC                       POP     {R4}
ROM:08000578 01 BC                       POP     {R0}
ROM:0800057A 00 47                       BX      R0
ROM:0800057A             @ End of function seedRNG__
ROM:0800057A
ROM:0800057A             @ ---------------------------------------------------------------------------
ROM:0800057C 04 01 00 04 dword_800057C:  .long 0x4000104         @ DATA XREF: seedRNG__+2r
ROM:08000580 06 01 00 04 dword_8000580:  .long 0x4000106         @ DATA XREF: seedRNG__+Cr
ROM:08000584 00 00 02 02 dword_8000584:  .long 0x2020000         @ DATA XREF: seedRNG__+12r
Code:
 
ROM:0806F5F8             @ =============== S U B R O U T I N E =======================================
ROM:0806F5F8
ROM:0806F5F8
ROM:0806F5F8             @ void __fastcall setRNG__(unsigned short T1Dat)
ROM:0806F5F8             setRNG__:                               @ CODE XREF: seedRNG__+8p
ROM:0806F5F8 00 04                       LSLS    R0, R0, #0x10   @ dumb typecasting
ROM:0806F5FA 00 0C                       LSRS    R0, R0, #0x10
ROM:0806F5FC 02 49                       LDR     R1, =0x3005D80  @ rng buffer
ROM:0806F5FE 08 60                       STR     R0, [R1]        @ set rng to T1Dat
ROM:0806F600 02 49                       LDR     R1, =0x20249BC  @ rng frame counter
ROM:0806F602 00 20                       MOVS    R0, #0          @ set counter to 0 to signify starting seed
ROM:0806F604 08 70                       STRB    R0, [R1]
ROM:0806F606 70 47                       BX      LR
ROM:0806F606             @ End of function setRNG__
Reply With Quote
  #5    
Old December 23rd, 2011 (1:42 AM).
ArmoredGuns ArmoredGuns is offline
 
Join Date: Jan 2010
Posts: 12
Quote:
Originally Posted by agentgeo View Post


Okay, here you go... However, I really recommend you learn to apply simple hacks like this.

*Note: Routine inserted at 0x9C0D00*
Thank you very much!!! I greatly appreciate it

Quote:
Originally Posted by Bond697 View Post
just FYI, the code to seed emerald's prng actually does exist in the game. all you would need to do is branch to this(and maybe turn on timer1 if it's not already, but that's easy) at some point and you're set. it was going to work exactly like fire red and leaf green.

it's just never used:


Code:
ROM:08000560             @ =============== S U B R O U T I N E =======================================
ROM:08000560
ROM:08000560
ROM:08000560             @ void __fastcall seedRNG__()
ROM:08000560             seedRNG__:
ROM:08000560 10 B5                       PUSH    {R4,LR}         @ this function never runs
ROM:08000562 06 48                       LDR     R0, =0x4000104  @ Timer1Data
ROM:08000564 04 88                       LDRH    R4, [R0]
ROM:08000566 20 1C                       MOVS    R0, R4          @ Timer1Data to r0
ROM:08000568 6F F0 46 F8                 BL      setRNG__        @ set rng state (0x3005D80) to result of timer1
ROM:0800056C 04 49                       LDR     R1, =0x4000106  @ T1CNT
ROM:0800056E 00 20                       MOVS    R0, #0
ROM:08000570 08 80                       STRH    R0, [R1]        @ turn off timer1
ROM:08000572 04 48                       LDR     R0, =0x2020000
ROM:08000574 04 80                       STRH    R4, [R0]        @ store the result of timer1 to 0x2020000
ROM:08000576 10 BC                       POP     {R4}
ROM:08000578 01 BC                       POP     {R0}
ROM:0800057A 00 47                       BX      R0
ROM:0800057A             @ End of function seedRNG__
ROM:0800057A
ROM:0800057A             @ ---------------------------------------------------------------------------
ROM:0800057C 04 01 00 04 dword_800057C:  .long 0x4000104         @ DATA XREF: seedRNG__+2r
ROM:08000580 06 01 00 04 dword_8000580:  .long 0x4000106         @ DATA XREF: seedRNG__+Cr
ROM:08000584 00 00 02 02 dword_8000584:  .long 0x2020000         @ DATA XREF: seedRNG__+12r
Code:
 
ROM:0806F5F8             @ =============== S U B R O U T I N E =======================================
ROM:0806F5F8
ROM:0806F5F8
ROM:0806F5F8             @ void __fastcall setRNG__(unsigned short T1Dat)
ROM:0806F5F8             setRNG__:                               @ CODE XREF: seedRNG__+8p
ROM:0806F5F8 00 04                       LSLS    R0, R0, #0x10   @ dumb typecasting
ROM:0806F5FA 00 0C                       LSRS    R0, R0, #0x10
ROM:0806F5FC 02 49                       LDR     R1, =0x3005D80  @ rng buffer
ROM:0806F5FE 08 60                       STR     R0, [R1]        @ set rng to T1Dat
ROM:0806F600 02 49                       LDR     R1, =0x20249BC  @ rng frame counter
ROM:0806F602 00 20                       MOVS    R0, #0          @ set counter to 0 to signify starting seed
ROM:0806F604 08 70                       STRB    R0, [R1]
ROM:0806F606 70 47                       BX      LR
ROM:0806F606             @ End of function setRNG__
Hmm I wonder if FRLG's PRNG seeding routine is better than Ruby/sapphire's...
Reply With Quote
  #6    
Old January 28th, 2012 (8:52 AM).
Kaphotics Kaphotics is offline
♥ Quick Claw Guillotine ♥
 
Join Date: Apr 2011
Posts: 22
Quote:
Originally Posted by ArmoredGuns View Post
Hmm I wonder if FRLG's PRNG seeding routine is better than Ruby/sapphire's...
It's not, R/S was better due to the more variant initial starting seeds (hence more random).

FRLG had 0x0000 - 0xFFFF starting seeds, whereas R/S was 0x0 - 0x7FFFFFFF.

Both are definitely more random than Emerald, but R/S did it better. In later games (DPPt and BW) you have a mix of datetime and hardware timers (delay).
Reply With Quote
  #7    
Old September 2nd, 2012 (7:23 AM).
AlphaDrache's Avatar
AlphaDrache AlphaDrache is offline
 
Join Date: Dec 2009
Gender: Male
Posts: 8
Are the addresses the same for the german emerald ROM?
Reply With Quote
  #8    
Old September 2nd, 2012 (7:50 AM).
Darthatron's Avatar
Darthatron Darthatron is offline
巨大なトロール。
 
Join Date: Jan 2006
Location: Melbourne, Australia
Age: 25
Gender: Male
Nature: Modest
Posts: 1,152
Quote:
Originally Posted by AlphaDrache View Post
Are the addresses the same for the german emerald ROM?
Probably, but to check just see if the bytes at the given offsets are the ones described in the tutorial.
__________________
あなた は しきしゃ です
わたし は ばか です
Reply With Quote
  #9    
Old September 3rd, 2012 (12:52 PM). Edited September 3rd, 2012 by Bond697.
Bond697 Bond697 is offline
 
Join Date: Oct 2008
Gender:
Posts: 28
Quote:
Originally Posted by Kaphotics View Post
It's not, R/S was better due to the more variant initial starting seeds (hence more random).

FRLG had 0x0000 - 0xFFFF starting seeds, whereas R/S was 0x0 - 0x7FFFFFFF.

Both are definitely more random than Emerald, but R/S did it better. In later games (DPPt and BW) you have a mix of datetime and hardware timers (delay).
this is wrong. r/s seeds only go 0-0xffff also even though they use a more complex formula. the seeding is 16-bit either way, so no there's not more seeds.

Code:
ROM:080003E4 ; =============== S U B R O U T I N E =======================================
ROM:080003E4
ROM:080003E4
ROM:080003E4 seedRNG                                 ; CODE XREF: main+30p
ROM:080003E4                 PUSH    {LR}
ROM:080003E6                 BL      buildSeed
ROM:080003EA                 MOVS    R2, R0          ; s32 seed to r2
ROM:080003EC                 LSRS    R0, R2, #0x10   ; r0 = seed >> 16
ROM:080003EE                 LDR     R1, =0xFFFF
ROM:080003F0                 ANDS    R1, R2          ; r1 = seed & 0xFFFF (get lower 16 bits of seed)
ROM:080003F2                 EORS    R0, R1          ; upperSeed ^ lowerSeed
ROM:080003F4                 BL      setRNG
ROM:080003F8                 POP     {R0}
ROM:080003FA                 BX      R0
ROM:080003FA ; End of function seedRNG
ROM:080003FA
ROM:080003FA ; ---------------------------------------------------------------------------
ROM:080003FC dword_80003FC   DCD 0xFFFF              ; DATA XREF: seedRNG+Ar
(sapphire)
Reply With Quote
  #10    
Old October 24th, 2012 (10:35 PM). Edited October 25th, 2012 by aroenai.
aroenai aroenai is offline
 
Join Date: Oct 2012
Gender: Male
Posts: 1
Quote:
Originally Posted by Bond697 View Post
just FYI, the code to seed emerald's prng actually does exist in the game. all you would need to do is branch to this(and maybe turn on timer1 if it's not already, but that's easy) at some point and you're set. it was going to work exactly like fire red and leaf green.

it's just never used:


Code:
ROM:08000560             @ =============== S U B R O U T I N E =======================================
ROM:08000560
ROM:08000560
ROM:08000560             @ void __fastcall seedRNG__()
ROM:08000560             seedRNG__:
ROM:08000560 10 B5                       PUSH    {R4,LR}         @ this function never runs
ROM:08000562 06 48                       LDR     R0, =0x4000104  @ Timer1Data
ROM:08000564 04 88                       LDRH    R4, [R0]
ROM:08000566 20 1C                       MOVS    R0, R4          @ Timer1Data to r0
ROM:08000568 6F F0 46 F8                 BL      setRNG__        @ set rng state (0x3005D80) to result of timer1
ROM:0800056C 04 49                       LDR     R1, =0x4000106  @ T1CNT
ROM:0800056E 00 20                       MOVS    R0, #0
ROM:08000570 08 80                       STRH    R0, [R1]        @ turn off timer1
ROM:08000572 04 48                       LDR     R0, =0x2020000
ROM:08000574 04 80                       STRH    R4, [R0]        @ store the result of timer1 to 0x2020000
ROM:08000576 10 BC                       POP     {R4}
ROM:08000578 01 BC                       POP     {R0}
ROM:0800057A 00 47                       BX      R0
ROM:0800057A             @ End of function seedRNG__
ROM:0800057A
ROM:0800057A             @ ---------------------------------------------------------------------------
ROM:0800057C 04 01 00 04 dword_800057C:  .long 0x4000104         @ DATA XREF: seedRNG__+2r
ROM:08000580 06 01 00 04 dword_8000580:  .long 0x4000106         @ DATA XREF: seedRNG__+Cr
ROM:08000584 00 00 02 02 dword_8000584:  .long 0x2020000         @ DATA XREF: seedRNG__+12r
Code:
 
ROM:0806F5F8             @ =============== S U B R O U T I N E =======================================
ROM:0806F5F8
ROM:0806F5F8
ROM:0806F5F8             @ void __fastcall setRNG__(unsigned short T1Dat)
ROM:0806F5F8             setRNG__:                               @ CODE XREF: seedRNG__+8p
ROM:0806F5F8 00 04                       LSLS    R0, R0, #0x10   @ dumb typecasting
ROM:0806F5FA 00 0C                       LSRS    R0, R0, #0x10
ROM:0806F5FC 02 49                       LDR     R1, =0x3005D80  @ rng buffer
ROM:0806F5FE 08 60                       STR     R0, [R1]        @ set rng to T1Dat
ROM:0806F600 02 49                       LDR     R1, =0x20249BC  @ rng frame counter
ROM:0806F602 00 20                       MOVS    R0, #0          @ set counter to 0 to signify starting seed
ROM:0806F604 08 70                       STRB    R0, [R1]
ROM:0806F606 70 47                       BX      LR
ROM:0806F606             @ End of function setRNG__
Can someone post an .ips patch that uses the built in code for Emerald, and possibly port it to R/S? The reason I ask is the batteries finally died in my copies of R/S/E so I wanted to start using my EZ Flash 3in1 and EZ Flash IV which both lack a RTC (gbata patched).

Edit: Oh wait, would that just be 61 05 00 08 at 0x478 for Emerald?
Edit 2: Nope white screen
Reply With Quote
  #11    
Old April 7th, 2014 (10:34 PM).
ThomasWinwood ThomasWinwood is offline
 
Join Date: Nov 2013
Gender: Male
Nature: Relaxed
Posts: 70
Quote:
Originally Posted by aroenai View Post
Can someone post an .ips patch that uses the built in code for Emerald, and possibly port it to R/S?
This isn't an IPS patch (though making one is trivial) but I think that you can use the existing RNG seeding routine by making the following changes. (I would really appreciate someone checking that this does in fact seed the PRNG correctly - I'm on Linux, so the only debugging tools I have available to me are "does the ROM work" and "do I get anything odd, like a trainer ID of 00000".)
  1. At 0x402 change 00 24 04 70 to FE 46 00 47.
  2. At 0x478 change 00 27 00 03 to 61 05 00 08.
  3. At 0x578 change 01 BC 00 47 to 00 BD 08 47.
Reply With Quote
  #12    
Old 4 Weeks Ago (3:44 PM). Edited 3 Weeks Ago by MWisBest.
MWisBest MWisBest is offline
 
Join Date: Mar 2017
Gender: Male
Posts: 19
Quote:
Originally Posted by ThomasWinwood View Post
This isn't an IPS patch (though making one is trivial) but I think that you can use the existing RNG seeding routine by making the following changes. (I would really appreciate someone checking that this does in fact seed the PRNG correctly - I'm on Linux, so the only debugging tools I have available to me are "does the ROM work" and "do I get anything odd, like a trainer ID of 00000".)
  1. At 0x402 change 00 24 04 70 to FE 46 00 47.
  2. At 0x478 change 00 27 00 03 to 61 05 00 08.
  3. At 0x578 change 01 BC 00 47 to 00 BD 08 47.
Sorry to dig up an old thread, but unfortunately this does not work. As far as I can tell, the issue is timer1 isn't turned on, so the end result is the PRNG is (re)seeded to 0. It would be nice not to rely on the RTC for the seed, but I'm not particularly good at writing assembly, just interpreting it. :/

I see the link died for the IPS patch of HackMew's fix, so I've attached a new one that should be identical (routine still inserted at 0x9C0D00).

Edit: Actually I was able to whip something up to enable timer1 and then call the seed function, but the timer value is always the same since the timing is never different.
It turns out the PRNG is seeded with the built-in function when a new game is started, but not when an existing one is loaded. It turns on timer1 when New Game is pressed (or somewhere around there), and then after the player enters their name it calls the built-in seed-from-timer1 function at 0x560.

For this method to work, timer1 needs to be turned on when the opening movie begins playing, and the built-in seed-from-timer1 function needs to be called when "Continue" (Load Game) is pressed. How exactly that can be done, I'm not sure yet.


Edit2: Well I've surprised myself. I seem to have gotten this built-in timer-based PRNG seeding working.

There's 1 routine required. The byte edit at 0x400 uses the game's built in function for enabling T1, and the added routine is to run the seed function after the "Press Start" screen.

Code:
.text
.align 2
.thumb
.thumb_func
.global EmeraldTimerPrngSeedAtMenu

main:
	push {lr}
	ldr r1, .SEED_RNG_FROM_T1
	bl bx_r1
	movs r0, #0
	ldr r1, .MENU_CB_THING
	bl bx_r1
	pop {r0}
	bx r0

bx_r1:
	bx r1

.align 2
.SEED_RNG_FROM_T1:
	.word 0x08000560|1
.MENU_CB_THING:
	.word 0x0802F6F4|1
Compile and insert into free space. Byte changes required:
  1. At 0x400 change 1D 48 00 24 04 70 to 00 F0 A8 F8 C0 46.
  2. At 0xAAED0 change DD F6 02 08 to XX XX XX 08, where XX XX XX is the location of the routine (EmeraldTimerPrngSeedAtMenu) +1 (e.x. if you insert it at 0x9C0D00, you'd put 01 0D 9C 08).

I've also attached an IPS of this for those who would prefer that; the routine was inserted at 0x9C0D00.
Attached Files
File Type: ips Emerald RNG Fix.ips‎ (74 Bytes, 1 views) (Save to Dropbox)
File Type: ips Emerald TIMER RNG Fix.ips‎ (63 Bytes, 1 views) (Save to Dropbox)
Reply With Quote
  #13    
Old 4 Weeks Ago (2:31 PM).
DizzyEgg's Avatar
DizzyEgg DizzyEgg is online now
 
Join Date: Feb 2014
Location: Poland
Age: 19
Gender: Male
Nature: Quiet
Posts: 671
Quote:
Originally Posted by MWisBest View Post
.
Why not use the RTC?
Reply With Quote
  #14    
Old 4 Weeks Ago (7:09 PM). Edited 3 Weeks Ago by MWisBest.
MWisBest MWisBest is offline
 
Join Date: Mar 2017
Gender: Male
Posts: 19
Quote:
Originally Posted by DizzyEgg View Post
Why not use the RTC?
Well that's not the method the game intended to be used. There's clearly a reason they changed to the timer method in FR/LG rather than using the RTC method from R/S; Emerald was released after FR/LG and has this timer method built-in, they just forgot to run it on each reset.


Oh, and if anybody is interested, here's a version that seeds the RNG with a full 32-bit value (0x0 to 0xFFFFFFFF instead of 0x0 to 0xFFFF). Requires 2 routines this time.

Byte edits required:
  1. At 0x402 change 00 24 04 70 to FE 46 00 47.
  2. At 0x478 change 00 27 00 03 to XX XX XX 08, where XX XX XX is the location of the first routine (TimersEnable) +1 (e.x. if you insert it at 0x9C0D00, you'd put 01 0D 9C 08).
  3. At 0xAAED0 change DD F6 02 08 to XX XX XX 08, where XX XX XX is the location of the second routine (EmeraldTimerPrngSeedAtMenu) +1 (see above).

There's an IPS patch attached too.

Spoiler:
Code:
.text
.align 2
.thumb
.thumb_func
.global TimersEnable

main:
	push {lr}
	mov r0, #0x80
	ldr r1, .TM1CNT
	strh r0, [r1]
	mov r0, #0x84	@ set timer2 to increment when timer1 overflows ("count-up timing")
	ldr r1, .TM2CNT
	strh r0, [r1]
	pop {pc}

.align 2
.TM1CNT:
	.word 0x04000106
.TM2CNT:
	.word 0x0400010A
Code:
.text
.align 2
.thumb
.thumb_func
.global EmeraldTimerPrngSeedAtMenu

main:
	push {lr}
	
	@ disable the timers immediately so the values remain static
	mov r0, #0x00
	ldr r1, .TM1CNT
	strh r0, [r1]
	ldr r1, .TM2CNT
	strh r0, [r1]
	
	@ manually store the values into the rng and init values, half-word at a time
	ldr r0, .TM1D
	ldrh r0, [r0]
	ldr r1, .RNG_STATE_PART_1
	strh r0, [r1]
	ldr r1, .TIMER_RESULT_PART_1
	strh r0, [r1]
	
	ldr r0, .TM2D
	ldrh r0, [r0]
	ldr r1, .RNG_STATE_PART_2
	strh r0, [r1]
	ldr r1, .TIMER_RESULT_PART_2
	strh r0, [r1]
	
	@ reset rng frame counter to 0
	@ NOTE: the built-in rng seed function seems to think
	@       this value is at 0x020249BC, whereas the rng
	@       advancement routine says it's at 0x020249C0. lolwut
	mov r0, #0
	ldr r1, .RNG_FRAME_COUNTER
	strb r0, [r1]
	
	@ mov r0, #0 is required here as part of the routine this replaces,
	@ but it's already done above here now; just noted in case it's changed.
	ldr r1, .MENU_CB_THING
	bl bx_r1
	pop {r0}
	bx r0

bx_r1:
	bx r1

.align 2
.TM1D:
	.word 0x04000104
.TM1CNT:
	.word 0x04000106
.TM2D:
	.word 0x04000108
.TM2CNT:
	.word 0x0400010A
.RNG_STATE_PART_1:
	.word 0x03005D80
.RNG_STATE_PART_2:
	.word 0x03005D82
.RNG_FRAME_COUNTER:
	.word 0x020249C0
.TIMER_RESULT_PART_1:
	.word 0x02020000
.TIMER_RESULT_PART_2:
	.word 0x02020002
.MENU_CB_THING:
	.word 0x0802F6F4|1


EDIT: Optimized the original routines I posted and fixed a small bug. Size cut in half! :)

Code:
.text
.align 2
.thumb
.thumb_func
.global TimersEnable

main:
	push {lr}
	ldr r1, .TIMER_REGISTER_BASE
	mov r0, #0x80
	strh r0, [r1, #0x06] @ TM1CNT
	mov r0, #0x84	     @ set timer2 to increment when timer1 overflows ("count-up timing")
	strh r0, [r1, #0x0A] @ TM2CNT
	pop {pc}

.align 2
.TIMER_REGISTER_BASE:
	.word 0x04000100
Code:
.text
.align 2
.thumb
.thumb_func
.global EmeraldTimerPrngSeedAtMenu

main:
	push {lr}
	
	@ disable the timers immediately so the values remain static
	mov r0, #0x00
	ldr r1, .TIMER_REGISTER_BASE
	strh r0, [r1, #0x06] @ TM1CNT
	strh r0, [r1, #0x0A] @ TM2CNT
	
	@ manually store seed into the rng state and init values because
	@ the built-in seed function does not read a full 32-bits
	ldrh r0, [r1, #0x04] @ TM1D
	ldrh r1, [r1, #0x08] @ TM2D
	lsl r1, #16          @ shift TM2D to be the upper 16-bits of the seed
	orr r0, r1           @ combine TM1D and the shifted TM2D into a full 32-bits
	ldr r1, .RNG_STATE
	str r0, [r1]
	ldr r1, .TIMER_RESULT
	str r0, [r1]
	
	@@ OPTIONAL: reset rng frame counter to 0
	@@           This value isn't ever read by the game, so it's not really
	@@           necessary to reset it unless you know what you're doing.
	@@ NOTE: the built-in rng seed function seems to think
	@@       this value is at 0x020249BC, whereas the rng
	@@       advancement routine says it's at 0x020249C0. lolwut
	@ mov r0, #0
	@ ldr r1, .RNG_FRAME_COUNTER
	@ str r0, [r1]
	
	@ if "mov r0, #0" is uncommented above here, comment the one below
	mov r0, #0
	ldr r1, .MENU_INIT_CB
	bl x_r1
	pop {r0}
	bx r0

x_r1:
	bx r1

.align 2
.TIMER_REGISTER_BASE:
	.word 0x04000100
.RNG_STATE:
	.word 0x03005D80
@@.RNG_FRAME_COUNTER:
@@	.word 0x020249C0
.TIMER_RESULT:
	.word 0x02020000
.MENU_INIT_CB:
	.word 0x0802F6F4|1
Attached Files
File Type: ips Emerald 32-bit TIMER RNG Fix.ips‎ (118 Bytes, 3 views) (Save to Dropbox)
Reply With Quote
  #15    
Old 3 Weeks Ago (6:47 AM). Edited 3 Weeks Ago by MWisBest.
MWisBest MWisBest is offline
 
Join Date: Mar 2017
Gender: Male
Posts: 19
One last option I whipped up: another 32-bit seed, bottom 16-bits is timer-based, but the upper 16-bits is RTC based like HackMew's original fix.

Byte edits required:
  1. At 0x400 change 1D 48 00 24 04 70 to 00 F0 A8 F8 C0 46.
  2. At 0xAAED0 change DD F6 02 08 to XX XX XX 08, where XX XX XX is the location of the routine (EmeraldTimerPrngSeedAtMenu) +1 (e.x. if you insert it at 0x9C0D00, you'd put 01 0D 9C 08).

Code:
.text
.align 2
.thumb
.thumb_func
.global EmeraldTimerAndRTCPrngSeedAtMenu

main:
	push {lr}
	
	@ disable the timer immediately so the value remains static
	mov r0, #0x00
	ldr r1, .TIMER_REGISTER_BASE
	strh r0, [r1, #0x06] @ TM1CNT
	
	@ get the "RTC seed" into r1
	ldr r1, .GET_RTC_MINUTES
	bl x_r1
	lsr r1, r0, #16
	@ no need to chop off the upper 16-bits of r0 like the original, it's done for us later
	eor r1, r0
	
	@ get the "timer seed" into r0
	ldr r0, .TIMER_REGISTER_BASE
	ldrh r0, [r0, #0x04] @ TM1D
	
	@ make full seed in r0 (RTC seed as upper 16-bits)
	lsl r1, #16
	orr r0, r1
	
	@ manually store seed into the rng state and init values because
	@ the built-in seed function does not read a full 32-bits
	ldr r1, .RNG_STATE
	str r0, [r1]
	ldr r1, .TIMER_RESULT
	str r0, [r1]
	
	@@ OPTIONAL: reset rng frame counter to 0
	@@           This value isn't ever read by the game, so it's not really
	@@           necessary to reset it unless you know what you're doing.
	@@ NOTE: the built-in rng seed function seems to think
	@@       this value is at 0x020249BC, whereas the rng
	@@       advancement routine says it's at 0x020249C0. lolwut
	@ mov r0, #0
	@ ldr r1, .RNG_FRAME_COUNTER
	@ str r0, [r1]
	
	@ if "mov r0, #0" is uncommented above here, comment the one below
	mov r0, #0
	ldr r1, .MENU_INIT_CB
	bl x_r1
	pop {r0}
	bx r0

x_r1:
	bx r1

.align 2
.TIMER_REGISTER_BASE:
	.word 0x04000100
.RNG_STATE:
	.word 0x03005D80
@@.RNG_FRAME_COUNTER:
@@	.word 0x020249C0
.TIMER_RESULT:
	.word 0x02020000
.GET_RTC_MINUTES:
	.word 0x0802F664|1
.MENU_INIT_CB:
	.word 0x0802F6F4|1
Attached Files
File Type: ips Emerald 32-bit RTC+TIMER RNG Fix.ips‎ (99 Bytes, 5 views) (Save to Dropbox)
Reply With Quote
Reply
Quick Reply

Sponsored Links
Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -8. The time now is 8:50 AM.