Roll RNG

󰃭 2025-03-28

Address FDBA61 contains a table of the numbers 0-FF, this is the RNG table (RNGTable). A pointer to the current RNG index is stored at 7E0026 (RNGIndex), this pointer is incremented every time a random number is generated during Battle.

This is the function that rolls the RNG:

RollRNG:
; Rolls a random value between two numbers.
; The upper limit is stored in the A register prior to calling
; The lower limit is stored in the X register prior to calling
C1AF22    SEP #$10       ; Set 8-bit index registers (X/Y)
C1AF24    STX $25        ; Store lower limit to $7E0025
C1AF26    REP #$10       ; Set 16-bit index registers (X/Y)
C1AF28    LDX $2C        ; Load X register from $7E002C
C1AF2A    PHX            ; Push X register value to stack
C1AF2B    SEP #$10       ; Set 8-bit index registers again
C1AF2D    LDX $25        ; Load lower limit from $7E0025
C1AF2F    CPX #$FF       ; Is the lower limit FF?
C1AF31    BNE $C1AF35    ; Branch if no
C1AF33    BRA $C1AF73    ; Else branch to end of function

; This is checking for a special battle event which is determined
; based on $7E2989 having bit being set.
; If the bit is set then the lower limit is returned.
C1AF35    STA $B31E      ; Store upper limit to $7EB31E
C1AF38    LDA $2989      ; Load A register from $7E2989
C1AF3B    BIT #$20       ; Test bit 5
C1AF3D    BEQ $C1AF42    ; Branch if bit 5 is clear
C1AF3F    TXA            ; Transfer X to A if bit 5 is set
C1AF40    BRA $C1AF73    ; Branch to end


; Check if the upper limit is 0, if so return 0
C1AF42    LDA $B31E      ; Load upper limit to A from $7EB31E
C1AF45    CMP #$00       ; Compare with 0
C1AF47    BEQ $C1AF73    ; Branch to end if value is 0

; If the lower limit and upper limit are equal return the upper limit
C1AF49    CMP $25        ; Compare with lower limit
C1AF4B    BEQ $C1AF73    ; Branch to end if they're equal

; Load the current RNG value
C1AF4D    LDX $RNGIndex  ; Load X with RNGIndex
; Check to see if upper_limit < lower_limit, if so return the RNG value
; directly
C1AF4F    SEC            ; Set carry flag
C1AF50    SBC $25        ; Subtract lower limit
C1AF52    CMP #$FF       ; Compare result with $FF
C1AF54    BNE $C1AF5C    ; Branch if not equal to $FF
C1AF56    LDA RNGTable,X ; Load value from RNG table at index X
C1AF5A    BRA $C1AF73    ; Branch to end

; Store the upper limit and RNG value to $2A and $28 in preparation
; for division subfunction
C1AF5C    STA $2A        ; Store upper limit - lower_limit to $2A
C1AF5E    STZ $2B        ; Store zero to $2B
C1AF60    LDA RNGTable,X ; Load A from RNG table using X as index
C1AF64    TAX            ; Transfer A to X
C1AF65    STX $28        ; Store X to $28
C1AF67    STZ $29        ; Store zero to $29

; This is a division subfunction, it divides the 2 bytes at $28
; with the two bytes at $2A and stores the remainder at $32 and result
; to $2A
C1AF69    JSR $C92A      ; Division subfunction
; A = RNG value % upper limit
; This is because the RNG table is 0-FF but the upper limit can be
; upper than FF.
C1AF6C    LDA $32        ; Load remainder from $32 (RNG value % lower limit)
C1AF6E    CLC            ; Clear carry flag
; Add the lower limit back, increment the RNG index, and restore context
C1AF6F    ADC $25        ; Add $25 to A
C1AF71    INC $RNGIndex  ; Increment RNGIndex
C1AF73    REP #$10       ; Set 16-bit index registers
C1AF75    PLX            ; Pull X from stack
C1AF76    STX $2C        ; Store X to $2C (restore context)
C1AF78    RTS            ; Return from subroutine

A modern version of this function (ignoring the special event bit) would look something like:

rng_table = [...]
rng_position = 0

def rollRNG(lower_limit, upper_limit):
    if lower_limit == 255:
        return upper_limit
    if upper_limit == 0:
        return 0
    if lower_limit == upper_limit:
        return upper_limit
    rng = rng_table[rng_position]
    if upper_limit < lower_limit:
        return rng
    temp = upper_limit - lower_limit
    rng_position += 1
    rng_position %= 256
    rng %= limit
    rng += lower_limit
    return rng 

(forgive my python, I can make it do things but it’s not a language I work in professionally)