Random number generator
The routine a game calls for its rolls, producing a sequence from a formula, a fixed table, or hardware timing.
A random number generator (RNG) produces the numbers a game rolls with. The C standard defines rand as computing “a sequence of pseudo-random integers”, and srand as seeding it so that the same seed repeats the sequence1. The five games in the table use three designs: a linear congruential generator, a fixed table walked by a counter, and bytes stirred by a hardware timer.
- FormulaDragon Warrior (1986). Battle rolls come from one generator, and reading the controller stirs it too.2,3,4Yoshi's Cookie (1992). One byte stepped as 5x + 17 mod 256, so it repeats every 256 steps.5,6Golden Sun (2001). The C standard's example constants, 1103515245 and 12345, with bits 8 to 23 as the result.7Pokémon Emerald (2004). The ISO C example generator, returning the top 16 bits.8,9
- Fixed tableFinal Fantasy (1987). Battle rolls come from a fixed table, so they repeat every 256 draws.10,11,12,13,14Wolfenstein 3D (1992). One index walks a 256-byte table, the same table Doom uses, reset to 0 for demos and seeded from the clock otherwise.15,16Doom (1993). One 256-byte table walked by two indices, one for play and one for the wipe, sounds, and screens.17,18,19,20
- Hardware-stirredPokémon Red and Blue (1996). The hardware divider added to one byte and subtracted from another every frame.21,22Pokémon Crystal (2000). Red and Blue's divider-stirred generator, returning the other byte.23
- Shift registerAsteroids (1979). A 16-bit shift register stepped on each call.24
- Stepped counterMetroid (1986). A byte that steps by 25 every frame, through all 256 values.25
- ROM as tablePac-Man (1980). A pointer stepped by 5p + 1 mod 8192 reads the game's own ROM as its table.26
#How it works
A linear congruential generator (LCG) keeps a state , steps it as , and hands out its high bits. A table generator keeps an index into a fixed list of bytes. A hardware-stirred generator adds a free-running counter into its state, so each result depends on the exact moment of the call.
LCG: x = (a * x + c) mod m; return the high bits of x # Dragon Warrior, Emerald
table: i = i + 1; return TABLE[i mod 256] # Final Fantasy
hardware: s = s + timer + carry; return s # Red/Blue, Crystal
A game then scales the number to the range it needs. Final Fantasy’s RandAX maps a byte to 12. Emerald takes a remainder, as in Random() % 100 + 1 for accuracy27. Red and Blue compare the byte with a threshold directly28.
| Design | State | Output | Varied by | |
|---|---|---|---|---|
| Dragon Warrior | LCG, 2 | 16 bits2 | the high byte2 | every call, including each controller read3 |
| Final Fantasy | 256-byte tables10,13 | an 8-bit index per stream10,14 | the table’s byte10 | calls only10 |
| Red and Blue | hardware-stirred21 | 2 bytes21 | hRandomAdd21 | the divider at each call; a call every frame21 |
| Crystal | hardware-stirred23 | 2 bytes23 | hRandomSub23 | the divider at each call; a call every frame23 |
| Emerald | LCG, 8 | 32 bits8 | the top 16 bits8 | a timer seed at the player’s naming screen; a call every frame9 |
#Implementations
#Dragon Warrior
UpdateRandNum steps a 16-bit state as 2, and battle code reads its high byte2. The 65,536 states split into two cycles of 32,7684, and over each cycle every high byte appears exactly 128 times4. Because the high byte is uniform, a probe that runs a routine once for every state measures its exact odds; the atlas measured Dragon Warrior’s run and damage routines that way4,29.
The controller routine steps the generator on every read3. Ryan8bit’s guide adds that an idle menu runs it 60 times a second, so a command’s outcome depends on when it is chosen3.
#Final Fantasy
Final Fantasy uses tables, not a formula. BattleRNG returns the next byte of a 256-byte table, indexed by a counter that wraps, so battle draws repeat every 256 calls10. That table holds $00 twice and never $9511. Disch’s comment assumes the table is a permutation, and the doubled $00 shows in the ROM: one swing at crit chance 1 crits 4 times in 256 rather than 311,30.
A second table, lut_RNG, holds every byte once13. BattleStepRNG walks it for encounter checks, reversing direction on some passes, and a battle counter indexes it to pick formations14,31. Over a full pass of 256 draws, each rate set against these tables is therefore exact13,31.
#Pokémon Red and Blue
Random_ adds the hardware divider register rDIV to hRandomAdd with carry and subtracts it from hRandomSub with borrow21. The VBlank handler calls it once a frame, and Random returns hRandomAdd21. The divider counts on its own, so the bytes depend on the exact cycle of each call as well as on the frame count21. A wild encounter reads both bytes directly, one to decide the fight and the other to pick the slot32,33.
In a link battle, BattleRandom instead reads the first 9 bytes of a 10-byte list that both Game Boys hold, then regenerates them as 22.
#Pokémon Crystal
Crystal keeps the generator but returns hRandomSub, and pret’s comment gives the divider’s rate as 16,384 Hz23. The link-battle list carries over23.
#Pokémon Emerald
Emerald’s Random is a 32-bit LCG, 8, returning the top 16 bits8. pret’s comment traces the multiplier to the C standard’s example rand8. That example steps 34, so Emerald keeps the multiplier and changes the increment34,8.
The retail game seeds the generator only when the player’s naming screen closes; the clock-based seed at power-on is compiled only into pret’s BUGFIX build9. After loading a save the state starts from 0, and the VBlank handler steps it once a frame9. Every session therefore walks the same sequence from the same start; only the number of steps before a roll changes its result9.
Pokémon FireRed and LeafGreen roll wild encounters on a generator of their own, , seeded at a new game35. Its increment is the C standard example’s, where Emerald’s Random uses 2469134,8.
#Consequences
The whole state is a few bytes, and every roll follows from it. Where input timing steps the generator, as in Dragon Warrior, a player’s timing picks the outcome3. Where the state starts from a fixed value, as in Emerald after a load, the player’s timing picks a place in a known sequence9.
#History
Games
| Game | Year | How | Note |
|---|---|---|---|
| Dragon Warrior | 1986 | Formula | battle rolls come from one generator, and reading the controller stirs it too |
| Yoshi's Cookie | 1992 | Formula | one byte stepped as 5x + 17 mod 256, so it repeats every 256 steps |
| Golden Sun | 2001 | Formula | the C standard's example constants, 1103515245 and 12345, with bits 8 to 23 as the result |
| Pokémon Emerald | 2004 | Formula | the ISO C example generator, returning the top 16 bits |
| Final Fantasy | 1987 | Fixed table | battle rolls come from a fixed table, so they repeat every 256 draws |
| Wolfenstein 3D | 1992 | Fixed table | one index walks a 256-byte table, the same table Doom uses, reset to 0 for demos and seeded from the clock otherwise |
| Doom | 1993 | Fixed table | one 256-byte table walked by two indices, one for play and one for the wipe, sounds, and screens |
| Pokémon Red and Blue | 1996 | Hardware-stirred | the hardware divider added to one byte and subtracted from another every frame |
| Pokémon Crystal | 2000 | Hardware-stirred | Red and Blue's divider-stirred generator, returning the other byte |
| Asteroids | 1979 | Shift register | a 16-bit shift register stepped on each call |
| Metroid | 1986 | Stepped counter | a byte that steps by 25 every frame, through all 256 values |
| Pac-Man | 1980 | ROM as table | a pointer stepped by 5p + 1 mod 8192 reads the game's own ROM as its table |
Every claim about this mechanic, by game (37)
References
- ^The C standard defines
randas computing "a sequence of pseudo-random integers", andsrandas starting a new sequence from a seed, so that the same seed repeats the same sequence.PublisherC99 draft N1256How we know
The rand function computes a sequence of pseudo-random integers in the range 0 to RAND_MAX.
§7.20.2.1, p. 312 · archived copy ↗ If srand is then called with the same seed value, the sequence of pseudo-random numbers shall be repeated.
§7.20.2.2, p. 312 · archived copy ↗ Checked against the evidence by its author, an AI model, 2026-10-20.
Checked by a second AI model, 2026-10-27.
- ^ abcdef
UpdateRandNumsteps a 16-bit state as , and battle code reads its high byte,RandNumUB.Codenmikstas/dragon-warrior-disassembly · Ryan8bit, DW FormulasHow we know
668UpdateRandNum: ⋮ 673LC563: ASL RandNumLB ; 674LC565: ROL RandNumUB ; ⋮ 687LC57C: ADC #$81 ;
source_files/Bank03.asm lines 668–692 at ebe6a13 · upstream ↗ $9495 = $9495 * 771 + 0x81
III.A, Common algorithms · archived copy ↗ Checked against the evidence by its author, an AI model, 2026-10-20.
Checked by a second AI model, 2026-10-21.
- ^ abcde
GetJoypadStatussteps the generator each time it reads the controller.Codenmikstas/dragon-warrior-disassembly · Ryan8bit, DW FormulasHow we know
805GetJoypadStatus: ⋮ 807LC60A: PHA ;Prepare to update the random number by first saving registers ⋮ 811LC60E: JSR UpdateRandNum ;($C55B)Get random number.
source_files/Bank03.asm lines 805–811 at ebe6a13 · upstream ↗ If you sit by idly while waiting to make a command, the random generator is run 60 times per second.
IV, Frequently Asked Questions · archived copy ↗ Checked against the evidence by its author, an AI model, 2026-10-20.
Checked by a second AI model, 2026-10-21.
- ^ abcdComputed from the generator's update, its 65,536 states form two cycles of 32,768, and over each cycle the high byte takes every value exactly 128 times.Codenmikstas/dragon-warrior-disassembly · Ryan8bit, DW Formulasrevised
How we know
ASL RandNumLB ROL RandNumUB CLC ADC RandNumLB … ADC #$81
source_files/Bank03.asm#L668-L692 · upstream ↗ This makes 32,768 possibilities.
III.A, Common algorithms · archived copy ↗ Measured by a script in MesenCE 2.2.1 (build 4b8a196), on . It fails if the result disagrees with the claim.
Checked against the evidence by its author, an AI model, 2026-10-25.
Checked by a second AI model, 2026-10-21.
Revised after a check by a second AI model, 2026-10-25.
- ^Yoshi's Cookie keeps its random number generator in one byte,
$0424, and steps it as , written out in place at each call site, so the sequence runs through all 256 values before it repeats.Verified“Yoshi's Cookie (USA)”How we know
In the cartridge (“Yoshi's Cookie (USA)”): fixed bank $C923-$C938, the setup menu's step: lda $0424, asl, asl, clc, adc $0424, clc, adc #$11, sta $0424, then a far call to the menu itself; bank 2 $9FA4-$9FE3, the same step in the kind picker. We don't reproduce the bytes.
Measured by a script in MesenCE 2.2.1 (build 4b8a196), on Yoshi's Cookie (USA) (SHA-1
b19b67e59dd6…). It fails if the result disagrees with the claim.The numbers come from the run; its author, an AI model, checked the script measures what the claim says, 2026-10-25.
Checked by a second AI model, 2026-10-25.
- ^The power-on code sets the generator to
$C3.Verified“Yoshi's Cookie (USA)”How we know
In the cartridge (“Yoshi's Cookie (USA)”): fixed bank $C0E4: lda #$C3, sta $0424. We don't reproduce the bytes.
Measured by a script in MesenCE 2.2.1 (build 4b8a196), on Yoshi's Cookie (USA) (SHA-1
b19b67e59dd6…). It fails if the result disagrees with the claim.The numbers come from the run; its author, an AI model, checked the script measures what the claim says, 2026-10-25.
Checked by a second AI model, 2026-10-25.
- ^Golden Sun's
RPGRandomis a linear congruential generator, (0x41C64E6D and 0x3039; the statesRPGRNGStateis a 32-bit unsigned int on the GBA), returningstate >> 8as an unsigned short: bits 8 to 23 of the state.RPGRandom2scales one result to 0 to 99, as RPGRandom × 100 >> 16 (computed). These are the constants of the C standard's examplerand, which returns bits 16 to 30 instead. Pokémon Emerald'sRandomkeeps the multiplier but adds 24691 and returns the top 16 bits; pret'srandom.hdefines a second step,ISO_RANDOMIZE2, with Golden Sun's 12345.CodeCoaltergeist/goldensun-decomp · C99 draft N1256 · pret/pokeemeraldHow we know
3extern unsigned int sRPGRNGState; ⋮ 5unsigned short RPGRandom(void) { 6 unsigned int state = sRPGRNGState * 0x41c64e6d + 0x3039; 7 sRPGRNGState = state; 8 return state >> 8; ⋮ 12unsigned short RPGRandom2(void) { 13 extern int RPGRandom_i(void) __asm__("RPGRandom"); 14 return RPGRandom_i() * 0x64 >> 16;
src/rpg/random.c lines 3–15 at 2e5c504 · upstream ↗ next = next * 1103515245 + 12345; return (unsigned int)(next/65536) % 32768;
§7.20.2.2 ¶5, p. 312 · archived copy ↗ 11u16 Random(void) ⋮ 13 gRngValue = ISO_RANDOMIZE1(gRngValue); 14 sRandCount++; 15 return gRngValue >> 16;
src/random.c lines 11–16 at 731ad5b · upstream ↗ 14// The number 1103515245 comes from the example implementation of rand and srand 15// in the ISO C standard. 16#define ISO_RANDOMIZE1(val) (1103515245 * (val) + 24691) 17#define ISO_RANDOMIZE2(val) (1103515245 * (val) + 12345)
include/random.h lines 14–17 at 731ad5b · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-22.
Checked by a second AI model, 2026-10-27.
- ^ abcdefghiEmerald's
Randomis a linear congruential generator, , returning the top 16 bits; pret's comment traces the multiplier to the examplerandin the ISO C standard.Codepret/pokeemeraldHow we know
8COMMON_DATA u32 gRngValue = 0; ⋮ 11u16 Random(void) ⋮ 13 gRngValue = ISO_RANDOMIZE1(gRngValue); 14 sRandCount++; 15 return gRngValue >> 16;
src/random.c lines 8–16 at 731ad5b · upstream ↗ 14// The number 1103515245 comes from the example implementation of rand and srand 15// in the ISO C standard. 16#define ISO_RANDOMIZE1(val) (1103515245 * (val) + 24691) 17#define ISO_RANDOMIZE2(val) (1103515245 * (val) + 12345)
include/random.h lines 14–17 at 731ad5b · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-20.
Checked by a second AI model, 2026-10-21.
- ^ abcdefEmerald seeds
Randomfrom a hardware timer only when the player's naming screen closes, which also sets the trainer ID; the seeding from the real-time clock at power-on is compiled only into pret's BUGFIX build, so after loading a save the generator starts from 0, and the VBlank handler steps it once a frame outside link, Frontier, and recorded battles.Codepret/pokeemeraldHow we know
108#ifdef BUGFIX 109 SeedRngWithRtc(); // see comment at SeedRngWithRtc definition below
src/main.c lines 108–110 at 731ad5b · upstream ↗ 208void SeedRngAndSetTrainerId(void) ⋮ 210 u16 val = REG_TM1CNT_L; 211 SeedRng(val); ⋮ 228// FRLG commented this out to remove RTC, however Emerald didn't undo this! 229#ifdef BUGFIX
src/main.c lines 208–236 at 731ad5b · upstream ↗ 365 if (!gMain.inBattle || !(gBattleTypeFlags & (BATTLE_TYPE_LINK | BATTLE_TYPE_FRONTIER | BATTLE_TYPE_RECORDED))) 366 Random();
src/main.c lines 365–366 at 731ad5b · upstream ↗ 700 if (sNamingScreen->templateNum == NAMING_SCREEN_PLAYER) 701 SeedRngAndSetTrainerId();
src/naming_screen.c lines 700–701 at 731ad5b · upstream ↗ 8COMMON_DATA u32 gRngValue = 0;src/random.c line 8 at 731ad5b · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-20.
Checked by a second AI model, 2026-10-21.
- ^ abcdef
BattleRNGreturns the next byte of a 256-byte table, indexed by a counter (btl_rngstate) that wraps, so battle draws repeat every 256 calls.CodeDisch, FF1 disassemblyHow we know
13817BattleRNG: 13818 LDX btl_rngstate 13819 INC btl_rngstate 13820 LDA @Scramble_lut, X 13821 RTS
Final Fantasy Disassembly/bank_0F.asm lines 13817–13824 at cbb87d3 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-20.
Checked by a second AI model, 2026-10-21.
- ^ abc
BattleRNG's table holds$00twice and never$95, so a battle draw is never$95.Code“Final Fantasy (USA)” · Disch, FF1 disassemblyHow we know
In the cartridge (“Final Fantasy (USA)”): bank $0F $FCF1-$FDF0, the table; `$00` sits at positions 97 and 110. We don't reproduce the bytes.
13811;; IMPORTANT NOTE!!!! ChaosDeath in bank B assumes that calling this routine 256 times consecutively will ⋮ 13823 @Scramble_lut: 13824 .INCBIN "bin/0F_FCF1_rngtable.bin"
Final Fantasy Disassembly/bank_0F.asm lines 13811–13824 at cbb87d3 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-20.
Checked by a second AI model, 2026-10-21.
- ^ ab
RandAXscales a table byte into a range: .CodeDisch, FF1 disassemblyHow we know
5893 TXA ⋮ 5895 SBC $68AF ; subtract to get the range. ⋮ 5898 JSR BattleRNG_L 5899 LDX $68B6 5900 JSR MultiplyXA ; random()*range ⋮ 5902 TXA ; drop the low 8 bits, put high 8 bits in A (effectively: divide by 256)
Final Fantasy Disassembly/bank_0C.asm lines 5888–5905 at cbb87d3 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-20.
Checked by a second AI model, 2026-10-21.
- ^ abcd
lut_RNG, the 256-byte table at$F100, holds every byte from$00to$FFexactly once.Code“Final Fantasy (USA)” · Disch, FF1 disassemblyHow we know
In the cartridge (“Final Fantasy (USA)”): bank $0F $F100-$F1FF, lut_RNG. We don't reproduce the bytes.
11326;; RNG scrambling lookup table [$F100 :: 0x3F110] ⋮ 11328;; This table is $100 bytes in size, and simply consists of every number ⋮ 11333lut_RNG: 11334 .INCBIN "bin/0F_F100_rngtable.bin"
Final Fantasy Disassembly/bank_0F.asm lines 11326–11334 at cbb87d3 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-20.
Checked by a second AI model, 2026-10-21.
- ^ abc
BattleStepRNGreturnslut_RNG[i]for a counter that steps by 1 per call; each time it wraps to 0, a sign byte gains$A0, and its top bit sets the direction of the next pass.CodeDisch, FF1 disassemblyHow we know
1315;; Random numbers are generated by stepping through a RNG LUT. Once it 1316;; cycles through the entire LUT, it cycles through it again -- potentially 1317;; in a reversed direction. Which direction it's going depends on battlestep_sign. ⋮ 1323BattleStepRNG: 1324 BIT battlestep_sign ; see if sign indicates a decrement 1325 BMI @Negative ⋮ 1339 ADC #$A0 1340 STA battlestep_sign ⋮ 1343 LDX battlestep ; put battlestep in X 1344 LDA lut_RNG, X ; use it to get a random number from the LUT
Final Fantasy Disassembly/bank_0F.asm lines 1315–1345 at cbb87d3 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-20.
Checked by a second AI model, 2026-10-21.
- ^Wolfenstein 3D's random numbers come from
rndtable, a fixed table of 256 bytes:US_RndTadds 1 to one index, wraps it at 256, and returns that entry, and the file's comment calls it "John Carmack's table driven pseudo-random number generator".SetupGameLevelsets the index to 0 for each level of a demo being played or recorded, and otherwise to the low byte of DX from DOS's get-time call (int 21h, function 2Ch), the hundredths of a second, 0 to 99 (the atlas's reading of the DOS call).Codeid-Software/wolf3dHow we know
4; Assembly portion of the User Mgr. This is just John Carmack's table 5; driven pseudo-random number generator, and we put it in the User Mgr 6; because we couldn't figure out where it should go
WOLFSRC/ID_US_A.ASM lines 4–6 at 0516778 · upstream ↗ 19rndtable db 0, 8, 109, 220, 222, 241, 149, 107, 75, 248, 254, 140, 16, 66WOLFSRC/ID_US_A.ASM line 19 at 0516778 · upstream ↗ 60 mov ax,[randomize] 61 or ax,ax 62 jne @@timeit ;if randomize is true, really random ⋮ 64 mov dx,0 ;set to a definite value 65 jmp @@setit ⋮ 67@@timeit: 68 mov ah,2ch 69 int 21h ;GetSystemTime 70 and dx,0ffh ⋮ 72@@setit: 73 mov [es:rndindex],dx
WOLFSRC/ID_US_A.ASM lines 60–73 at 0516778 · upstream ↗ 85PROC US_RndT 86 public US_RndT ⋮ 88 mov ax,SEG rndtable 89 mov es,ax 90 mov bx,[es:rndindex] 91 inc bx 92 and bx,0ffh 93 mov [es:rndindex],bx 94 mov al,[es:rndtable+BX] 95 xor ah,ah 96 ret
WOLFSRC/ID_US_A.ASM lines 85–96 at 0516778 · upstream ↗ 642 if (demoplayback || demorecord) 643 US_InitRndT (false); 644 else
WOLFSRC/WL_GAME.C lines 641–644 at 0516778 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-22.
Checked by a second AI model, 2026-10-22.
- ^Doom's
rndtableholds the same 256 values in the same order as Wolfenstein 3D's (compared entry by entry, computed); Doom walks it with two indices (prndindexforP_Random,rndindexforM_Random), where Wolfenstein 3D uses one (rndindex).Codeid-Software/wolf3d · id-Software/DOOMHow we know
19rndtable db 0, 8, 109, 220, 222, 241, 149, 107, 75, 248, 254, 140, 16, 66 20 db 74, 21, 211, 47, 80, 242, 154, 27, 205, 128, 161, 89, 77, 36
WOLFSRC/ID_US_A.ASM lines 19–20 at 0516778 · upstream ↗ 37 db 120, 163, 236, 249WOLFSRC/ID_US_A.ASM line 37 at 0516778 · upstream ↗ 17rndindex dw ?WOLFSRC/ID_US_A.ASM line 17 at 0516778 · upstream ↗ 31unsigned char rndtable[256] = { 32 0, 8, 109, 220, 222, 241, 149, 107, 75, 248, 254, 140, 16, 66 , 33 74, 21, 211, 47, 80, 242, 154, 27, 205, 128, 161, 89, 77, 36 ,
linuxdoom-1.10/m_random.c lines 31–33 at a77dfb9 · upstream ↗ 50 120, 163, 236, 249linuxdoom-1.10/m_random.c lines 50–51 at a77dfb9 · upstream ↗ 53int rndindex = 0; 54int prndindex = 0; ⋮ 56// Which one is deterministic? 57int P_Random (void) ⋮ 59 prndindex = (prndindex+1)&0xff; 60 return rndtable[prndindex]; ⋮ 63int M_Random (void) ⋮ 65 rndindex = (rndindex+1)&0xff; 66 return rndtable[rndindex];
linuxdoom-1.10/m_random.c lines 53–67 at a77dfb9 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-22.
Checked by a second AI model, 2026-10-22.
- ^Doom's random numbers come from
rndtable, a fixed table of 256 bytes, walked by two indices: each call toP_RandomorM_Randomadds 1 to its own index, wraps it at 256, and returns that table entry.Codeid-Software/DOOMHow we know
31unsigned char rndtable[256] = { 32 0, 8, 109, 220, 222, 241, 149, 107, 75, 248, 254, 140, 16, 66 ,
linuxdoom-1.10/m_random.c lines 31–32 at a77dfb9 · upstream ↗ 53int rndindex = 0; 54int prndindex = 0; ⋮ 56// Which one is deterministic? 57int P_Random (void) ⋮ 59 prndindex = (prndindex+1)&0xff; 60 return rndtable[prndindex]; ⋮ 63int M_Random (void) ⋮ 65 rndindex = (rndindex+1)&0xff; 66 return rndtable[rndindex];
linuxdoom-1.10/m_random.c lines 53–67 at a77dfb9 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-21.
Checked by a second AI model, 2026-10-21.
- ^Doom's play code (weapon damage, aim spread, pain) rolls
P_Random, andM_Randomserves the rest: the screen wipe, sound pitch, intermission animations, and the status bar.Codeid-Software/DOOMHow we know
633 damage = 5*(P_Random ()%3+1); 634 angle = mo->angle; ⋮ 637 angle += (P_Random()-P_Random())<<18;
linuxdoom-1.10/p_pspr.c lines 633–637 at a77dfb9 · upstream ↗ 894 if ( (P_Random () < target->info->painchance)linuxdoom-1.10/p_inter.c line 894 at a77dfb9 · upstream ↗ 159 y[0] = -(M_Random()%16);linuxdoom-1.10/f_wipe.c line 159 at a77dfb9 · upstream ↗ 326 // hacks to vary the sfx pitches ⋮ 330 pitch += 8 - (M_Random()&15);
linuxdoom-1.10/s_sound.c lines 326–330 at a77dfb9 · upstream ↗ 523 a->nexttic = bcnt + 1 + (M_Random()%a->period);linuxdoom-1.10/wi_stuff.c line 523 at a77dfb9 · upstream ↗ 992 st_randomnumber = M_Random();linuxdoom-1.10/st_stuff.c line 992 at a77dfb9 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-21.
Checked by a second AI model, 2026-10-21.
- ^
G_InitNewresets both of Doom's random indices to 0, and it runs when a new game starts, when a saved game loads, when a demo starts playing, and when the command line starts a game directly (a warp or autostart, or a net game).Codeid-Software/DOOMrevisedHow we know
69void M_ClearRandom (void) ⋮ 71 rndindex = prndindex = 0;
linuxdoom-1.10/m_random.c lines 69–72 at a77dfb9 · upstream ↗ 1414 M_ClearRandom ();linuxdoom-1.10/g_game.c line 1414 at a77dfb9 · upstream ↗ 1345void G_DoNewGame (void) ⋮ 1356 G_InitNew (d_skill, d_episode, d_map);
linuxdoom-1.10/g_game.c lines 1345–1356 at a77dfb9 · upstream ↗ 1226 // load a base level 1227 G_InitNew (gameskill, gameepisode, gamemap);
linuxdoom-1.10/g_game.c lines 1226–1227 at a77dfb9 · upstream ↗ 1613 // don't spend a lot of time in loadlevel 1614 precache = false; 1615 G_InitNew (skill, episode, map);
linuxdoom-1.10/g_game.c lines 1613–1615 at a77dfb9 · upstream ↗ 1161 if ( gameaction != ga_loadgame ) ⋮ 1163 if (autostart || netgame) 1164 G_InitNew (startskill, startepisode, startmap);
linuxdoom-1.10/d_main.c lines 1161–1164 at a77dfb9 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-21.
Revised after a check by a second AI model, 2026-10-21.
- ^Doom's
rndtableis not a permutation: its 256 entries hold 166 distinct values, 101 of them once, 45 twice, 16 three times, 3 four times, and 1 five times; the value 145 appears 5 times and the value 0 twice.Codeid-Software/DOOMrevisedHow we know
31unsigned char rndtable[256] = { ⋮ 50 120, 163, 236, 249
linuxdoom-1.10/m_random.c lines 31–51 at a77dfb9 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-21.
Revised after a check by a second AI model, 2026-10-21.
- ^ abcdefgh
Random_adds the hardware divider registerrDIVto the bytehRandomAddwith carry and subtracts it fromhRandomSubwith borrow; the VBlank handler calls it every frame, andRandomreturnshRandomAdd.Codepret/pokeredHow we know
1Random_:: 2; Generate a random 16-bit value. 3 ldh a, [rDIV] 4 ld b, a 5 ldh a, [hRandomAdd] 6 adc b 7 ldh [hRandomAdd], a 8 ldh a, [rDIV] 9 ld b, a 10 ldh a, [hRandomSub] 11 sbc b 12 ldh [hRandomSub], a
engine/math/random.asm lines 1–13 at af51989 · upstream ↗ 1Random:: 2; Return a random number in a. 3; For battles, use BattleRandom. ⋮ 7 farcall Random_ 8 ldh a, [hRandomAdd]
home/random.asm lines 1–8 at af51989 · upstream ↗ 37 call Randomhome/vblank.asm line 37 at af51989 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-20.
Checked by a second AI model, 2026-10-21.
- ^ ab
BattleRandomcallsRandomoutside link battles; in a link battle both Game Boys read the first 9 bytes of a shared 10-byte list in turn, and after the ninth read those 9 are each replaced by ; the tenth byte is never read.Codepret/pokeredrevisedHow we know
6543BattleRandom: 6544; Link battles use a shared PRNG. ⋮ 6546 ld a, [wLinkState] 6547 cp LINK_STATE_BATTLING 6548 jp nz, Random ⋮ 6557 inc a ⋮ 6572; if we picked the last seed, we need to recalculate the nine seeds ⋮ 6586; multiply by 5 6587 add a 6588 add a 6589 add c 6590; add 1 ⋮
engine/battle/core.asm lines 6543–6599 at af51989 · upstream ↗ 19DEF SERIAL_RNS_LENGTH EQU 10constants/serial_constants.asm line 19 at af51989 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-20.
Revised after a check by a second AI model, 2026-10-21: The link RNG uses only 9 of its 10 bytes.
- ^ abcdefgCrystal's
Randomis Red and Blue's generator, adding the divider register (with carry) tohRandomAddand subtracting it (with borrow) fromhRandomSub, but it returnshRandomSubwhere Red and Blue'sRandomreturnshRandomAdd; pret's comment says the divider counts at 16,384 Hz.Codepret/pokecrystal · pret/pokeredHow we know
1Random:: ⋮ 7; The divider is a register that increments at a rate of 16384Hz. ⋮ 16 ldh a, [rDIV] 17 ld b, a 18 ldh a, [hRandomAdd] 19 adc b 20 ldh [hRandomAdd], a ⋮ 22 ldh a, [rDIV] 23 ld b, a 24 ldh a, [hRandomSub] 25 sbc b 26 ldh [hRandomSub], a ⋮
home/random.asm lines 1–29 at 97187cd · upstream ↗ 1Random_:: ⋮ 3 ldh a, [rDIV] 4 ld b, a 5 ldh a, [hRandomAdd] 6 adc b 7 ldh [hRandomAdd], a 8 ldh a, [rDIV] 9 ld b, a 10 ldh a, [hRandomSub] 11 sbc b 12 ldh [hRandomSub], a 13 ret
engine/math/random.asm lines 1–13 at af51989 · upstream ↗ 1Random:: ⋮ 7 farcall Random_ 8 ldh a, [hRandomAdd]
home/random.asm lines 1–12 at af51989 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-25.
Checked by a second AI model, 2026-10-21.
Checked by a second AI model, 2026-10-25.
- ^Asteroids' random routine (77B5) shifts a 16-bit register left one bit and sets the new low bit to the old bit 14 exclusive-or the old bit 0, turning an all-zero register into 1; it returns the low byte.CodeComputer Archeology, Asteroids
How we know
ASL $5F ; {ram.rndValue} ROL $60 ; {ram.$60} BPL $77BD ; {} INC $5F ; {ram.rndValue} LDA $5F ; {ram.rndValue} BIT $77D1 ; {} BEQ $77C8 ; {} EOR #$01 STA $5F ; {ram.rndValue} ORA $60 ; {ram.$60} BNE $77CE ; {} INC $5F ; {ram.rndValue} …
content/Arcade/Asteroids/Code.md#L1977-L1991 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-22.
Checked by a second AI model, 2026-10-22.
- ^The main loop calls
RandomNumbersonce per frame, after the frame's work; it adds 5 toRandomNumber1five times, 25 in all, so the byte steps through all 256 values every 256 frames.Codenmikstas/metroid-disassembly · “Metroid (USA)”How we know
34RandomNumbers: ⋮ 37LC002: LDX #$05 ; 38LC004:* LDA RandomNumber1 ; 39LC006: CLC ; 40LC007: ADC #$05 ; 41LC009: STA RandomNumber1 ;2E is increased by #$19 every frame and ⋮ 46LC012: DEX ; 47LC013: BNE - ;
Source_Files/Bank07.asm lines 34–47 at 4270d57 · upstream ↗ 170WaitNMIEnd: ⋮ 176LC0D3:* JSR RandomNumbers ;($C000)Update pseudo random numbers. 177LC0D6: JMP MainLoop ;($C0BC)Jump to top of subroutine.
Source_Files/Bank07.asm lines 170–177 at 4270d57 · upstream ↗ In the cartridge (“Metroid (USA)”): bank 7 $C000. We don't reproduce the bytes.
Checked against the evidence by its author, an AI model, 2026-10-20.
Checked by a second AI model, 2026-10-21.
- ^A frightened ghost picks a random direction from
random_2a23, which steps a pointer as and returns the byte at that address, so the game's own first 8 KB of ROM serve as the random table. The direction is the low 2 bits; a reversal or a wall sends it on to try the next one.Codemburkley/pacman-crevisedHow we know
12227/* Generates a random number by reading a byte from a randomised ROM address ⋮ 12246 RND_VAL_PTR = (RND_VAL_PTR * 5 + 1) & 0x1fff; 12247 return MEM[RND_VAL_PTR];
pacman.c lines 12227–12247 at 3277e56 · upstream ↗ 11905XYPOS randomDirection_291e (XYPOS hl, uint8_t *orientation) ⋮ 11921 BEST_ORIENTATION_FOUND = random_2a23() & 3; ⋮ 11942 /* Prohibit ghosts from doing u-turns */ ⋮ 11952 /* Ensure this direction is not into a wall */ ⋮ 11980 BEST_ORIENTATION_FOUND = (BEST_ORIENTATION_FOUND + 1) & 3;
pacman.c lines 11905–11980 at 3277e56 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-21.
Revised after a check by a second AI model, 2026-10-21.
- ^
Cmd_accuracycheckcombines the attacker's accuracy stage and the target's evasion stage into one stage, multiplies the move's accuracy in percent by that stage's ratio, and misses when a roll from 1 to 100 exceeds the result, so a 100% move at even stages never misses.Codepret/pokeemeraldHow we know
1128 if (gBattleMons[gBattlerTarget].status2 & STATUS2_FORESIGHT) ⋮ 1136 buff = acc + DEFAULT_STAT_STAGE - gBattleMons[gBattlerTarget].statStages[STAT_EVASION]; ⋮ 1149 calc = sAccuracyStageRatios[buff].dividend * moveAcc; 1150 calc /= sAccuracyStageRatios[buff].divisor; ⋮ 1175 // final calculation 1176 if ((Random() % 100 + 1) > calc)
src/battle_script_commands.c lines 1128–1176 at 731ad5b · upstream ↗ 588static const struct StatFractions sAccuracyStageRatios[] = ⋮ 590 { 33, 100}, // -6 ⋮ 596 { 1, 1}, // 0 ⋮ 602 { 3, 1}, // +6
src/battle_script_commands.c lines 588–603 at 731ad5b · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-20.
Checked by a second AI model, 2026-10-21.
- ^
MoveHitTestlands a move when a random byte is below its accuracy byte, so even a 100% move misses 1 time in 256.Codepret/pokeredHow we know
5322; if the random number generated is greater than or equal to the scaled accuracy, the move misses 5323; note that this means that even the highest accuracy is still just a 255/256 chance, not 100% 5324 call BattleRandom 5325 cp b 5326 jr nc, .moveMissed
engine/battle/core.asm lines 5321–5327 at af51989 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-20.
Checked by a second AI model, 2026-10-21.
- ^Measured in the ROM over all 65,536 generator states, with Agility 40 against a defense byte of 40, the hero escapes 87.70% of the time from the first group, 81.64% from the second, 75.20% from the third, and 50.20% from the fourth; the hero takes the first turn 87.70% of the time.Verified“Dragon Warrior (USA) (Rev 1)” · nmikstas/dragon-warrior-disassembly
How we know
In the cartridge (“Dragon Warrior (USA) (Rev 1)”): bank 3 $EE91-$EEFC, TryRun through CalcNextOdds, the code the probe calls. We don't reproduce the bytes.
LDA RandNumUB AND #$7F … LDA EnBaseDef … JSR WordMultiply … LDA DisplayedAgi … SBC GenWord42LB LDA MultRsltUB SBC GenWord42UB
source_files/Bank03.asm#L8256-L8325 · upstream ↗ Measured by a script in MesenCE 2.2.1 (build 4b8a196), on Dragon Warrior (USA) (Rev 1) (SHA-1
66809063b828…). It fails if the result disagrees with the claim.The numbers come from the run; its author, an AI model, checked the script measures what the claim says, 2026-10-25.
Checked by a second AI model, 2026-10-21.
Checked by a second AI model, 2026-10-25.
- ^Measured in the ROM over all 256 battle-RNG states, one swing with base damage 20, hit rate 10, and crit chance 1 against evade 6 and absorb 4 hits 221 times and is critical 4 times; with the attacker in Dark it hits 170 times, and against a sleeping defender 216 times.Verified“Final Fantasy (USA)” · Disch, FF1 disassembly
How we know
In the cartridge (“Final Fantasy (USA)”): bank $0C $A68C-$A8D3, the math of DoPhysicalAttack the probe runs, skipping the animation at $A775-$A7C8. We don't reproduce the bytes.
4310 STA math_hitchance ⋮ 4319 AND #AIL_DARK 4320 BEQ :+ 4321 LDA math_hitchance 4322 SEC 4323 SBC #40 4324 STA math_hitchance ⋮ 4327 AND #AIL_DARK 4328 BEQ :+ 4329 LDA math_hitchance ⋮ 4332 STA math_hitchance ⋮ 4364 AND #AIL_STUN | AIL_SLEEP ⋮
Final Fantasy Disassembly/bank_0C.asm lines 4307–4591 at cbb87d3 · upstream ↗ Measured by a script in MesenCE 2.2.1 (build 4b8a196), on Final Fantasy (USA) (SHA-1
e8f34d935760…). It fails if the result disagrees with the claim.The numbers come from the run; its author, an AI model, checked the script measures what the claim says, 2026-10-25.
Checked by a second AI model, 2026-10-21.
Checked by a second AI model, 2026-10-25.
- ^ ab
GetBattleFormationpicks one of the area's 8 formations by indexinglut_RNGwith a counter that rises by 1 per battle; the low 6 bits select formations 0–3 with 12 chances in 64 each, 4 and 5 with 6, 6 with 3, and 7 with 1.CodeDisch, FF1 disassemblyHow we know
1293 INC battlecounter ; increment the battle counter 1294 LDX battlecounter ; and put it in X 1295 LDA lut_RNG, X ; use it as seed to get a random number ⋮ 1297 AND #$3F ; drop the 2 high bits of the random number 1298 TAX ; and put in X 1299 LDY lut_FormationWeight, X ; use that to index the formation weight LUT to know which formation to use
Final Fantasy Disassembly/bank_0F.asm lines 1293–1299 at cbb87d3 · upstream ↗ 1357lut_FormationWeight: 1358 .BYTE 0,0,0,0,0,0, 0,0,0,0,0,0 ; 12/64 chance of formation 0 ⋮ 1365 .BYTE 7 ; 1/64
Final Fantasy Disassembly/bank_0F.asm lines 1357–1365 at cbb87d3 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-20.
Checked by a second AI model, 2026-10-21.
- ^On each step in grass or water,
TryDoWildEncounterstarts a wild battle when the bytehRandomAddis below the map's encounter rate, out of 256; Route 1's grass rate is 25.Codepret/pokeredHow we know
26; determine if wild pokemon can appear in the half-block we're standing in ⋮ 32 ld a, [wGrassRate] 33 jr z, .CanEncounter ⋮ 37 jr z, .CanEncounter ⋮ 47 ld a, [wGrassRate] 48.CanEncounter 49; compare encounter chance with a random number to determine if there will be an encounter 50 ld b, a 51 ldh a, [hRandomAdd] 52 cp b 53 jr nc, .CantEncounter2
engine/battle/wild_encounters.asm lines 26–53 at af51989 · upstream ↗ 1Route1WildMons: 2 def_grass_wildmons 25 ; encounter rate
data/wild/maps/Route1.asm lines 1–2 at af51989 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-20.
Checked by a second AI model, 2026-10-21.
- ^The byte
hRandomSubthen picks one of the map's 10 slots, which have 51, 51, 39, 25, 25, 25, 13, 13, 11, and 3 chances in 256.Codepret/pokeredHow we know
54 ldh a, [hRandomSub] 55 ld b, a 56 ld hl, WildMonEncounterSlotChances
engine/battle/wild_encounters.asm lines 54–62 at af51989 · upstream ↗ 17 wild_chance 51 ; 51/256 = 19.9% chance of slot 0 ⋮ 26 wild_chance 3 ; 3/256 = 1.2% chance of slot 9
data/wild/probabilities.asm lines 11–28 at af51989 · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-20.
Checked by a second AI model, 2026-10-21.
- ^ abcdThe standard's example
randsteps and returns .PublisherC99 draft N1256How we know
next = next * 1103515245 + 12345; return (unsigned int)(next/65536) % 32768;
§7.20.2.2 ¶5, p. 312 · archived copy ↗ Checked against the evidence by its author, an AI model, 2026-10-20.
Checked by a second AI model, 2026-10-27.
- ^FireRed and LeafGreen roll encounters on their own generator, , seeded at a new game; a check passes when its value mod 1,600 is below 16 times the area's rate, cut to 80% on a bike, plus 16/200 of a buff to which every failed check adds the area's rate, reset by a battle or a Repel.Codepret/pokefireredrevised
How we know
20#define MAX_ENCOUNTER_RATE 1600src/wild_encounter.c line 20 at ce6406d · upstream ↗ 304 if (WildEncounterRandom() % MAX_ENCOUNTER_RATE < encounterRate) ⋮ 311 encounterRate *= 16; 312 if (TestPlayerAvatarFlags(PLAYER_AVATAR_FLAG_MACH_BIKE | PLAYER_AVATAR_FLAG_ACRO_BIKE)) 313 encounterRate = encounterRate * 80 / 100; 314 encounterRate += sWildEncounterData.encounterRateBuff * 16 / 200;
src/wild_encounter.c lines 302–314 at ce6406d · upstream ↗ 372 if (DoWildEncounterRateTest(gWildMonHeaders[headerId].landMonsInfo->encounterRate, FALSE) != TRUE) ⋮ 374 AddToWildEncounterRateBuff(gWildMonHeaders[headerId].landMonsInfo->encounterRate);
src/wild_encounter.c lines 372–374 at ce6406d · upstream ↗ 667static u16 WildEncounterRandom(void) ⋮ 669 sWildEncounterData.rngState = ISO_RANDOMIZE2(sWildEncounterData.rngState); 670 return sWildEncounterData.rngState >> 16;
src/wild_encounter.c lines 667–671 at ce6406d · upstream ↗ 18#define RAND_MULT 1103515245 ⋮ 20#define ISO_RANDOMIZE2(val)(RAND_MULT * (val) + 12345)
include/random.h lines 18–20 at ce6406d · upstream ↗ 778static void AddToWildEncounterRateBuff(u8 encounterRate) ⋮ 780 if (VarGet(VAR_REPEL_STEP_COUNT) == 0) 781 sWildEncounterData.encounterRateBuff += encounterRate; 782 else 783 sWildEncounterData.encounterRateBuff = 0;
src/wild_encounter.c lines 778–784 at ce6406d · upstream ↗ 103 SeedWildEncounterRng(Random());src/new_game.c line 103 at ce6406d · upstream ↗ Checked against the evidence by its author, an AI model, 2026-10-21.
Revised after a check by a second AI model, 2026-10-21.
Sources
Code
- Disch. 2019. “Final Fantasy Disassembly.” Commit cbb87d3. BenWenger/FinalFantasyDisassembly @ cbb87d3 · licence, all uses
- pret contributors. 2026. “pokeemerald: decompilation of Pokémon Emerald.” pret. Commit 731ad5b. pret/pokeemerald @ 731ad5b · licence, all uses
- pret contributors. 2026. “pokered: disassembly of Pokémon Red and Blue.” pret. Commit af51989. pret/pokered @ af51989 · licence, all uses
- nmikstas. 2023. “dragon-warrior-disassembly: NES Dragon Warrior software disassembly.” Commit ebe6a13. nmikstas/dragon-warrior-disassembly @ ebe6a13 · licence, all uses
- 1990. “Final Fantasy (USA).” · licence, all uses
- pret contributors. 2026. “pokecrystal: disassembly of Pokémon Crystal.” pret. Commit 97187cd. pret/pokecrystal @ 97187cd · licence, all uses
- 1989. “Dragon Warrior (USA) (Rev 1).” · licence, all uses
- pret contributors. 2026. “pokefirered: decompilation of Pokémon FireRed and LeafGreen.” pret. Commit ce6406d. pret/pokefirered @ ce6406d · licence, all uses
Primary
- JTC1/SC22/WG14, ISO/IEC. 2007. “ISO/IEC 9899:TC3, Committee Draft WG14/N1256 (C99 with Technical Corrigenda 1–3).” ISO/IEC JTC1/SC22/WG14. original · archived · licence, all uses
Secondary
- Ryan8bit. 2011. “Dragon Warrior (NES) Formulas.” GameFAQs. v1.0. original · archived · licence, all uses