Load chunks from ROM in Sonic 1
From Sonic Retro
(Original guide by FraGag)
In Sonic 1, the chunks (metatiles) are larger than in the sequels: 256x256 instead of 128x128. This makes them take up a lot more space and there is a limit to how much you can put in RAM. The game limits itself to $52 chunks (plus one empty chunk), and this takes up more than half of the RAM already. If you were to have $80 chunks, you would take up the whole RAM! If you desperately need more than $52 chunks, you can load them from ROM directly. However, the chunks data is usually compressed in the ROM, so to use the chunks data from ROM, you will need to store them uncompressed, which takes a lot more space (6 KB to 10 KB compressed, compared to at least 41 KB uncompressed — 512 bytes per chunk).
This guide will allow you to continue using chunks loaded to RAM for some zones, while also allowing chunks to be read from ROM for other zones.
Contents
Using the uncompressed chunk mappings
Since the game normally stores compressed data, we need to change it to store uncompressed data instead. For example, for Green Hill Zone, replace this:
Blk256_GHZ: incbin map256\ghz.bin
even
with this:
Blk256_GHZ: incbin map256_u\ghz.bin
even
Note that if you're using SonED2 you'll have to change this.
Metatile Compression: 1
Change it to 0.
chunkcmp=Uncompressedbefore the first level's section. If you only want to change specific levels, add that line in the sections for each act of the level(s).
Then replace each instance of "chunks=../map256/" with "chunks=../map256_u/" in each level you want to load chunks from ROM.
Skipping loading chunks to RAM (title screen)
If you decide to read the chunks from ROM for Green Hill Zone and you still use the Green Hill Zone data for your title screen, you should skip decompressing the chunks to avoid overwriting other data in RAM. Go to Title_LoadText and find the following lines:
lea (Blk256_GHZ).l,a0 ; load GHZ 256x256 mappings
lea ($FF0000).l,a1
bsr.w KosDec
Comment them out or delete them.
Skipping loading chunks to RAM (levels and ending sequence)
In MainLoadBlockLoad, the chunks data, amongst others, is decompressed to RAM. We are going to disable this. Find the following lines:
lea ($FF0000).l,a1 ; RAM address for 256x256 mappings
bsr.w KosDec
and replace them with the following:
tst.b ($FFFFFE10).w ; are we in Green Hill Zone?
beq.s @no_dec ; if yes, branch
cmpi.b #6,($FFFFFE10).w ; are we in the ending sequence?
beq.s @no_dec ; if yes, branch
lea ($FF0000).l,a1 ; RAM address for 256x256 mappings
bsr.w KosDec
@no_dec:
Fixing art
The chunks are composed of blocks, which contain art tiles. Since the chunks are not in RAM anymore, you will get empty levels. Go to sub_6BD6 (loc_712C if you followed this guide) and replace the code from
moveq #-1,d3
to
rts
with the following:
tst.b ($FFFFFE10).w ; are we in Green Hill Zone?
beq.s @ghz ; if yes, branch
cmpi.b #6,($FFFFFE10).w ; are we in the ending sequence?
beq.s @ghz ; if yes, branch
moveq #-1,d3 ; load chunks from RAM
bsr.s LocateBlock
bra.s @continue
@ghz:
moveq #0,d3
bsr.s LocateBlock
add.l #Blk256_GHZ,d3
@continue:
movea.l d3,a0
move.w (a0),d3
andi.w #$3FF,d3
lsl.w #3,d3
adda.w d3,a1
rts
; ---------------------------------------------------------------------------
LocateBlock:
move.b (a4,d0.w),d3 ; load chunk ID in d3
beq.s LocateBlock_EmptyChunk
subq.b #1,d3
andi.w #$7F,d3 ; '?'
ror.w #7,d3
add.w d4,d4
andi.w #$1E0,d4
andi.w #$1E,d5
add.w d4,d3
add.w d5,d3
rts
; ---------------------------------------------------------------------------
LocateBlock_EmptyChunk:
addq.w #4,sp ; pop a stack frame to leave a1 pointing at the first tile
rts
Fixing collision
The chunks also contain collision information, so now we need to tell the game that the data is loaded elsewhere. Find the Floor_ChkTile subroutine and replace it with the following code:
Floor_ChkTile_LocateBlock:
lea ($FFFFA400).w,a1
move.b (a1,d0.w),d1
beq.s Floor_ChkTile_EmptyChunk ; if the chunk ID is 0 (empty chunk), branch
bmi.s loc_1499A
subq.b #1,d1 ; the empty chunk is not included in the chunk mappings, subtract 1 to read the correct data
ext.w d1
ror.w #7,d1
move.w d2,d0
add.w d0,d0
andi.w #$1E0,d0
add.w d0,d1
move.w d3,d0
lsr.w #3,d0
andi.w #$1E,d0
add.w d0,d1
rts
; ---------------------------------------------------------------------------
loc_1499A:
andi.w #$7F,d1
btst #6,1(a0)
beq.s loc_149B2
addq.w #1,d1
cmpi.w #$29,d1
bne.s loc_149B2
move.w #$51,d1
loc_149B2:
subq.b #1,d1
ror.w #7,d1
move.w d2,d0
add.w d0,d0
andi.w #$1E0,d0
add.w d0,d1
move.w d3,d0
lsr.w #3,d0
andi.w #$1E,d0
add.w d0,d1
rts
; ---------------------------------------------------------------------------
Floor_ChkTile_EmptyChunk:
lea ($FFFFFF00).w,a1 ; override a1
addq.w #4,sp ; pop a stack frame to avoid adding the address of the chunk mappings to a1
rts
; ---------------------------------------------------------------------------
; Subroutine to find which tile the object is standing on
; ---------------------------------------------------------------------------
; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||
Floor_ChkTile: ; XREF: FindFloor; et al
move.w d2,d0
lsr.w #1,d0
andi.w #$380,d0
move.w d3,d1
lsr.w #8,d1
andi.w #$7F,d1
add.w d1,d0
tst.b ($FFFFFE10).w ; are we in Green Hill Zone?
beq.s @ghz ; if yes, branch
cmpi.b #6,($FFFFFE10).w ; are we in the ending sequence?
beq.s @ghz ; if yes, branch
moveq #-1,d1
bsr.w Floor_ChkTile_LocateBlock
movea.l d1,a1
rts
; ---------------------------------------------------------------------------
@ghz:
moveq #0,d1
bsr.w Floor_ChkTile_LocateBlock
add.l #Blk256_GHZ,d1
movea.l d1,a1
rts
; End of function Floor_ChkTile
|Load chunks from ROM in Sonic 1]]