User File #638789011495453224

Upload All User Files

#638789011495453224 - Famidash v1.2 Lucky Draw RNG analyzer

famidash_lucky_draw_analyze_starting_rng_value.lua
Game: Famidash ( NES, see all files )
2 downloads
Uploaded 2 days ago by FractalFusion (see all 88)
This script tells you, starting with an RNG value either specified or read from memory, whether Lucky Draw will eventually be successful or end in an infinite loop (modes 1&2), or alternatively whether the first attempt is successful or fails a particular check (modes 3&4).
  • mode 1: Starting with initial RNG given below, determine whether Lucky Draw will eventually be successful and on which attempt, or end up in an infinite loop and state which attempt repeats which attempt, and what the RNG value is when it repeats.
  • mode 2: Same as mode 1, but with RNG value read from memory address 0x1B (4-byte little-endian)
  • mode 3: Starting with initial RNG given below, determine whether the first attempt is successful, and if not, which of the 788 checks it fails, and the final RNG value upon death (this RNG value is the value for the next attempt).
  • mode 4: Same as mode 2, but with RNG value read from memory address 0x1B (4-byte little-endian)
console.clear()

--famidash v1.2
--This script tells you, starting with an RNG value either specified or read from memory, whether Lucky Draw will eventually be successful or end in an infinite loop (modes 1&2), or alternatively whether the first attempt is successful or fails a particular check (modes 3&4).

--mode 1: Starting with initial RNG given below, determine whether Lucky Draw will eventually be successful and on which attempt, or end up in an infinite loop and state which attempt repeats which attempt, and what the RNG value is when it repeats.
--mode 2: Same as mode 1, but with RNG value read from memory address 0x1B (4-byte little-endian)
--mode 3: Starting with initial RNG given below, determine whether the first attempt is successful, and if not, which of the 788 checks it fails, and the final RNG value upon death (this RNG value is the value for the next attempt).
--mode 4: Same as mode 2, but with RNG value read from memory address 0x1B (4-byte little-endian)

local mode=1
local initial_rng_value=0xBABF9847 --only applicable if mode is 1 or 3

--this RNG is a 32-bit linear feedback shift register (LFSR)
--also called "newrand" in the source
local function rand32(thisrng, numtimes)
	local rng=thisrng
    for i=1,(8*numtimes) do
		if rng>=0x80000000 then rng = ((rng*2)&0xFFFFFFFF)~0xC5 else rng = rng*2 end
	end
	return rng
end

--RNG may be modified by the following function (8-bit LFSR only applying to the lowest byte)
--also called "rand1" in the source
local function rand8(thisrng, numtimes)
	local lbyte=thisrng&0xFF
	for i=1,numtimes do
		if lbyte>=0x80 then lbyte=((lbyte*2)&0xFF)~0xCF else lbyte=lbyte*2 end
	end
	return ((thisrng&0xFFFFFF00)|lbyte)
end
--function combining uses of both rand32 and rand8
local function rand8rand32(thisrng, numtimesrand8, numtimeswhole)
	local rng=thisrng
	for i=1,numtimeswhole do
		rng=rand8(rng,numtimesrand8)
		rng=rand32(rng,1)
	end
	return rng
end
--check whether player survives in Lucky Draw - there are 788 such checks
local function check(rng1,rng2)
	return ((rng1&0x3F)~=(rng2&0x3F))
end

local crng_temp=0
local check_count=1
local dist=0
local crng=0
if mode==1 or mode==3 then
	crng=initial_rng_value
else
	crng=mainmemory.read_u32_le(0x1B)
end
local prev_values={}
local exitvalue=-1
local successflag=false
local i=0
console.write(string.format("Testing RNG value %08X:\n", crng))

--this is the main loop
--limited to 50000 loops, but there are no known instances of reaching 50000 without resolution, and there is not expected to be one
for i=1,50000 do
	
	if prev_values[crng] then
		exitvalue=i
		break
	end
	prev_values[crng]=i
	
	for fakeloop=1,1 do
		crng=rand32(crng,24)
		crng=rand8rand32(crng,16,2)
		crng=rand32(crng,2)
		crng=rand8rand32(crng,16,3)
		crng=rand32(crng,1) --selects random character
		crng=rand8rand32(crng,16,24)	

		--check #1
		crng_temp=rand32(crng,1)
		crng=rand32(crng_temp,1)
		if check(crng,crng_temp) then check_count=check_count+1 else
			crng=rand8(crng,16)
			break
		end
		crng=rand8rand32(crng,16,2)
		crng=rand8rand32(crng,15,3)
		crng=rand8rand32(crng,9,1)
		
		--check #2
		crng_temp=rand32(crng,1)
		crng=rand32(crng_temp,1)
		if check(crng,crng_temp) then check_count=check_count+1 else
			crng=rand8(crng,9)
			break
		end
		crng=rand8rand32(crng,9,4)

		--the following is responsible for checks #3-#786
		dist=7840
		local nextcheckdist=8448
		local get_out=false
		while dist<3219328 do
			if dist>=nextcheckdist then
				--check
				crng_temp=rand32(crng,1)
				crng=rand32(crng_temp,1)
				if check(crng,crng_temp) then
					check_count=check_count+1
					nextcheckdist=nextcheckdist+4096
				else
					get_out=true
					dist=dist+708
					break
				end	
			end
			dist=dist+708
			crng=rand32(crng,1)
		end
		if get_out then break end
		
		--now at dist 3219328
		crng=rand8rand32(crng,2,1)
		
		--check #787
		crng_temp=rand32(crng,1)
		crng=rand32(crng_temp,1)
		if check(crng,crng_temp) then check_count=check_count+1 else
			crng=rand8(crng,2)
			break
		end
		crng=rand8rand32(crng,2,4)
		crng=rand8rand32(crng,4,2)
		
		--check #788 (final)
		crng_temp=rand32(crng,1)
		crng=rand32(crng_temp,1)
		if check(crng,crng_temp) then check_count=check_count+1 else
			crng=rand8(crng,4)
			break
		end
		crng=rand8rand32(crng,4,1)

		
		successflag=true
	
	end
	
	if successflag or mode>=3 then break end

end

if successflag then
	if mode==1 or mode==2 then
		console.write(string.format("Success after %d attempts", i))
	else
		console.write("Attempt is successful")
	end
else
	if mode==1 or mode==2 then
		if exitvalue~=-1 then
			console.write(string.format("Exited due to repetition at attempt %d of attempt %d (period %d), repeated RNG value is %08X", exitvalue,prev_values[crng],exitvalue-prev_values[crng],crng))
		else
			console.write(string.format("Exited after max attempts (50000)")) --this is not expected to happen
		end
	else
		console.write(string.format("Failed at check #%d with final RNG value: %08X", check_count, crng))
	end
end