(Note: This page contains only information about the "Lucky Draw" level in Famidash v1.2.nes and how randomness works. If other information is to be added, consider moving the below information to a subpage.)

Lucky Draw

Known source code files implementing random functions:

Lua script

This Lua script determines, based on an RNG value, whether Lucky Draw will eventually be successful or end in an infinite loop, or alternatively whether the first attempt is successful or fails a particular check, depending on the mode:
(See information below on how randomness works in Lucky Draw.)

_newrand

Based on the source code's _newrand function, the main pseudo-random number generator (PRNG) is a simple period 2^32-1 linear feedback shift register (LFSR) that is equivalent to the following Lua code:
local function _newrand(rng)
	for i=1,8 do
		if rng>=0x80000000 then
			-- & means bitwise AND, ~ means bitwise XOR
			rng = ((rng*2)&0xFFFFFFFF)~0xC5
		else
			rng = rng*2
		end
	end
	return rng
end
The above PRNG auto-runs once per frame in most cases, without the expectation of using this value (since, obviously, most levels in Famidash have no randomness). In rare instances, Famidash runs this function to get a random value.

rand1

In other rare instances, Famidash can also use the following function (called rand1 in the source code) to alter only the least-significant byte of the RNG (an 8-bit LFSR that only affects the least-significant byte):
local function rand1(rng)
	local lbyte=rng&0xFF
	if lbyte>=0x80 then
		-- & means bitwise AND, ~ means bitwise XOR
		lbyte=((lbyte*2)&0xFF)~0xCF
	else
		lbyte=lbyte*2
	end
	-- | means bitwise OR
	return ((rng&0xFFFFFF00)|lbyte)
end
The above function can run multiple times per frame (as well as running _newrand during the same frame), and determines the flashing effects on some objects. However, the majority of levels do not use this function.
It turns out the level Lucky Draw uses both of these functions.

How Lucky Draw determines whether an attempt is successful

When first selecting Lucky Draw, as well as after any death, the RNG address (0x1B, four byte little endian) will freeze on a particular value. As far as is known, this value is the only thing that determines whether the first/following attempt is a successful attempt. No player input that changes RNG has been found.
The following procedure determines whether an attempt is successful:
(frame 1): run _newrand x1
(frame 2): run _newrand x1
(frame 3): run _newrand x22 then rand1 x16 then _newrand x1
(frame 4): run rand1 x16 then _newrand x1
(frame 5): run _newrand x2 then rand1 x16 then _newrand x1
(frame 6&7): run rand1 x16 then _newrand x1
(frame 8): run _newrand (random player character) then rand1 x16 then _newrand x1
(frame 9-31): run rand1 x16 then _newrand x1
(frame 32): run _newrand x2.
- If RNG values are equal mod 64: run rand1 x16 then kill player.
- Otherwise: run rand1 x16 then _newrand x1 and continue.
(frame 33): run rand1 x16 then _newrand x1
(frame 34-36): run rand1 x15 then _newrand x1
(frame 37): run rand1 x9 then _newrand x1
(frame 38): run _newrand x2.
- If RNG values are equal mod 64: run rand1 x9 then kill player.
- Otherwise: run rand1 x9 then _newrand x1 and continue.
(frame 39-41): run rand1 x9 then _newrand x1

At this point, the distance is 7840. The next distance at which player survival check occurs is 8448.

Repeat the following until distance is 3219328:
{
If distance has not yet reached/exceeded the next survival check distance:
- Run _newrand then add 708 to distance.
Otherwise, if distance has reached/exceeded the next survival check distance:
- Run _newrand x2.
-- If RNG values are equal mod 64: kill player.
-- Otherwise: Run _newrand, add 4096 to get next check distance, add 708 to distance.
}

Once the distance is 3219328, the following now applies:

(frame 1): run rand1 x2 then _newrand x1
(frame 2): run _newrand x2.
- If RNG values are equal mod 64: run rand1 x2 then kill player.
- Otherwise: run rand1 x2 then _newrand x1 and continue.
(frame 3-5): run rand1 x2 then _newrand x1
(frame 6-7): run rand1 x4 then _newrand x1
(frame 8): run _newrand x2.
- If RNG values are equal mod 64: run rand1 x4 then kill player.
- Otherwise: '''Success: Player will beat the level.'''
If the attempt is unsuccessful, the RNG value when the player was killed will be the new RNG value for the next attempt.

GameResources/NES/Famidash last edited by FractalFusion 2 days ago
Page History Latest diff List referrers View Source