Actions

SCHG How-to

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.

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 (recommended)

These optional (but recommended) improvements are here for you to distinguish your new character(s) from Sonic (or any other main character) even more. This gives 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!

SCHG How-To Guide: Sonic the Hedgehog (16-bit)
Fixing Bugs
Fix Demo Playback | Fix a Race Condition with Pattern Load Cues | Fix the SEGA Sound | Display the Press Start Button Text | Fix the Level Select Menu | Fix the Hidden Points Bug | Fix Accidental Deletion of Scattered Rings | Fix Ring Timers | Fix the Walk-Jump Bug | Correct Drowning Bugs | Fix the Death Boundary Bug | Fix the Camera Follow Bug | Fix Song Restoration Bugs | Fix the HUD Blinking | Fix the Level Select Graphics Bug | Fix a remember sprite related bug
Changing Design Choices
Change Spike Behavior | Collide with Water After Being Hurt | Fix Special Stage Jumping Physics | Improve the Fade In\Fade Out Progression Routines | Fix Scattered Rings' Underwater Physics | Remove the Speed Cap | Port the REV01 Background Effects | Port Sonic 2's Level Art Loader | Retain Rings Between Acts | Add Sonic 2 (Simon Wai Prototype) Level Select | Improve ObjectMove Subroutines | Add Sonic 2 Level Select | Collide with Water After Being Hurt | Smooth Out Rotation in Special Stages
Adding Features
Add Spin Dash ( Part 1 (GitHub)/(Hivebrain) / Part 2 / Part 3 / Part 4 ) | Add Eggman Monitor | Add Super Sonic | Add Extended Camera | Add the Air Roll | Add 6-Button Support
Sound Features
Expand the Sound Index | Play Different Songs Per Act | Port Sonic 2 Final Sound Driver | Port Sonic 3's Sound Driver | Change The SEGA Sound | Correct PAL Music Tempo
Extending the Game
Load Chunks From ROM | Add Extra Characters | Make an Alternative Title Screen | Use Dynamic Tilesets | Make GHZ Load Alternate Art | Make Ending Load Alternate Art | Add a New Zone | Set Up the Goggle Monitor | Add New Moves | Add a Dynamic Collision System | Dynamic Special Stage Walls System | Extend Sprite Mappings and Art Limit | Enigma Credits | Use Dynamic Palettes
Miscellaneous
Convert the Hivebrain 2005 Disassembly to ASM68K
Split Disassembly Guides
Set Up a Split Disassembly | Basic Level Editing | Basic Art Editing | Basic ASM Editing (Spin Dash)

|Add Extra Characters]]