Add Extra Characters
From Sonic Retro
(Original guide by Sonic 65)
(Guide updated by Makotoyuki and JGMR)
Multiple characters is a fad in hacks nowadays, but not everyone knows how to add multiple characters to their hacks. That's what this tutorial is here for. This tutorial assumes you have basic knowledge of how to use a split disassembly, and is assuming you are using Hivebrain's 2005 disassembly and the SVN/GitHub disassemblies. It is also assuming that your art fits with Sonic's mappings.
Contents
- 1 Beginning the process
- 2 Load the extra character on the title screen
- 3 Making the game load art for the extra character
- 4 Conclusion
- 5 Optional improvements
Beginning the process
First of all, extract the art that you want from the ROM. You could do this by splitting it, or going into a hex editor and extracting the portion you want into a seperate file. Either way, once you have your file, put it into the 'artunc' folder of your split disassembly. My file is named 'msonic.bin', but yours could be named anything; just replace all instances of 'msonic.bin' that I say with your file's name.
The first step is to search for 'Art_Sonic:' in your disassembly. The result of the search should look something like this:
; ---------------------------------------------------------------------------
; Uncompressed graphics - Sonic
; ---------------------------------------------------------------------------
Art_Sonic: incbin artunc\sonic.bin ; Sonic
even
Now, copy that data and paste it below. Then change Art_Sonic to another label, and replace the sonic.bin with your filename. My result was this:
; ---------------------------------------------------------------------------
; Uncompressed graphics - Metal Sonic
; ---------------------------------------------------------------------------
Art_MetalSonic: incbin artunc\msonic.bin ; Metal Sonic
even
Note that if you're using the AS version of Hivebrain's 2005 disassembly or newer versions of the GitHub disassembly which are based on AS instead of SNASM68K/ASM68K, you may need to readjust your code to suit the assembler. Notably, instances of "incbin" should be replaced with "binclude" whenever appropriate.
For users of the GitHub/SVN disassemblies, an additional step is required. Open up 'Variables.asm' and underneath 'v_megadrive:', add this:
v_character: = $FFFFFFF9 ; character flag
This will set our character flag, in which this case it uses the unused RAM address $FFFFFFF9. You can change this RAM address into any other unused RAM address you want.
For newer versions of the GitHub disassembly, this process works out differently. Locate the following line as shown:
v_megadrive: ds.b 1 ; Megadrive machine type
ds.b 1 ; unused <-- locate this line here
f_debugmode: ds.w 1 ; debug mode flag
Replace it with this:
v_character: ds.b 1 ; character flag
Load the extra character on the title screen
Next, you have to decide how you want to have your character be chosen. I chose to make the character Metal Sonic if B was pressed at the title screen. For the purposes of this tutorial, I will assume you want to do it that way too. So search for 'loc_3230:'. You should find something like this if you're using the Hivebrain disassembly:
loc_3230:
tst.w ($FFFFF614).w
beq.w Demo
andi.b #$80,($FFFFF605).w ; check if Start is pressed
beq.w loc_317C ; if not, branch
Or this if you're using the GitHub/SVN disassembly:
loc_3230:
tst.w (v_demolength).w
beq.w GotoDemo
andi.b #btnStart,(v_jpadpress1).w ; check if Start is pressed
beq.w Tit_MainLoop ; if not, branch
After the beq.w Demo (or beq.w GotoDemo in the GitHub/SVN disassembly), put this in for the Hivebrain disassembly:
Title_CheckForB:
cmpi.b #$10,($FFFFF605).w ; has B been pressed?
bne.s StartCheck ; if not, branch
Title_SecondCharacter:
move.b #1,($FFFFFFF9).w ; set the multiple character flag to 1 (indicating Metal Sonic)
move.b #$B5,d0 ; put value of ring sound into d0
bsr.w PlaySound_Special ; jump to the subroutine that plays the sound currently in d0 ($B5, at the moment)
StartCheck:
And this for the GitHub/SVN disassembly:
Tit_CheckForB:
cmpi.b #btnB,(v_jpadpress1).w ; has B been pressed?
bne.s StartCheck ; if not, branch
Tit_SecondCharacter:
move.b #1,(v_character).w ; set the multiple character flag to 1 (indicating Metal Sonic)
move.b #sfx_Ring,d0 ; put value of ring sound into d0
bsr.w PlaySound_Special ; jump to the subroutine that plays the sound currently in d0 (sfx_Ring, at the moment)
StartCheck:
This checks if B is pressed, and sets a flag at $FFFFFFF9/v_character if it is. It also plays the ring sound (which is $B5/sfx_Ring in the sound test). You can change the sound it plays by changing $B5/sfx_Ring to the sound test value of whatever sound you want to play.
Making the game load art for the extra character
Now, go to the LoadSonicDynPLC subroutine in the Hivebrain disassembly or open up SonicLoad GFX under _incobj in the GitHub/SVN disassembly and find this instruction:
lea (Art_Sonic).l,a1
Replace it with:
cmpi.b #1,($FFFFFFF9).w ; is the multiple character flag set to 1 (Metal Sonic)?
bne.s SonicArtLoad ; if not, load Sonic's art
lea (Art_MetalSonic).l,a1 ; load Metal Sonic's art
bra.s ContLoadPLC ; branch to rest of code
SonicArtLoad:
lea (Art_Sonic).l,a1 ; load Sonic's art
ContLoadPLC:
for the Hivebrain disassembly and
cmpi.b #1,(v_character).w ; is the multiple character flag set to 1 (Metal Sonic)?
bne.s @sonicart ; if not, load Sonic's art
lea (Art_MetalSonic).l,a1 ; load Metal Sonic's art
bra.s @loadart ; branch to rest of code
@sonicart:
lea (Art_Sonic).l,a1 ; load Sonic's art
@loadart:
for the GitHub/SVN disassemblies (for newer versions of the GitHub disassembly, replace the "@" with "." to prevent building errors).
This code tests if the multiple character flag (which we set to $01 if you pressed B at the title screen) is set to $01. If it isn't, it just loads Sonic's art like normal and continues to the ContLoadPLC/@loadart subroutine. If it is, it loads Metal Sonic's art and jumps directly to the ContLoadPLC/@loadart subroutine (so that we don't load Sonic's art at all).
Now, if you have implemented the DPLC routine from Sonic 2 by following this guide, then this process will work out differently. Find this instruction:
move.l #Art_Sonic,d6
Replace it with:
cmpi.b #1,($FFFFFFF9).w ; is the multiple character flag set to 1 (Metal Sonic)?
bne.s SonicArtLoad ; if not, load Sonic's art
move.l #Art_MetalSonic,d6 ; load Metal Sonic's art
bra.s SPLC_ReadEntry ; branch to rest of code
SonicArtLoad:
move.l #Art_Sonic,d6 ; load Sonic's art
for the Hivebrain disassembly and
cmpi.b #1,(v_character).w ; is the multiple character flag set to 1 (Metal Sonic)?
bne.s .sonicart ; if not, load Sonic's art
move.l #Art_MetalSonic,d6 ; load Metal Sonic's art
bra.s .readentry ; branch to rest of code
.sonicart:
move.l #Art_Sonic,d6 ; load Sonic's art
for the GitHub/SVN disassemblies.
Conclusion
And...that's all. Compile the code, and if you run into any errors you either chose a subroutine name that was already taken or did something else wrong. Have fun putting new characters in your hacks!
Optional improvements
These optional improvements are here for you to give your new character(s) a distinct and unique personality separate from Sonic himself.
Making the extra character load its own mappings and PLC
If you think using only Sonic's art and not touching the mappings and PLC data is limiting and you want your new character to have different mappings and PLCs from Sonic, then this part of the tutorial will show you how to do that.
Beginning the process
First, make a copy of Sonic's mapping and DPLC data. The mappings go to the '_maps' folder of your split disassembly, while your DPLCs goes to either the '_inc' or '_maps' folder of your split disassembly, depending on if you're using the Hivebrain or GitHub/SVN disassemblies. The copied mapping file will be called 'MetalSonic.asm', while the copied DPLC file will either have the names 'MetalSonic dynamic pattern load cues.asm' or 'MetalSonic - Dynamic Gfx Script.asm', depending on if you're using the Hivebrain or GitHub/SVN disassemblies. Again, you can have any name you want for your files; just replace all instances of 'MetalSonic' that I say with your chosen name.
But before we dive into putting our mappings and DPLCs in, we need to do some prerequisite work here to avoid any potential errors when compiling the code.
First, open up your mappings and DPLC files in your text editor of choice. Depending on whether you have the Hivebrain or GitHub/SVN versions of the files, here are some things that you may want to watch out for:
- Hivebrain: mappings have the labels 'Map_Sonic' and 'byte_XXXXX', while DPLCs have the words 'SonPLC' and 'SonicDynPLC' on the labels. These won't be present if you have a mappings file generated by another program.
- 'Map_Sonic:' and 'SonicDynPLC:' are located in the main ASM file (sonic1.asm).
- GitHub/SVN: mappings have the labels 'Map_Sonic' and 'MS_XXXXXX', while DPLCs have the words 'SonPLC' and 'SonicDynPLC' on the labels. Again, these won't be present if you have a mappings file generated by another program.
- 'Map_Sonic:' and 'SonicDynPLC:' are located directly within their own files, with 'Map_Sonic:' placed under 'Sonic.asm' and 'Sonic - Dynamic Gfx Script.asm' respectively, located in _maps.
- The mappings file also has the label 'MS_XXXXXX' for the mapping frames. It also has additional code for use with Constants, with labels 'ptr_MS_XXXXXX' and 'fr_XXXXXX'. If you have a mappings file generated by another program, these additions will be absent.
- In later versions of the GitHub disassembly, the 'Map_Sonic' and 'SonicDynPLC' labels will have the words '_internal' prefixed after the words.
To prevent a double name conflict in compiling the code, we need to change several name instances so that they don't cause the aforementioned naming conflict. To do that, replace instances of 'Son' and 'Sonic' with your character's name, and then add a '2' to the labels before the underscore ('_') in several labels ('byte_XXXXXX' => 'byte2_XXXXXX') except for those with 'Map_' on them, such as 'Map_XXXXXX'. This will resolve the problem with compiling the code in the future.
Now we need to include our files. Make a search for 'Nem_JapNames:' in your disassembly, and below it, you will see the following instructions. Depending on which type of disassembly you have, here's what you'll find in the Hivebrain disassembly:
; ---------------------------------------------------------------------------
; Sprite mappings - Sonic
; ---------------------------------------------------------------------------
Map_Sonic:
include "_maps\Sonic.asm"
; ---------------------------------------------------------------------------
; Uncompressed graphics loading array for Sonic
; ---------------------------------------------------------------------------
SonicDynPLC:
include "_inc\Sonic dynamic pattern load cues.asm"
For the GitHub/SVN disassemblies, it looks like this:
include "_maps\Sonic.asm"
include "_maps\Sonic - Dynamic Gfx Script.asm"
And for later versions of the GitHub disassembly, it looks like this:
Map_Sonic: include "_maps/Sonic.asm"
SonicDynPLC: include "_maps/Sonic - Dynamic Gfx Script.asm"
Copy what you see below and change it so that it resembles our results below. For the Hivebrain disassembly:
; ---------------------------------------------------------------------------
; Sprite mappings - Sonic
; ---------------------------------------------------------------------------
Map_Sonic:
include "_maps\Sonic.asm"
; ---------------------------------------------------------------------------
; Uncompressed graphics loading array for Sonic
; ---------------------------------------------------------------------------
SonicDynPLC:
include "_inc\Sonic dynamic pattern load cues.asm"
; ---------------------------------------------------------------------------
; Sprite mappings - Metal Sonic
; ---------------------------------------------------------------------------
Map_MetalSonic:
include "_maps\MetalSonic.asm"
; ---------------------------------------------------------------------------
; Uncompressed graphics loading array for Metal Sonic
; ---------------------------------------------------------------------------
MetalSonicDynPLC:
include "_inc\MetalSonic dynamic pattern load cues.asm"
For the GitHub/SVN disassemblies:
include "_maps\Sonic.asm"
include "_maps\Sonic - Dynamic Gfx Script.asm"
include "_maps\MetalSonic.asm"
include "_maps\MetalSonic - Dynamic Gfx Script.asm"
And for later versions of the GitHub disassembly:
Map_Sonic: include "_maps/Sonic.asm"
SonicDynPLC: include "_maps/Sonic - Dynamic Gfx Script.asm"
Map_MetalSonic: include "_maps/MetalSonic.asm"
MetalSonicDynPLC: include "_maps/MetalSonic - Dynamic Gfx Script.asm"
Making the game load mappings and PLC for the extra character
Now go to the code for Sonic, which should be 'Obj01' in the Hivebrain disassembly and 'SonicPlayer' in the GitHub/SVN disassembly. From there, locate 'Obj01_Main' for the Hivebrain disassembly and 'Sonic_Main' in the GitHub/SVN disassembly and find these instructions below. Depending on which type of disassembly you have, in the Hivebrain disassembly it should look like this:
move.l #Map_Sonic,4(a0)
For the GitHub/SVN disassemblies, it looks like this:
move.l #Map_Sonic,obMap(a0)
Replace it with this:
cmpi.b #1,($FFFFFFF9).w ; is the multiple character flag set to 1 (Metal Sonic)?
bne.s SonicMapLoad ; if not, load Sonic's mappings
move.l #Map_MetalSonic,4(a0) ; load Metal Sonic's mappings
bra.s ContLoadMap ; branch to rest of code
SonicMapLoad:
move.l #Map_Sonic,4(a0)
ContLoadMap:
For the Hivebrain disassembly and
cmpi.b #1,($FFFFFFF9).w ; is the multiple character flag set to 1 (Metal Sonic)?
bne.s @sonicmap ; if not, load Sonic's mappings
move.l #Map_MetalSonic,obMap(a0) ; load Metal Sonic's mappings
bra.s @loadmap ; branch to rest of code
@sonicmap:
move.l #Map_Sonic,obMap(a0)
@loadmap:
for the GitHub/SVN disassemblies
This code tests if the multiple character flag (which we set to $01 if you pressed B at the title screen) is set to $01. If it isn't, it just loads Sonic's mappings like normal and continues to the ContLoadMap subroutine. If it is, it loads Metal Sonic's mappings and jumps directly to the ContLoadMap subroutine (so that we don't load Sonic's mappings at all).
Now go back to the LoadSonicDynPLC subroutine in the Hivebrain disassembly or open up SonicLoad GFX under _incobj in the GitHub/SVN disassembly and find this instruction:
lea (SonicDynPLC).l,a2
Replace it with this:
cmpi.b #1,($FFFFFFF9).w ; is the multiple character flag set to 1 (Metal Sonic)?
bne.s SonicPLCLoad ; if not, load Sonic's DPLC
lea (MetalSonicDynPLC).l,a2 ; load Metal Sonic's DPLC
bra.s ContLoadDPLC ; branch to rest of code
SonicPLCLoad:
lea (SonicDynPLC).l,a2
ContLoadDPLC:
For the Hivebrain disassembly and
cmpi.b #1,($FFFFFFF9).w ; is the multiple character flag set to 1 (Metal Sonic)?
bne.s @sonicplc ; if not, load Sonic's DPLC
lea (MetalSonicDynPLC).l,a2 ; load Metal Sonic's DPLC
bra.s @loadplc ; branch to rest of code
@sonicplc:
lea (SonicDynPLC).l,a2 ; load PLC script
@loadplc:
for the GitHub/SVN disassemblies
This code tests if the multiple character flag (which we set to $01 if you pressed B at the title screen) is set to $01. If it isn't, it just loads Sonic's DPLCs like normal and continues to the ContLoadPLC subroutine. If it is, it loads Metal Sonic's DPLCs and jumps directly to the ContLoadPLC subroutine (so that we don't load Sonic's DPLCs at all).
Conclusion
With all of that done, compile the code and it should build successfully. You shouldn't get any errors during building, unless you did something wrong when following the guide. Your new character may still look the same after following the guide; the easiest way to determine that you have followed this guide correctly is to provide your own art, mappings, and DPLCs for your extra character. If your custom files are shown in-game, then you have successfully completed this optional guide.
Making the extra character load its own animations and palettes
If you want to have your new character to have different animations and palettes from Sonic, then this part of the tutorial will show you how to do that.
Beginning the process
First, make a copy of Sonic's animation and palette data. The animations go to the '_anim' folder of your split disassembly, while your palettes goes to either the 'pallet' or 'palette' folder of your split disassembly, depending on if you're using the Hivebrain or GitHub/SVN disassemblies. Specifically for the GitHub/SVN disassemblies, we'll be using 'Sonic (without frame IDs).asm' for our new animation file that we're going to copy, because it does not use frame IDs. The copied animation file will be called 'MetalSonic.asm', while the copied palette file will have the name 'msonic.bin' (not to be confused with our 'msonic.bin' art file located under the 'artunc' folder). Again, you can have any name you want for your files; just replace all instances of 'MetalSonic' that I say with your chosen name.
But before we dive into putting our animations and palettes in, we need to know a few things regarding the animation files.
First, open up your animation files in your text editor of choice. Depending on whether you have the Hivebrain or GitHub/SVN versions of the files, here are some things that you may want to watch out for:
- Hivebrain: animations have the words 'SonicAniData' and 'SonAni' on the labels.
- 'SonicAniData:' is located in the main ASM file (sonic1.asm).
- GitHub/SVN: animations have the words 'Ani_Sonic' and 'SonAni' on the labels.
- 'Ani_Sonic:' is located directly within its own file, with 'Ani_Sonic:' placed under 'Sonic.asm', located in _anim.
- The main 'Sonic.asm' animation file includes frame IDs within the animation files. They have the labels 'fr_XXXXXX' to refer to them. There is an alternative animation file named 'Sonic (without frame IDs).asm' that do not contain the frame IDs. Both can be found in the _anim folder. For this guide, the version of the animation file we're using for our new character is the one without frame IDs.
- The animation file also has additional code for use with Constants, with labels 'ptr_XXXXXX' and 'id_XXXXXX'. Both animation files include constants for the animation IDs at the very bottom. The labels 'id_XXXXXX' are used here. They typically follow in this format:
id_Walk: equ (ptr_Walk-Ani_Sonic)/2 ; 0 id_Run: equ (ptr_Run-Ani_Sonic)/2 ; 1 id_Roll: equ (ptr_Roll-Ani_Sonic)/2 ; 2 id_Roll2: equ (ptr_Roll2-Ani_Sonic)/2 ; 3 id_Push: equ (ptr_Push-Ani_Sonic)/2 ; 4 id_Wait: equ (ptr_Wait-Ani_Sonic)/2 ; 5 ...
- In the SVN disassembly, one label is different in the two separate animation files. In this case, 'XXXXXX_Hang' is named as 'XXXXXX_LZHang' in the animation file without the frame IDs. The GitHub disassembly fixes this error. This does not affect anything that we’re doing with in the guide.
To prevent a double name conflict in compiling the code, we need to change several name instances so that they don't cause the aforementioned naming conflict. To do that, replace instances of 'Son' and 'Sonic' with your character's name. This will resolve the problem with compiling the code in the future. For the SVN/GitHub disassemblies, this has to be taken further. Add a '2' to the labels before the underscore ('_') in several labels ('ptr_XXXXXX' => 'ptr2_XXXXXX') except for those with your character's name on them.
Regarding palette files, they must be one palette line long, as newer versions of the GitHub disassembly changed the routines on handling palette files. If you have a palette file that is up to four palette lines long, this will cause some palette issues when the main level fades in during the title card sequences. So make sure to adjust your palette files accordingly to prevent such issues. Users of the older GitHub/SVN disassemblies will not experience these issues.
Now we need to include our files. We'll start with the animation files. Make a search for '_anim\Sonic.asm' in your disassembly, and you will see the following instructions. Depending on which type of disassembly you have, here's what you'll find in the Hivebrain disassembly:
SonicAniData:
include "_anim\Sonic.asm"
For the GitHub/SVN disassemblies, it looks like this:
include "_anim\Sonic.asm"
Later versions of the GitHub disassembly look identical, except that the backslash '\' is replaced with a slash '/'.
Copy what you see below and change it so that it resembles our results below. For the Hivebrain disassembly:
SonicAniData:
include "_anim\Sonic.asm"
MetalSonicAniData:
include "_anim\MetalSonic.asm"
For the GitHub/SVN disassemblies:
include "_anim\Sonic.asm"
include "_anim\MetalSonic.asm"
And for later versions of the GitHub disassembly:
include "_anim/Sonic.asm"
include "_anim/MetalSonic.asm"
Now for the palettes. Make a search for 'Pal_Sonic:' in your disassembly, and you will see the following instructions. Depending on which type of disassembly you have, here's what you'll find in the Hivebrain disassembly:
Pal_Sonic: incbin pallet\sonic.bin
For the GitHub/SVN disassemblies, it looks like this:
Pal_Sonic: incbin "palette\Sonic.bin"
For later versions of the GitHub disassembly based on AS, it looks like this:
Pal_Sonic: bincludePalette "palette/Sonic.bin"
As before, copy what you see below and change it so that it resembles our results below. For the Hivebrain disassembly:
Pal_Sonic: incbin pallet\sonic.bin
Pal_MetalSonic: incbin pallet\msonic.bin
For the GitHub/SVN disassemblies:
Pal_Sonic: incbin "palette\Sonic.bin"
Pal_MetalSonic: incbin "palette\msonic.bin"
And for the later versions of the GitHub disassembly based on AS:
Pal_Sonic: bincludePalette "palette/Sonic.bin"
Pal_MetalSonic: bincludePalette "palette\msonic.bin"
Making the game load animations and palettes for the extra character
Now we can begin making the game load our custom animations and palettes for our extra character. We’ll start off with the animations first. So go to the Sonic_Animate subroutine in the Hivebrain disassembly or open up Sonic Animate under _incobj in the GitHub/SVN disassembly and find the following instruction below. Depending on which type of disassembly you have, in the Hivebrain disassembly it should look like this:
lea (SonicAniData).l,a1
For the GitHub/SVN disassemblies, it looks like this:
lea (Ani_Sonic).l,a1
Replace it with this:
cmpi.b #1,($FFFFFFF9).w ; is the multiple character flag set to 1 (Metal Sonic)?
bne.s SonicAnimLoad ; if not, load Sonic's animations
lea (MetalSonicAniData).l,a1 ; load Metal Sonic's animations
bra.s ContLoadAnim ; branch to rest of code
SonicAnimLoad:
lea (SonicAniData).l,a1
ContLoadAnim:
For the Hivebrain disassembly and
cmpi.b #1,($FFFFFFF9).w ; is the multiple character flag set to 1 (Metal Sonic)?
bne.s @sonicani ; if not, load Sonic's animations
lea (Ani_MetalSonic).l,a1 ; load Metal Sonic's animations
bra.s @loadani ; branch to rest of code
@sonicani:
lea (Ani_Sonic).l,a1
@loadani:
for the GitHub/SVN disassemblies
This code tests if the multiple character flag (which we set to $01 if you pressed B at the title screen) is set to $01. If it isn't, it just loads Sonic's animations like normal and continues to the ContLoadAnim subroutine. If it is, it loads Metal Sonic's animations and jumps directly to the ContLoadAnim subroutine (so that we don't load Sonic's animations at all).
Now, we're not done yet. We still have to do some more work to load the proper animations. So go to 'loc_13A9C:' (or '@nomodspeed:' in the GitHub/SVN disassembly), and you'll see the following for the Hivebrain disassembly:
lea (SonAni_Run).l,a1 ; use running animation
cmpi.w #$600,d2 ; is Sonic at running speed?
bcc.s loc_13AB4 ; if yes, branch
lea (SonAni_Walk).l,a1 ; use walking animation
Or this for the GitHub/SVN disassemblies:
lea (SonAni_Run).l,a1 ; use running animation
cmpi.w #$600,d2 ; is Sonic at running speed?
bcc.s @running ; if yes, branch
lea (SonAni_Walk).l,a1 ; use walking animation
Replace it with this:
cmpi.b #1,($FFFFFFF9).w ; is the multiple character flag set to 1 (Metal Sonic)?
bne.s SonicRunWalkLoad ; if not, load Sonic's animations
lea (MetalSonicAni_Run).l,a1 ; use Metal Sonic's running animation
cmpi.w #$600,d2 ; is Metal Sonic at running speed?
bcc.s loc_13AB4 ; if yes, branch
lea (MetalSonicAni_Walk).l,a1 ; use Metal Sonic's walking animation
bra.s ContLoadAnim2 ; branch to rest of code
SonicRunWalkLoad:
lea (SonAni_Run).l,a1 ; use running animation
cmpi.w #$600,d2 ; is Sonic at running speed?
bcc.s loc_13AB4 ; if yes, branch
lea (SonAni_Walk).l,a1 ; use walking animation
ContLoadAnim2:
For the Hivebrain disassembly and
cmpi.b #1,($FFFFFFF9).w ; is the multiple character flag set to 1 (Metal Sonic)?
bne.s @sonicani2 ; if not, load Sonic's animations
lea (MetalSonicAni_Run).l,a1 ; use Metal Sonic's running animation
cmpi.w #$600,d2 ; is Metal Sonic at running speed?
bcc.s @running ; if yes, branch
lea (MetalSonicAni_Walk).l,a1 ; use Metal Sonic's walking animation
bra.s @loadani2 ; branch to rest of code
@sonicani2:
lea (SonAni_Run).l,a1 ; use running animation
cmpi.w #$600,d2 ; is Sonic at running speed?
bcc.s @running ; if yes, branch
lea (SonAni_Walk).l,a1 ; use walking animation
@loadani2:
for the GitHub/SVN disassemblies
Next, go to 'loc_13ADE:' (or '@nomodspeed2:' in the GitHub/SVN disassembly) and find these lines:
lea (SonAni_Roll2).l,a1 ; use fast animation
cmpi.w #$600,d2 ; is Sonic moving fast?
bcc.s loc_13AF0 ; if yes, branch
lea (SonAni_Roll).l,a1 ; use slower animation
Replace them with this:
cmpi.b #1,($FFFFFFF9).w ; is the multiple character flag set to 1 (Metal Sonic)?
bne.s SonicRollLoad ; if not, load Sonic's animations
lea (MetalSonicAni_Roll2).l,a1 ; use fast animation
cmpi.w #$600,d2 ; is Metal Sonic moving fast?
bcc.s loc_13AF0 ; if yes, branch
lea (MetalSonicAni_Roll).l,a1 ; use slower animation
bra.s loc_13AF0 ; branch to rest of code
SonicRollLoad:
lea (SonAni_Roll2).l,a1 ; use fast animation
cmpi.w #$600,d2 ; is Sonic moving fast?
bcc.s loc_13AF0 ; if yes, branch
lea (SonAni_Roll).l,a1 ; use slower animation
For the Hivebrain disassembly and
cmpi.b #1,($FFFFFFF9).w ; is the multiple character flag set to 1 (Metal Sonic)?
bne.s @sonicani3 ; if not, load Sonic's animations
lea (MetalSonicAni_Roll2).l,a1 ; use fast animation
cmpi.w #$600,d2 ; is Metal Sonic moving fast?
bcc.s @rollfast ; if yes, branch
lea (MetalSonicAni_Roll).l,a1 ; use slower animation
bra.s @rollfast ; branch to rest of code
@sonicani3:
lea (SonAni_Roll2).l,a1 ; use fast animation
cmpi.w #$600,d2 ; is Sonic moving fast?
bcc.s @rollfast ; if yes, branch
lea (SonAni_Roll).l,a1 ; use slower animation
for the GitHub/SVN disassemblies
And finally, go to 'loc_13B26:' (or '@belowmax3:' in the GitHub/SVN disassembly) and find this line:
lea (SonAni_Push).l,a1
Replace it with this:
cmpi.b #1,($FFFFFFF9).w ; is the multiple character flag set to 1 (Metal Sonic)?
bne.s SonicPushLoad ; if not, load Sonic's animations
lea (MetalSonicAni_Push).l,a1
bra.s ContLoadAnim3 ; branch to rest of code
SonicPushLoad:
lea (SonAni_Push).l,a1
ContLoadAnim3:
For the Hivebrain disassembly and
cmpi.b #1,($FFFFFFF9).w ; is the multiple character flag set to 1 (Metal Sonic)?
bne.s @sonicani4 ; if not, load Sonic's animations
lea (MetalSonicAni_Push).l,a1
bra.s @loadani3 ; branch to rest of code
@sonicani4:
lea (SonAni_Push).l,a1
@loadani3:
for the GitHub/SVN disassemblies
Now that's the animation part done, now for the palettes. But before we put our code in, we need to provide the pointers for our new palette file. So for the Hivebrain disassembly, open up 'Pallet Pointers.asm' located in the '_inc' folder, and find these lines:
dc.l Pal_Ending
dc.w $FB00
dc.w $1F
Place this after it:
dc.l Pal_MetalSonic
dc.w $FB00
dc.w 7
This will load our palette into the pointer of palettes. In this case, our new palette will have a palette ID of $14.
For the GitHub/SVN disassemblies, this process works out differently. Open up 'Palette Pointers.asm' located in the '_inc' folder, and locate this line:
ptr_Pal_Ending: palp Pal_Ending,$FB00,$40 ; $13 (19) - ending sequence
And add this underneath it:
ptr_Pal_MetalSonic: palp Pal_MetalSonic,$FB00,$10 ; 3 - Metal Sonic
This will load our palette into the pointer of palettes. Note that on the GitHub disassembly, the '$FB00' instruction would be replaced with 'v_pal_dry'.
For the later versions of the GitHub disassembly based on AS, this process also works out differently, but is still relatively the same. Find this line:
ptr_Pal_Ending: palp 0,Pal_Ending ; $13 (19) - ending sequence
And add this underneath it:
ptr_Pal_MetalSonic: palp 0,Pal_MetalSonic ; $14 (20) - Metal Sonic
This will again load our palette into the pointer of palettes.
Now for completeness, go down to the end of the file and find this line:
palid_Ending: equ (ptr_Pal_Ending-PalPointers)/8
Add this underneath it:
palid_MetalSonic: equ (ptr_Pal_MetalSonic-PalPointers)/8
This will give us a palette ID for our new palette that we've loaded into the pointer of palettes. In this case, our new palette will have a palette ID of $14.
Now to actually load our palette in-game. So search for "Level_LoadPal:" and find the following lines. On Hivebrain disassemblies it looks like this:
moveq #3,d0
bsr.w PalLoad2 ; load Sonic's pallet line
On GitHub/SVN disassemblies, it looks like this:
moveq #palid_Sonic,d0
bsr.w PalLoad2 ; load Sonic's palette
On later versions of the GitHub disassembly, it looks like this:
moveq #palid_Sonic,d0
bsr.w PalLoad ; load Sonic's palette
Replace those lines with this:
cmpi.b #1,($FFFFFFF9).w ; is the multiple character flag set to 1 (Metal Sonic)?
bne.s SonicPalLoad ; if not, load Sonic's pallets
moveq #$14,d0 ; <-- the '$14' refers to our pallet ID, located under "Pallet Pointers.asm" in '_inc'
bsr.w PalLoad2 ; load Sonic's pallet line
bra.s ContLoadPal ; branch to rest of code
SonicPalLoad:
moveq #3,d0
bsr.w PalLoad2 ; load Sonic's pallet line
ContLoadPal:
For the Hivebrain disassembly and
cmpi.b #1,($FFFFFFF9).w ; is the multiple character flag set to 1 (Metal Sonic)?
bne.s @SonicPalLoad ; if not, load Sonic's palettes
moveq #palid_MetalSonic,d0 ; <-- this refers to our palette ID, located under "Palette Pointers.asm" in '_inc'
bsr.w PalLoad2 ; load Sonic's palette
bra.s @loadpal ; branch to rest of code
@SonicPalLoad:
moveq #palid_Sonic,d0
bsr.w PalLoad2 ; load Sonic's palette
@loadpal:
for the GitHub/SVN disassemblies and
cmpi.b #1,($FFFFFFF9).w ; is the multiple character flag set to 1 (Metal Sonic)?
bne.s .sonicpal ; if not, load Sonic's palettes
moveq #palid_MetalSonic,d0 ; <-- this refers to our palette ID, located under "Palette Pointers.asm" in '_inc'
bsr.w PalLoad ; load Metal Sonic's palette
bra.s .loadpal ; branch to rest of code
.sonicpal:
moveq #palid_Sonic,d0
bsr.w PalLoad ; load Sonic's palette
.loadpal:
for later versions of the GitHub disassembly
This code tests if the multiple character flag (which we set to $01 if you pressed B at the title screen) is set to $01. If it isn't, it just loads Sonic's palettes like normal and continues to the ContLoadPal subroutine. If it is, it loads Metal Sonic's palettes and jumps directly to the ContLoadPal subroutine (so that we don't load Sonic's palettes at all).
Conclusion
With all of that done, compile the code and it should build successfully. You shouldn't get any errors during building, unless you did something wrong when following the guide. Your new character may still look the same after following the guide; the easiest way to determine that you have followed the guide correctly is to provide your own art, mappings, DPLCs, animations, and palettes for your extra character. If your custom files are shown in-game, then you have successfully completed this optional guide.
Ability to switch between Sonic and the extra character on the title screen
This isn't necessarily related to improving the extra character itself per se, but this part of the guide will show you how to easily switch between Sonic and your extra character on the title screen for better convenience.
If we take a look back at the code for selecting the extra character on the title screen, we can see the following code that we just set up in the guide:
Title_CheckForB:
cmpi.b #$10,($FFFFF605).w ; has B been pressed?
bne.s StartCheck ; if not, branch
Title_SecondCharacter:
move.b #1,($FFFFFFF9).w ; set the multiple character flag to $01 (indicating Metal Sonic)
move.b #$B5,d0 ; put value of ring sound into d0
bsr.w PlaySound_Special ; jump to the subroutine that plays the sound currently in d0 ($B5, at the moment)
StartCheck:
Here we can see that the extra character flag is set when B is pressed, which would allow for us to select our extra character. However, if we press B again, it would produce the same result as when hitting B for the first time on the title screen, meaning that there is no way to return back to Sonic.
To rectify this, we need to add in some additional code so that we can provide a solution for switching back to Sonic when B is pressed again after selecting our extra character, which would also allow us to switch back to our extra character and vice versa.
So head over to 'Title_SecondCharacter:', and underneath the label, add this in:
cmpi.b #1,($FFFFFFF9).w ; is the multiple character flag set to 1 (Metal Sonic)?
beq.s Title_RevertCharacter ; if yes, branch
And after 'bsr.w PlaySound_Special', add this in:
bra.s StartCheck ; branch to rest of code
So now the code will look like this when finished:
Title_SecondCharacter:
cmpi.b #1,($FFFFFFF9).w ; is the multiple character flag set to 1 (Metal Sonic)?
beq.s Title_RevertCharacter ; if yes, branch
move.b #1,($FFFFFFF9).w ; set the multiple character flag to $01 (indicating Metal Sonic)
move.b #$B5,d0 ; put value of ring sound into d0
bsr.w PlaySound_Special ; jump to the subroutine that plays the sound currently in d0 ($B5, at the moment)
bra.s StartCheck ; branch to rest of code
Now we need to provide code for switching back to Sonic. Make a new subroutine as shown below and put it underneath the 'Title_SecondCharacter:' subroutine. Here's what it should look like:
Title_SecondCharacter:
cmpi.b #1,($FFFFFFF9).w ; is the multiple character flag set to 1 (Metal Sonic)?
beq.s Title_RevertCharacter ; if yes, branch
move.b #1,($FFFFFFF9).w ; set the multiple character flag to $01 (indicating Metal Sonic)
move.b #$B5,d0 ; put value of ring sound into d0
bsr.w PlaySound_Special ; jump to the subroutine that plays the sound currently in d0 ($B5, at the moment)
bra.s StartCheck ; branch to rest of code
Title_RevertCharacter:
move.b #0,($FFFFFFF9).w ; set the multiple character flag to $00 (indicating Sonic)
move.b #$C9,d0 ; put value of ring sound into d0
bsr.w PlaySound_Special ; jump to the subroutine that plays the sound currently in d0 ($C9, at the moment)
As you can see, the bottom check is similar to what we have set earlier on in the guide, but this time it's resetting the flag at $FFFFFFF9 back to zero. The hidden score tally sound is also played (which is $C9 in the sound test) instead of the ring sound, to better indicate that our character is now Sonic rather than our extra character. Again, you can change the sound it plays by changing $C9 to whatever sound test value you should play.
And with that, we now have the ability to switch between Sonic and our extra character just by pressing B on the title screen.
Conclusion
And that's all you need to improve your extra characters in your hacks! Everything else is up to you to take your characters to the next level, whether that would be providing the complete set of art, mappings, DPLCs, etc., for each and every part of your character throughout the game such as the proper palettes in the Special Stages, new sprites in the Ending Sequence and others, as well as giving your characters new abilities. Have fun with your new characters!
|Add Extra Characters]]