Skip to content

Instantly share code, notes, and snippets.

@notwa
Last active October 15, 2020 00:08
Show Gist options
  • Save notwa/7dc05f233f513f5c029c4c8e26cc692d to your computer and use it in GitHub Desktop.
Save notwa/7dc05f233f513f5c029c4c8e26cc692d to your computer and use it in GitHub Desktop.
info dump on the RNG in OoT and MM

info dump on the RNG in OoT and MM

if you find any discrepancies, please leave a comment or tweet at @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.

/* 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment