Advertisement
Guest User

NSMB RNG

a guest
Feb 1st, 2023
138
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 4.49 KB | None | 0 0
  1. -- Author: Suuper
  2.  
  3. -- Set how many changes the script will check up to.
  4. local maxChanges = 10000
  5. local rngAddress = 0x088A68
  6.  
  7. local initialValue = mainmemory.read_u32_le(rngAddress)
  8. local initialFrame = emu.framecount()
  9.  
  10. local lastValue = initialValue
  11. local totalChanges = 0
  12.  
  13. print("Watching RNG, starting frame: " .. initialFrame)
  14.  
  15. function hex(v)
  16.     return string.format("%x", v)
  17. end
  18.  
  19. function RNGStep(iRNG)
  20.     -- This forumla gives correct results:
  21.     -- u54 a = (u64)0x0019660D * iRNG + 0x3C6EF35F
  22.     -- return (a + (a >> 32)) & 0xffffffff
  23.     -- However, Lua does not have 64-bit integers.
  24.     -- We will work around this problem by turning the values to be
  25.     -- multiplied into 2-digit base-0x10000 numbers and multiplying those
  26.     -- digits manually.
  27.     local aVal = 0x3C6EF35F
  28.     local mHigh = 0x0019
  29.     local mLow  = 0x660D
  30.     -- Note that (a >> 32) is the same thing as reading the high 4 bytes
  31.     -- as a u32: *(((u32*)a) + 1). We use this fact to avoid creating large -- numbers that might lose integer precision.
  32.        
  33.     local rngHigh = math.floor(iRNG / 0x10000)
  34.     local rngLow = iRNG % 0x10000
  35.      
  36.     local low = rngLow * mLow
  37.     -- lowHigh is guaranteed to fit within 32 bits because mLow + mHigh
  38.     -- is less than 0x10000
  39.     local lowHigh = rngHigh * mLow + mHigh * rngLow -- * 0x10000
  40.     local high = rngHigh * mHigh -- * 0x100000000
  41.     -- Instead of multiplying lowHigh and high, we get the bytes that would
  42.     -- end up as the high 32 bits of a u64 directly.
  43.     local u64High = math.floor(lowHigh / 0x10000) + high
  44.     local u64Low = (lowHigh % 0x10000) * 0x10000 + low + aVal
  45.     if u64Low > 0xffffffff then -- this may happen, because +aVal
  46.         u64High = u64High + 1
  47.         -- We mod 0x100000000 later, so changing u64Low isn't necessary.
  48.         -- u64Low = u64Low - 0x100000000
  49.     end
  50.    
  51.     return (u64Low + u64High) % 0x100000000
  52. end
  53.  
  54. function watch()
  55.     local rng = mainmemory.read_u32_le(rngAddress)
  56.  
  57.     local changesThisFrame = 0
  58.     while rng ~= lastValue and changesThisFrame < maxChanges do
  59.         -- Advance one step
  60.         lastValue = RNGStep(lastValue)
  61.         changesThisFrame = changesThisFrame + 1
  62.     end
  63.    
  64.     -- Make sure the values match. (We might have hit maxChanges)
  65.     if (rng ~= lastValue) then
  66.         -- Or, we might have loaded a savestate.
  67.         local rewindedChanges = checkRewind(rng)
  68.         if (rewindedChanges == -1) then
  69.             print("RNG did not advance as expected. Restting at frame " .. emu.framecount() .. ".")
  70.             -- Reset counter
  71.             totalChanges = 1
  72.             changesThisFrame = -1
  73.             initialValue = rng
  74.             initialFrame = emu.framecount()
  75.             --print("Watching RNG, starting frame: " .. initialFrame)
  76.         else
  77.             print("RNG set back.")
  78.             changesThisFrame = rewindedChanges - totalChanges
  79.         end
  80.     end
  81.    
  82.     -- Set up for next frame
  83.     totalChanges = totalChanges + changesThisFrame
  84.     lastValue = rng
  85.    
  86.      -- Print if there was change
  87.     if changesThisFrame ~= 0 then
  88.         print("Total RNG steps: " .. totalChanges .. ", this frame: " .. changesThisFrame)
  89.     end
  90.        
  91. end
  92.  
  93. -- If the RNG didn't advance as expected, check if it went backwards.
  94. -- This is probably due to a savestate. In this case, we don't want
  95. -- to reset the counter to 0, we want to go back to that frame's state.
  96. function checkRewind(newRngValue)
  97.     local rng = initialValue
  98.     local changes = 0
  99.     while rng ~= newRngValue and changes < totalChanges do
  100.         rng = RNGStep(rng)
  101.         changes = changes + 1
  102.     end
  103.    
  104.     if (rng == newRngValue) then
  105.         return changes
  106.     else
  107.         return -1
  108.     end
  109. end
  110.  
  111. -- Please don't use this in conjuction with the watch function.
  112. function manualAdvance()
  113.     local inputs = joypad.getimmediate();
  114.     if (inputs.B) then
  115.         local rng = mainmemory.read_u32_le(rngAddress);
  116.         rng = RNGStep(rng);
  117.         mainmemory.write_u32_le(rngAddress, rng);
  118.     end
  119. end
  120.  
  121. -- What is 5-1
  122. local changeHistory = {}
  123. local previousFrame = 0
  124. function test()
  125.     local rng = mainmemory.read_u32_le(rngAddress)
  126.  
  127.     local changesThisFrame = 0
  128.     while rng ~= lastValue and changesThisFrame < maxChanges do
  129.         -- Advance one step
  130.         lastValue = RNGStep(lastValue)
  131.         changesThisFrame = changesThisFrame + 1
  132.     end
  133.    
  134.     -- Change history tracking
  135.     local fnum = emu.framecount()
  136.     if fnum == previousFrame + 1 then
  137.         if changeHistory[fnum] ~= changesThisFrame then
  138.             if changesThisFrame ~= 0 or changeHistory[fnum] ~= nil then
  139.                 print("Frame " .. fnum .. ": " .. changesThisFrame)
  140.             end
  141.             changeHistory[fnum] = changesThisFrame
  142.         end
  143.     end
  144.    
  145.     -- Set up for next frame
  146.     lastValue = rng
  147.     previousFrame = fnum
  148. end
  149. --test()
  150.  
  151. while true do
  152.     -- manualAdvance();
  153.     watch();
  154.     -- test()
  155.  
  156.     emu.frameadvance();
  157. end
  158.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement