How to Add A 7th Chaos Emerald/Special Stage in Sonic 1

Discussion in 'Tutorials' started by Speems, Apr 15, 2023.

  1. Speems

    Speems Well-Known Member Member

    Mar 14, 2017
    Rochester Hills, MI
    In Sonic 1, there are six chaos emeralds, with six respective special stages. The second game introduced a 7th emerald and respective special stage, and every game since had seven emeralds with seven stages (unless you're one of the 8-bit titles). As such, some hacks have tried to implement it, while others aren't aware and feel rather silly. This guide is here to get you up to speed and ensure a 7th emerald is actually somewhat easy. A neat bonus is that you'll be closer towards a true port of Super Sonic (not needing to lower the emerald requirement). This tutorial targets the Hivebrain 2005 disassembly, but references to the Github disassembly are present.

    Step 1 - Updated Checks

    Every time there's a check for 6 emeralds and special stages, update it to 7. This is because the value of 6 for the RAM addresses of $FFFFFE57 and $FFFFFE16 is frequently checked, so updating it to 7 will reflect the emerald and stage count all the way through. These checks are in End_ClrRam3, Obj87_Main, Obj8B_Main, Obj4B_Main, Obj7E_Loop, SS_Load, SS_ChkEmldNum, and Obj09_GetEmer. However, most of these just have the emerald check, but ignoring them will prevent it from working. Obj7E_Loop has a cmpi.b check for #6,d1 a few lines above the loc_C842 label, this also requires a 7. Now the Got Them All text is used at 7 emeralds rather than 6, and also allows the good ending to be accessible. If you ported the Sonic 2 level select, there is an extra check in s2_menu.asm in the Menu_Set_All_Emeralds label (when activating the all emeralds code).

    The Github RAM variables are v_emeralds and v_lastspecial respectively.

    Step 2 - Additional Layout Array

    In the _inc folder, there is an asm file named "Special stage layout pointers". Open it and add an entry for SS_7 just above the even. If you save and build, you'll get an error stating there's no definition for SS_7. So go back to sonic1.asm and search for the Special layouts section. Add an entry for SS_7 (with an incbin for 7.bin) just before the block of code checking for animated uncompressed graphics. Now if you save and build, it says there's no 7.bin file. You can copy and paste an existing file and rename it to 7, which allows a successful build. Now the data exists, but isn't called upon.

    The Github disassembly has Start Location Array - Special Stages.asm in the _inc folder, and you would add a ss7.bin inclusion to fit with the other six. Check the main sonic.asm file for the SS_LayoutIndex header, and add an entry for SS_7. Do the same thing for the Special Stage layouts section. Stage files are named as just the numbers in Hivebrain, while Github uses the "ss#" pattern for the filenames.

    Step 3 - Start Location

    In the misc folder, there is a BIN file for starting locations in special stages named sloc_ss. It has four bytes per special stage (24 bytes), similar to the main start location file for levels. Open up a hex editor (like HxD) and since we're cloning an existing stage file, we can copy a respective four-byte range in a hex editor and ammend it to the end of the file, resulting in 28 bytes. This allows a start location for our new stage. Now, building it complains about the movea.l command for SS_LayoutIndex having an illegal value. Thanks to the new bytes, it makes the assembler think the layout index is too far away to be referenced upon the instruction's execution. Head down to SS_LoadData and replace that faulty (a0,d0.w),a0 line with these two lines:

            lea    SS_LayoutIndex(pc),a0
            movea.l    (a0,d0.w),a0
    It's kinda like when you use a JSR command for certain instructions/branches that are too far away to be referenced. This also works in the Github disassembly without needing to change labels.

    Step 4 - Make That 7th Special Stage

    At this point, you can open S1SSEdit (an application that edits special stages in Sonic 1) and work with the respective file you copied and renamed as 7. Have fun with the layout, I'm not telling you what exact design to go for. You can insert an existing emerald for now, but we'll take care of that later.

    After all our current work, when completing the existing six special stages, you'll see the "Chaos Emeralds" text when you get the standard six, but when completing the newly added seventh (with the temporary emerald or finding one with debug mode out of bounds), it will say "Sonic Got Them All". This means all of the necessary functionality is working as intended. But you're probably asking something: Don't we need an actual 7th emerald object with art? And what about the ending? Yes and yes, so let's get into that.

    Step 5 - Seventh Emerald in Special Stage 7 and the Results

    In Obj7F_PosData, you'll see six entries for the emeralds. The values represent their X-axis position on the special stage results screen. Add ", $170" after the 158 entry, which allows seven emeralds on the special stage results. It may appear as a duplicate of an existing emerald next to the others when collected (although it is normal with the current mappings) and appear mis-centered, but it's normal (at least for ensuring it works). Make use of the Obj7F mappings, ssresems art file, and ssresult palette file (all four lines!) in Flex2 for adding an extra sprite. We don't actually need to add more tiles, as we can make use of the palette in its mapping much like with how the yellow and green emeralds are displayed. It's up to you to manage said palette to correctly display a 7th emerald. You should have eight sprites (seven emeralds and an empty sprite, a blank frame used for a flashing effect). Upon building, it would now have the emeralds flash between the normal sprites and the cyan one. To fix this, go to Obj7F_Flash and change both instances of 6 to 7, which restores the blank frame's intented use.

    In the "Special stage mappings and VRAM pointers" file within _inc, add this in place of the last Map_SS_R before the entry for Up:

        dc.l Map_SS_Chaos2
        dc.w $6770
    This uses the gray emerald sprite but loads it with the 4th palette line, rendering it as cyan. The 770 represents the VRAM frame, and the 6 tells it to use the fourth palette line. The file is identical in the Github disassembly. The game doesn't make use of the 1Up object (unless S1SSEdit is used to place it back in), and this method only works if you're willing to sacrifice it for an easy way out. Replace the Obj09_Chk1Up and Obj09_Get1Up routines with the following code:

            cmpi.b    #$28,d4    ; is the item the second emerald object?
            bne.s    Obj09_ChkEmer
            bsr.w    SS_RemoveCollectedItem
            bne.s    Obj09_GetEmer2
            move.b    #5,(a2)
            move.l    a1,4(a2)
            cmpi.b    #7,($FFFFFE57).w; do you have all the emeralds?
            beq.s    Obj09_NoEmer; if yes, branch
            move.b    #$6,d4
            moveq    #0,d0
            move.b    ($FFFFFE57).w,d0
            lea    ($FFFFFE58).w,a2
            move.b    d4,(a2,d0.w)
            addq.b    #1,($FFFFFE57).w; add 1 to number of emeralds
            bra.s    Obj09_NoEmer
    This code was concocted by Nineko as a workaround to making an additional emerald object. As such, we lose the 1Up object and is workshopped into a secondary emerald object.

    As for the results screen palette, try copying the special file as a seperate file and swap the 1st and 2nd palette line positioning (ensuring the line that holds Sonic's palette is in line 2). It would require a few palette touchups in line 0 to resemble the example:
    This aforementioned random color gives the title card font a different color on the results screen like before. Current issue is that the white shine renders as the fifth shade of green in special stages, so replace it with a standard white, which is also lines up with the example. After all these inclusions, it should work.

    Step 6 - Seventh Emerald Part 2, Ending Boogaloo

    The ending uses different emerald art and mappings (endemera.bin and Obj88.asm with the ending.bin palette). Add a new sprite using the blue emerald, and set its palette usage to the fourth line. This renders it as sky blue. Much like the previous file, we don't need to add extra tiles as palette management is our savior. The four shades can be switched out for the same cyan shades as the previous files. You should have eight sprites (flash, blue, yellow, pink, green, red, white, cyan) in the mappings. Obj8C makes use of these files. Now we need to apply the new sprite, starting with the rotating emeralds in the good ending. In Obj88_MainLoop, the third to last line is as follows:

            addi.b    #$2A,d3
    This ensures the ending emeralds are evenly spaced, by increasing their angle by $2A (which is 42 with the math being ~255/6, since angles use a byte value, with the maximum set to 255.) Change the value to 25, as this allows an open space inbetween the blue and gray emeralds. Now we need to actually apply our change! This line above Obj88_MainLoop (or last line in Obj88_Main2) is as follows:

            moveq    #5,d1
    It is also present in loc_5A6A and Obj8C_Main. Change these three specific instances to 6, as it will allow the 7th emerald to fit evenly in that blank space. It will also be juggled by Eggman in the Try Again screen.

    After all that, you should be fully complete! There are now seven Chaos Emeralds in your hack, with seven respective special stages, and all proper code checks and additions work as intended. Now go ahead and port Super Sonic with no questions asked (prolly not from me tho)! Have at it! This guide was tested with Kega Fusion and a close-to-the-latest nightly build of BlastEm. Additional credits to Professor Neo, DeltaWooloo, and Nineko.
    Last edited: Apr 16, 2023
    Techokami, Ashuro, nineko and 5 others like this.