Did a little digging and will do an initial WIP to get the hang and see how this game works...
some useful memory addresses
7F0016,2s,coin total
7F0018,2s,coins displayed
7E0070,2s,zone loading
7E0090,2s,zone index
7E0402,2s,player state
7E0408,2s,X
7E040C,2s,Y
7E0410,2s,Z
7E0413,1s,X velocity
7E0415,1s,Y velocity
7E0417,1s,Z velocity
7E041B,1s,X speed
7E046E,1s,dash left
7E04Ca,1s,dash stance left
7F0030,2s,Yacko dead
7F0032,2s,Wacko dead
7F0034,2s,Dot dead
7E1D02,1s,slot 1 result
7E1D12,1s,slot 2 result
7E1D22,1s,slot 3 result
7E1D08,1s,slot 1 time left
7E1D18,1s,slot 2 time left
7E1D28,1s,slot 3 time left
7E1D32,1s,slots state
7E1D38,2u,slots seed
7E003A,2u,frame counter
7F001A,1s,spins left
slots 1,2 and 3 can have the following valid values, all others mean nothing (using a cheat to set it to anything else will only make it spin some more):
0 = Yacko
2 = Wacko
4 = Dot
6 = Ralph
8 = Pinky
10 = Brain
12 = Brown Squirrel
14 = Chicken
16 = Nurse
18 = CEO
20 = Grey Squirrel
So the following values are result combinations:
00 02 04 = Regain every Warner sibling captured.
06 06 06 = Lose all of your coins.
08 08 08 = Lose 10 coins.
10 10 10 = Lose half of your coins.
12 12 12 = Receive 20 coins.
14 14 14 = Double the amount of coins you have.
16 16 16 = Be invincible for a brief time.
18 18 18 = Receive a Continue.
20 20 20 = Receive 50 coins.
note how 666 is the worst combo :P
Using a GameShark cheat to set these three slots to something useful will indeed make the game think that that combo was rolled (so it's not just a resulting value)
slots state assumes the values 0, 2, 4, 6, 8, 10, 12
with what i believe to have the following meanings
0 = nothing is happening
2 = slots are started, this is where/when the result is determined
4 = spinning
6 = slots are stopped
8 = slots standing still
10 = results being processed (locking this to 10 will re-apply the result over and over)
12 = result screen
7E1D38,2u and 7E003A,2u together form the seed for the slot machine, locking them both will endlessly produce the same spin
7E003A,2u is simply a frame counter (loops on overflow) that continues during an in-game pause.
7E1D38,2u is determined by the value of the frame counter and is only set when a new spin is started (slots state==2)
now i need to figure out how these 2 values determine the results
other useful data is welcome as well ofcourse
edit: Much against my personal preference, I might do this run in Snes9x v1.43 simply because I think I can write some LUA scripts that will help a great deal in manipulating the slot machine
So far I found two ways to manipulate the slot-machine both based on the same principle
1) One can choose to stop the currently spinning round prematurely, thus the frame on which the next one will start is different, thus the frameCounter will be different, thus the result will be (or, can be) different. Unfortunately, one is not completely free to choose on which frame the next one start, quick tests indicate that one can only choose between 4 options (more research needed)
2) In pause mode one can wait for a more favorable slot-result (since the frameCounter changes). Pausing costs at least 2 frames (more if you need to wait longer for the wanted result)
edit2: Ok I was wrong, if you have 1 (or more) spin queued for after your current spin... its very easy to manipulate what will come up next (not sure yet how easy it will be to make sure its something we want)
the 'time left' values for slots 1, 2 and 3 start at 32, 64 and 76 respectively. By pressing L, the value on the lowest non-zero counter is subtracted from all three values. The result is evaluated a fixed amount of frames after all timers hit 0
edit3:
with kind regards to nitrodon whos figured out the disassembled ROM:D great work
<Nitrodon> ok... here's the routine
<Nitrodon> 50% of the time, simply randomize all 3 reels
<Nitrodon> the other 50% of the time:
<Nitrodon> randomly choose a good result
<Nitrodon> if the timer meets some conditions (strictest for 6 6 6, always for 0 2 4), keep that result
<Nitrodon> otherwise, re-randomize all 3 reels if the timer meets a different condition
<Nitrodon> otherwise, re-randomize all 3 reels 75% of the time
<Nitrodon> otherwise rig the slots against you
<Nitrodon> and then, when it checks to see if you got something, it rigs the slots against you if that result is impossible
<Nitrodon> 10 10 10, 16 16 16, and 18 18 18 are less likely to be rigged in your favor than 8 8 8, 12 12 12, 14 14 14
<Nitrodon> 20 20 20 is also in the "more likely" category
Nitro managed to fully explain the RNG... my hero :D now its available a LUA version :)
next step is writing it to tell me when to press 'L' (or how long to pause).. as soon as i have some spare time :(
FRAMECOUNT_ADDRESS = 0x7E003A
RNG_ADDRESS = 0x7E1D38
local frameCounter,RN
--[[
code for bit_and(m,n) goes here
]]--
function randomize()
originalHigh = (RN >= 32768)
RN = RN * 3
if (originalHigh) then RN = RN + 1 end
RN = RN * 257
RN=RN % 65536
RN = RN + 129
if (RN >= 65536) then RN = RN - 65535 end
RN = RN + frameCounter
RN = RN % 65536
end
function assignReel()
randomize()
RNmod16 = RN % 16
if (RNmod16 <= 10) then
return RNmod16 * 2
end
RN256mod16 = math.floor(RN/256) % 16
if (RN256mod16 <= 10) then
return RN256mod16 * 2
end
timerMod8 = frameCounter % 8
if (timerMod8 == 7) then timerMod8 = 3 end
return (RN256mod16 - 5 - timerMod8) * 2
end
riggedReels = {{0,2,4},{6,6,6},{8,8,8},{10,10,10},{12,12,12},{14,14,14},{16,16,16},{18,18,18},{20,20,20}}
riggedReelConditions = {0x00, 0xFF, 0x10, 0x30, 0x10, 0x10, 0x30, 0x30, 0x10}
function spin()
randomize()
if (RN % 2 == 1) then
return assignReel(), assignReel(), assignReel()
else
randomize()
cappedRN = RN % 256
rigIndex = 0
if (cappedRN <= 31) then rigIndex = 1
elseif (cappedRN <= 39) then rigIndex = 2
elseif (cappedRN <= 71) then rigIndex = 3
elseif (cappedRN <= 103) then rigIndex = 4
elseif (cappedRN <= 135) then rigIndex = 5
elseif (cappedRN <= 167) then rigIndex = 6
elseif (cappedRN <= 199) then rigIndex = 7
elseif (cappedRN <223>0) then
return assignReel(), assignReel(), assignReel()
end
reels = riggedReels[rigIndex]
return reels[1], reels[2], (reels[3]+2)%22
end
end
while true do
frameCounter = memory.readword(FRAMECOUNT_ADDRESS) + 1
RN = memory.readword(RNG_ADDRESS)
initialRN = RN
r1, r2, r3 = spin()
snes9x.message(frameCounter..","..initialRN.." exp:"..RN..", with "..r1..","..r2..","..r3)
snes9x.frameadvance()
end
the code gets messed up by some process in the TASvids code :P
here's the full stuff:
http://lua.pastey.net/96769-38zw