forked from Ports/goldeneye-pc-port
random.c's dsll32/dsrl32 helpers modelled the real MIPS64 dsll32/dsrl32 instructions as ordinary 32-bit shift-by-n operations, masked to 32 bits. Real MIPS64 dsll32/dsrl32 shift the FULL 64-bit register by n+32 with no masking - they exist specifically to encode a 32-63 shift amount in a 5-bit immediate field. The bug was bit-exact-looking but wrong: it produced a deterministic, self-consistent stream that was never the N64's actual stream, from the very first draw. Surfaced by M-138's security/decomp-fidelity review (a forked review agent's numeric trace + a hand trace of random.s both found the same divergence); fix decided over disclose-as-known-issue per M-139b. Fix: dsll32(x,n) = x << (n+32), dsrl32(x,n) = x >> (n+32), no masking. No other line changes - every call site (randomGetNext, randomGetNextFrom, chrObjRandomGetNext) already mirrors random.s/ chrObjRandom.s line-by-line through these two helpers plus plain <</>> (which already matched dsll/dsrl correctly). Verified against a standalone C reproduction outside the game (first five draws from random.s's real initial seed diverge completely between the buggy and corrected helpers, confirming the fix actually changes the output stream). 242/242 clean build; full 21-level verify.sh sweep PASS, no crashes. This silently changes every RNG-derived sequence (loot, AI variance, anything seeded from randomGetNext/randomGetNextFrom) from the first draw in every build going forward. Savegames are unaffected (seed isn't save state); existing recorded replays will diverge against a post-fix build. Called out in v0.3.0 release notes per M-139c. Claude-Session: https://claude.ai/code/session_01KwZViAFaXua3PKgHHjNgvi