Neither S1 nor S3K have a "dirty" screen flag, so what the camhack does there is make a savestate, set the camera values to one screen above/left of the target position, then invisibly emulate the number of frames required to scroll down/right onto the target (advancing the camera position by 16 pixels each frame), emulate one frame visibly, then load that savestate without redrawing the screen.
As for S3K's specialized method of getting tile addresses, it's fairly simple once you understand it. There's a table of 16-bit pointers to the start of each row, starting at FF8008, and alternating foreground and background.
So, to get a specific foreground tile
- Take its row number (Y/128), multiplied by 4 (so really just take Y/32)
- Read the short pointer at 0xFF8008 + that number
- Sign extend the short pointer (>= 0x8000 -> >= 0xFFFF8000, <= 7FFF -> <= 0x00007FFF)
- Add its column number (X/128) to the pointer
or, in lua change the beginning of work_tiles to
function get_tileS1S2(X, Y)
return addr_levellayout + ((Y * level_rowlength) * 2) + X
end
function get_tileS3SK(X, Y)
local rowpoint, tilenum
Y = AND(Y*4,memory.readword(0xFFEEAE)) --optional, for correct behavior when outside normal level height bounds
rowpoint = memory.readword(addr_levellayout + Y + 8)
if rowpoint > 0x7FFF then
rowpoint = OR(rowpoint,0xFF0000)
end
tilenum = rowpoint + X
return tilenum
end
function work_tiles(xcamera, ycamera)
local xtile1, ytile1, tilepos, tilenum, x1, y1, x2, y2, get_tile
if game == "s3sk" then
get_tile = get_tileS3SK
else
get_tile = get_tileS1S2
end
xtile1 = math.floor((xcamera + xmouse) / level_tilesize)
ytile1 = math.floor((ycamera + ymouse) / level_tilesize)
tilepos = get_tile(xtile1,ytile1)
tilenum = memory.readbyte(tilepos)