To be paired with this movie. The piece sequence is hard-coded in the script, eliminating the need to brute-force the RNG.
pieceMap = "ZSLJTOI" -- Represents values 0-6
pieces =
{
"ZITLJOS",
"OZSITLJ",
"SITZJOL",
"TJOLIZS",
"JIOTZSL",
"SZOILJT",
"OJTLZSI",
"STILOZJ",
"JZLOTSI",
"ZILJOTS",
"LSJOZIT",
"OISZJLT",
"TZSIOLJ",
"IOJTZSL",
"TLISZJO",
"ZOJLSIT",
"SLJITOZ",
"JTILZSO",
"LZOSJIT",
"LSOITJZ",
"IZLTOSJ",
"JITSOLZ",
"LZJOSIT",
"ZLIJSTO",
"LJIOTSZ",
"TSZIOLJ",
"JSZTOIL",
"JLSIOTZ",
"SLOJZIT",
"OTJZSLI",
"JOZSITL",
"ZSOLTJI",
"ZOTILSJ",
"ZSTOJLI",
"ISTZOJL",
"ZJSILOT",
"LZISJTO",
"ILJSZOT",
"JOZLTSI",
"SIZOJLT",
"ZOTJSLI",
"JTOZSLI",
"ISLZTJO",
"LTIOJSZ",
"LTIOSZJ",
"OZISTLJ",
"IOJZSTL",
"ZTILJSO",
"ITZOSLJ",
"SLIOJZT",
"JSLZTOI",
"LTJISZO",
"IZTJSOL",
"JSTZIOL",
"LSTJOZI",
"JZISOLT",
"LSTJIOZ",
"LJIOZST",
"IOSJLZT",
"ZISTJLO",
"JOZILTS",
"ITJLSOZ",
"TLJZSIO",
"JSLZTIO",
"TLOJISZ",
"ILOTZSJ",
"IJLZTSO",
"SOZLIJT",
"JOTLISZ",
"IOJLSZT",
"IOTZJLS",
"OITZSJL",
"OZISTJL"
}
totalBags = 73 -- 1 bag = 7 unique pieces
pieceLandedLastFrame = false
currentBag = 1
currentBagIndex = 7
holdPiece = 255 -- Unsigned masterrace
nextHoldPiece = 255
currentPieces = pieces[1] -- All currently visible pieces, besides hold
INDICATOR_ADDRESS = 0x021C453C -- This address is 0 right before the game starts
PIECE_IDLE_FRAMES_ADDRESS = 0x0217DD30 -- Increments every frame a piece is in play
CURRENT_PIECE_ADDRESS = 0x0217DD1C
NEXT_PIECE_ADDRESS = 0x0217DD24
NEXT_PIECES_QUEUE = 0x0217DDA9 -- Includes the 5 pieces after the next piece
HOLD_PIECE_ADDRESS = 0x0217DD2C
PIECE_STATUS_ADDRESS = 0x0217DD32 -- Hard drop = 4, clearing lines = 3, lowering lines above cleared lines = 6
function getPieceNumberFromString(pieceString)
return (string.find(pieceMap, pieceString) - 1)
end
function fillCurrentBagWithPieceArray(pieceArray, holdPieceValue)
if( holdPiece == 255 ) then -- Stupid way to tell if it is really early in the game
memory.writebyte( CURRENT_PIECE_ADDRESS, getPieceNumberFromString( pieceArray[1] ) )
memory.writebyte( NEXT_PIECE_ADDRESS, getPieceNumberFromString( pieceArray[2] ) )
memory.writebyte( HOLD_PIECE_ADDRESS, holdPieceValue )
end
for a = 3, 7 do
memory.writebyte( NEXT_PIECES_QUEUE + a - 3, getPieceNumberFromString( pieceArray[a] ) )
end
end
function getPieceArrayFromBag(bagString)
pieceArray = {}
for a = 1, 7 do
pieceArray[a] = string.sub(bagString, a, a)
end
return pieceArray
end
function cycleCurrentPieces()
_G.currentBagIndex = currentBagIndex + 1
if currentBagIndex == 8 then
_G.currentBag = currentBag + 1
if currentBag > totalBags then -- Overflow protection
_G.currentBag = 1
end
_G.currentBagIndex = 1
end
_G.currentPieces = string.sub(currentPieces, 2, -1) .. string.sub(pieces[ currentBag ], currentBagIndex, currentBagIndex)
end
function holdCurrentPiece()
if(pieceLandedLastFrame == 1) then
indexToTakeHoldFrom = 2;
else
indexToTakeHoldFrom = 1
end
_G.nextHoldPiece = getPieceNumberFromString( string.sub(_G.currentPieces, indexToTakeHoldFrom, indexToTakeHoldFrom) )
if holdPiece == 255 then
cycleCurrentPieces()
else
if(pieceLandedLastFrame == 1) then
_G.currentPieces = string.sub(currentPieces, 1, 1) .. string.sub(pieceMap, holdPiece + 1, holdPiece + 1) .. string.sub(currentPieces, 3, -1)
else
_G.currentPieces = string.sub(pieceMap, holdPiece + 1, holdPiece + 1) .. string.sub(currentPieces, 2, -1)
end
end
_G.holdPiece = nextHoldPiece
end
function thereWasAHardDrop()
return memory.readbyte( PIECE_STATUS_ADDRESS ) == 4
end
function thereWasAHold()
return joypad.get()["L"] or joypad.get()["R"]
end
function tetrisCoreLogic()
if thereWasAHold() then
holdCurrentPiece()
end
if thereWasAHardDrop() and not pieceLandedLastFrame then -- Wait 1 frame before cycling pieces
_G.pieceLandedLastFrame = true
elseif pieceLandedLastFrame then
_G.pieceLandedLastFrame = thereWasAHardDrop() -- In the case of a hold + hard drop right after a tetris, PIECE_STATUS_ADDRESS can equal 4 for two consecutive frames
cycleCurrentPieces()
end
end
function resetEngine()
_G.pieceLandedLastFrame = false
_G.currentBag = 1
_G.currentBagIndex = 7
_G.holdPiece = 255
_G.nextHoldPiece = 255
_G.currentPieces = pieces[currentBag]
end
function inMarathonMode()
return memory.readbyte( PIECE_IDLE_FRAMES_ADDRESS ) ~= 0x80 and emu.framecount() > 232 -- PIECE_IDLE_FRAMES_ADDRESS starts to equal 0x80 at frame 232
end
function updateBag()
fillCurrentBagWithPieceArray( getPieceArrayFromBag( currentPieces ), holdPiece)
end
emu.registerbefore(
function ()
if inMarathonMode() then
if memory.readword( INDICATOR_ADDRESS ) == 0 then
resetEngine()
else
tetrisCoreLogic()
end
updateBag()
end
end
)