Merge remote-tracking branch 'rng64/master'

This commit is contained in:
Connor Olding 2019-08-03 07:33:13 -07:00
commit f463e58706

121
rng.md Normal file
View File

@ -0,0 +1,121 @@
# info dump on the RNG in OoT and MM
if you find any discrepancies, please
leave a comment or tweet at [@antiformant][twitter].
[twitter]: https://twitter.com/antiformant
## the function itself
the random number generator in both games is an LCG:
https://en.wikipedia.org/wiki/Linear_congruential_generator
specifically, it uses the constants from Numerical Recipes in C.
```c
/* the C code looks something like this: */
static uint32_t rng_value = 1;
uint32_t prng() {
/* note: intentional unsigned overflow. */
rng_value = rng_value * 1664525 + 1013904223;
return rng_value;
/* note: in the game, there's some code to reinterpret the value
as a floating point number, which I've omitted here. */
}
```
if you're interested, you can find the function(s) in any version by searching
for F35F in RAM. you should see a 660D nearby, usually a bit before.
you can find the rng_value variable
by looking at the disassembly of the RNG function.
note that there are a few different variations of the function
that are not commonly invoked; you can find these the same way.
here are some known addresses:
game, version | RNG value | RNG function | variants
------------- | --------- | ------------ | --------
OoT 1.0 | 80105440 | 800CDC90 | ?
OoT 1.2 | 80105A80 | 800CE4D0 | ?
MM (J) 1.1 | 8009E890 | 8008797C | 80087940
MM (U): | 80097530 | 80086FDC | ?
## the quirks
when a new scene is loaded,
the RNG value is set directly to the CPU's cycle count.
that means, depending on all the code that has been run
up to that point, the RNG value is set to a
pseudo-unpredictable value when you enter a new area.
to clarify what a "new scene" being loaded is:
* loading the title screen
* loading a save file
* entering a new area (TODO: do rooms within a scene count?)
* **not** the N64 logo being shown
* **not** the file select screen
### other invocations
creating a new file will invoke the RNG
to determine the Bomber's Code, etc.
obviously, this does not apply to OoT.
although the GameCube versions don't have an N64 logo,
they still do similar initializations before the title screen is shown.
### emulators
as far as i know, the cycle counter in emulators
(including Virtual Console, excluding CEN64)
is very roughly approximated.
it's not a critical component to emulating most games,
so emulators can skimp on it to achieve better performance.
this means RNG should be fairly consistent, given identical inputs.
*this does not mean RNG will be consistent across emulators.*
the plugins you use might affect this as well.
## exploiting the RNG
### in Ocarina of Time
because the title screen sequence starts on Hyrule Field
with a ton of actors loaded,
the RNG value is updated many times each frame.
as far as i know, you'd have to be frame perfect to reach the file select screen
with a consistent RNG, but i haven't done a lot of testing.
maybe there's a part of the title sequence
with wider gaps between RNG invocations,
giving you a wider window to enter the inputs to reach the file select screen.
this might not be exploitable anyway due to
the reset that occurs when loading scenes, as described earlier.
### in Majora's Mask
the first title screen in this game is very simple.
only a handful of actors are loaded and executing.
as a result, the RNG is only invoked
something like every 75 frames *on average.*
this is a big window to reach the file select screen.
*in theory,* you should be able mash A and Start to reach the
file select to create a file, and that file will have the same
Bomber's code, lottery codes, and Spider House mask order.
remember that "the same" is specific to each emulator,
as described earlier.
### in practice
this needs testing.
i can somewhat consistently reach the file select screen
with the same RNG value in Project64 2.2 and Bizhawk 1.12.1.
Virtual Console and N64 have not been tested.
this might be useful for the new MM 100% ruleset
if it's found to be consistent, but don't hold your breath.