You getting bored of better performance at the cost of space? Let's try something different this time.
Here, we'll be porting Sonic 2's layout format and loader to Sonic 1. This doesn't save a whole lot of space (my own port reduced the total size of all REV01 level layouts from 5722 bytes to 3721), but it's a good way to familiarise yourself with the layout format and the differences between Sonic 1's and Sonic 2's. This guide will break compatibility with whatever level editors use pre-defined level layout formats. To my knowledge, the only workaround exists for SonLVL.
The theory behind it
The standard level layout setup, if you don't already know, is a simple list of chunks, arranged into rows, from left to right, following that is another row, then another, etc. This is consistent between Sonic 1 and Sonic 2.
So what is the difference between Sonic 1 and Sonic 2's layouts?
Sonic 1:
Sonic 2:
What does this mean, and why?
1.
2.
3 & 4.
5.
That's the goal here, folks. We're going to free up some ROM space by employing the Sonic 2 layout loading system in Sonic 1, and creating an S1-S2 hybrid level layout format!
Please note that this does not involve modifying Sonic 1 to use the 128x128 chunks system. This involves only the level layouts. Also note that Project Sonic 1: Two-Eight and any derivatives already use the Sonic 2 level layout format and loader.
Converting the layouts
We have two ways to go about this: either we simply copy the processed layouts from RAM, or we convert them manually in a hex editor. The former is significantly easier than the latter, it being the one I recommend.
From RAM:
By hand
Note that the ending has its own layout, be sure to convert that also.
With all of your layouts converted, compress them in Kosinski, and replace the contents of the 'levels' folder with them. Make sure that each and every one of the original files are replaced.
Porting the layout loader
The loader was totally rewritten for Sonic 2, so we'll have to port the routine over instead of tweaking Sonic 1's current one to use the new format.
The loader is known as "LevelLayoutLoad" in Sonic 1, and "loadLevelLayout" in Sonic 2. Looking at Sonic 1's you can see that it clears $FFFFA400-$FFFFA800, and then uses the FG and BG layouts to construct the real layout. Sonic 2's, on the other hand, is far more simple, being little more than an arrangement for a branch to KosDec. Humorously, you can find an S1-style loader dummied out below the used code. Said dummied out code is modified to conform to Sonic 2's rules, showing that Sonic 1's loader was still in use even after the jump to a 128x128 chunk system was made. Don't be as careless as Sonic Team with your precious ROM space, and delete (or comment out) all code from the label
to the line
and, in its place, paste this:
Converting the level layout index
Go to Level_Index. In Sonic 1, each act in the index has three entries, word-sized pointers. The first is the FG layout, the second is the BG layout, the third... you got me. It doesn't seem to be used and normally points to null data, on three exceptions does it share its pointer with the second entry. Sonic 2 has a single word-sized pointer per act, this pointer leading to the combined FG and BG. We'll convert the index to Sonic 2's format, getting rid of the always- (and recently-made-) redundant data.
Remove the second and third entry of each act's section of the index, leaving only the FG entry. You can change whatever entries that still point to null data, and have them point to a used layout, or just blank out the pointer altogether, though in the latter's case, loading that entry will lead to a crash. You are free to delete the many 'Level_XXXbg's and null 'byte_XXXXX's, saving even more room in ROM.
With that, you're done. Save and build.
But wait!
Fixing compatibility with SonLVL (credit to MainMemory for fix)
Because our layout format is not exactly Sonic 1 or Sonic 2, no level editors support it! Here are the directions for regaining compatibility with SonLVL, the only editor I'm aware of that's capable of this.
Inside your 'SonLVL INI Files' folder, create a blank file with the name "CustomLayout.cs", to keep things simple, and open it in a text editor. Inside, paste this, and save the file:
This goes all the way back to Section 4; our custom layout is almost one-for-one identical to Sonic 2's layout format, safe for three features: any editors that support Sonic 2's layout format expect the rows to be 128 bytes in length and for there to be 16 of them. This is not the case with Sonic 1's system, which has a row length of 64 and a row total of 8. Also, we're still using S1's 'looping chunk' system, which Sonic 2 lacks. Here, these parameters are changed to reflect this, while otherwise treating the layouts as Sonic 2's.
With CustomLayout.cs done, create a new .ini file with the name SonLVL.user.ini or S1LVL.rev01.user.ini, depending on which .ini you use. Inside, paste these global setting:
But that's not all, each act is still configured to use two layout files! Open your SonLVL.ini or S1LVL.rev01.ini and copy across all act definitions to the end of your user.ini, and replace the data inside each with this single line:
With the XXXX being the layout of the act. You should have something like this:
When using SonLVL, don't open the user.ini, use the normal INI.
Here, we'll be porting Sonic 2's layout format and loader to Sonic 1. This doesn't save a whole lot of space (my own port reduced the total size of all REV01 level layouts from 5722 bytes to 3721), but it's a good way to familiarise yourself with the layout format and the differences between Sonic 1's and Sonic 2's. This guide will break compatibility with whatever level editors use pre-defined level layout formats. To my knowledge, the only workaround exists for SonLVL.
The theory behind it
The standard level layout setup, if you don't already know, is a simple list of chunks, arranged into rows, from left to right, following that is another row, then another, etc. This is consistent between Sonic 1 and Sonic 2.
So what is the difference between Sonic 1 and Sonic 2's layouts?
Sonic 1:
- Layouts are in two separate files for each act
- Files are uncompressed
- Designed for the 256x256 chunk system
- Maximum row size and number: 64x8
- Each layout file has a two-byte header
Sonic 2:
- Layouts are in one file for each act
- Files are Kosinski-compressed
- Designed for 128x128 chunk system
- Maximum row size and number: 128x16
- Layout files do not have headers
What does this mean, and why?
1.
Spoiler
2.
Spoiler
3 & 4.
Spoiler
5.
Spoiler
That's the goal here, folks. We're going to free up some ROM space by employing the Sonic 2 layout loading system in Sonic 1, and creating an S1-S2 hybrid level layout format!
Please note that this does not involve modifying Sonic 1 to use the 128x128 chunks system. This involves only the level layouts. Also note that Project Sonic 1: Two-Eight and any derivatives already use the Sonic 2 level layout format and loader.
Converting the layouts
We have two ways to go about this: either we simply copy the processed layouts from RAM, or we convert them manually in a hex editor. The former is significantly easier than the latter, it being the one I recommend.
From RAM:
Spoiler
By hand
Spoiler
Note that the ending has its own layout, be sure to convert that also.
With all of your layouts converted, compress them in Kosinski, and replace the contents of the 'levels' folder with them. Make sure that each and every one of the original files are replaced.
Porting the layout loader
The loader was totally rewritten for Sonic 2, so we'll have to port the routine over instead of tweaking Sonic 1's current one to use the new format.
The loader is known as "LevelLayoutLoad" in Sonic 1, and "loadLevelLayout" in Sonic 2. Looking at Sonic 1's you can see that it clears $FFFFA400-$FFFFA800, and then uses the FG and BG layouts to construct the real layout. Sonic 2's, on the other hand, is far more simple, being little more than an arrangement for a branch to KosDec. Humorously, you can find an S1-style loader dummied out below the used code. Said dummied out code is modified to conform to Sonic 2's rules, showing that Sonic 1's loader was still in use even after the jump to a 128x128 chunk system was made. Don't be as careless as Sonic Team with your precious ROM space, and delete (or comment out) all code from the label
LevelLayoutLoad:
to the line
; End of function LevelLayoutLoad2
and, in its place, paste this:
LevelLayoutLoad: move.w (v_zone).w,d0 ; Load Zone and Act into d0 ror.b #2,d0 lsr.w #5,d0 ; Convert d0's Zone & Act value into an offset lea (Level_Index).l,a0 move.w (a0,d0.w),d0 ; Offset Level_Index by d0 to reach the appropriate layout pointer lea (a0,d0.w),a0 ; Load layout ROM pointer into a0 lea (v_lvllayout).w,a1 ; Load layout RAM address into a1 bra.w KosDec ; Decompress layout to RAM ; End of function LevelLayoutLoad
Converting the level layout index
Go to Level_Index. In Sonic 1, each act in the index has three entries, word-sized pointers. The first is the FG layout, the second is the BG layout, the third... you got me. It doesn't seem to be used and normally points to null data, on three exceptions does it share its pointer with the second entry. Sonic 2 has a single word-sized pointer per act, this pointer leading to the combined FG and BG. We'll convert the index to Sonic 2's format, getting rid of the always- (and recently-made-) redundant data.
Remove the second and third entry of each act's section of the index, leaving only the FG entry. You can change whatever entries that still point to null data, and have them point to a used layout, or just blank out the pointer altogether, though in the latter's case, loading that entry will lead to a crash. You are free to delete the many 'Level_XXXbg's and null 'byte_XXXXX's, saving even more room in ROM.
With that, you're done. Save and build.
But wait!
Fixing compatibility with SonLVL (credit to MainMemory for fix)
Because our layout format is not exactly Sonic 1 or Sonic 2, no level editors support it! Here are the directions for regaining compatibility with SonLVL, the only editor I'm aware of that's capable of this.
Inside your 'SonLVL INI Files' folder, create a blank file with the name "CustomLayout.cs", to keep things simple, and open it in a text editor. Inside, paste this, and save the file:
namespace SonicRetro.SonLVL.API.S2
{
public class CustomLayout : SonicRetro.SonLVL.API.S2.Layout
{
public override void ReadLayout(byte[] rawdata, LayoutData layout)
{
layout.FGLayout = new byte[DefaultSize.Width, DefaultSize.Height];
layout.BGLayout = new byte[DefaultSize.Width, DefaultSize.Height];
layout.FGLoop = new bool[DefaultSize.Width, DefaultSize.Height];
layout.BGLoop = new bool[DefaultSize.Width, DefaultSize.Height];
int c = 0;
for (int lr = 0; lr < DefaultSize.Height; lr++)
{
for (int lc = 0; lc < DefaultSize.Width; lc++)
{
layout.FGLayout[lc, lr] = (byte)(rawdata[c] & 0x7F);
layout.FGLoop[lc, lr] = (rawdata[c++] & 0x80) == 0x80;
}
for (int lc = 0; lc < DefaultSize.Width; lc++)
{
layout.BGLayout[lc, lr] = (byte)(rawdata[c] & 0x7F);
layout.BGLoop[lc, lr] = (rawdata[c++] & 0x80) == 0x80;
}
}
}
public override void WriteLayout(LayoutData layout, out byte[] rawdata)
{
rawdata = new byte[(DefaultSize.Width * DefaultSize.Height) * 2];
int c = 0;
for (int lr = 0; lr < DefaultSize.Height; lr++)
{
for (int lc = 0; lc < DefaultSize.Width; lc++)
rawdata[c++] = (byte)(layout.FGLayout[lc, lr] | (layout.FGLoop[lc, lr] ? 0x80 : 0));
for (int lc = 0; lc < DefaultSize.Width; lc++)
rawdata[c++] = (byte)(layout.BGLayout[lc, lr] | (layout.BGLoop[lc, lr] ? 0x80 : 0));
}
}
public override bool HasLoopFlag { get { return true; } }
public override System.Drawing.Size MaxSize { get { return new System.Drawing.Size(64, 8); } }
}
}
This goes all the way back to Section 4; our custom layout is almost one-for-one identical to Sonic 2's layout format, safe for three features: any editors that support Sonic 2's layout format expect the rows to be 128 bytes in length and for there to be 16 of them. This is not the case with Sonic 1's system, which has a row length of 64 and a row total of 8. Also, we're still using S1's 'looping chunk' system, which Sonic 2 lacks. Here, these parameters are changed to reflect this, while otherwise treating the layouts as Sonic 2's.
With CustomLayout.cs done, create a new .ini file with the name SonLVL.user.ini or S1LVL.rev01.user.ini, depending on which .ini you use. Inside, paste these global setting:
layoutfmt=Custom layoutcodefile=CustomLayout.cs layoutcodetype=CustomLayout.CustomLayout
But that's not all, each act is still configured to use two layout files! Open your SonLVL.ini or S1LVL.rev01.ini and copy across all act definitions to the end of your user.ini, and replace the data inside each with this single line:
layout=../levels/XXXX.bin
With the XXXX being the layout of the act. You should have something like this:
layoutcodetype=CustomLayout.CustomLayout [Green Hill Zone Act 1] layout=../levels/ghz1.bin [Green Hill Zone Act 2] layout=../levels/ghz2.bin [Green Hill Zone Act 3] layout=../levels/ghz3.bin [Marble Zone Act 1] layout=../levels/mz1.bin ...
When using SonLVL, don't open the user.ini, use the normal INI.
This post has been edited by Clownacy: 02 December 2014 - 07:16 PM


05