Actions

SCHG How-to

Create Clone and Special Stage Monitors

From Sonic Retro

This guide will show you how to make two new monitors for Sonic 2, which are a Clone monitor and a Special Stage monitor, both which are featured in my hack, Sonic 2 Loco. Please give credit to me if you use these new monitors. For our purposes, we will be using the Nov 2010 .svn disasm, though, I’m sure these modifications will work with slightly older S2 disasms.


In a Sonic and Tails game OR Sonic-alone game, the clone monitor will enable a flag which will allow Sonic to call an extra Tails character upon pressing A while on the ground (at the expense of using 10 rings). Hitting the clone monitor will give the player a free Tails character. Upon pressing A and if Sonic has at least 10 rings, Sonic will display his unused “Whistle” sprites from Sonic 3, and a Tails character will appear at Sonic’s X and Y coordinates. If Sonic does not have at least 10 rings, the “buzzer” sound effect will play, and nothing will happen.

This extra Tails character interacts with chunks, monitors, and enemies/bosses, but not with other objects. Moreover, the mappings of the extra Tails characters will be garbled. (Making the extra Tails characters interact with other objects and fixing the mappings would need an extreme rewrite of the Sonic 2 Engine to handle multiple Tails objects, which I didn’t feel like doing.)

This monitor will not work in a Tails-alone game, because even if you try to force the game to load a Sonic object at Tails X and Y coordinates, an extra Tails object will appear instead. (In a Tails-along game, if any extra Tails object dies, you die!). Keeping this fact in mind, it is strongly recommended to make this monitor do something different in a Tails-alone game.


The Special Stage monitor, upon being hit, will launch the player into the special stage, like if he hit a starpost with 50 rings. Moreover, if the player has all 7 emeralds, this monitor will give the player 50 rings. Using this monitor is a good alternative to allowing the player to enter the special stage by starposts, and is similar to the Special Stage monitor in Sonic SMS games. Since the monitor does not save your position, it is strongly recommended to put a checkpoint before the Special stage monitor. This guide will also show how to disable the starposts for entering the special stage.


Creating a clone monitor:

For our purposes, we will be using the question mark monitor, which is unused in the main game. If you would like, you can use SonMapEd to change the question mark monitor’s icon to an appropriate one, say the Tails 1-up icon.

First, goto “Obj2E_Types”. You should see something like this:


Obj2E_Types:	offsetTable
		offsetTableEntry.w robotnik_monitor		; 0 - Static
		offsetTableEntry.w sonic_1up			; 1 - Sonic 1-up
		offsetTableEntry.w tails_1up			; 2 - Tails 1-up
		offsetTableEntry.w robotnik_monitor		; 3 - Robotnik
		offsetTableEntry.w super_ring			; 4 - Super Ring
		offsetTableEntry.w super_shoes		; 5 - Speed Shoes
		offsetTableEntry.w shield_monitor		; 6 - Shield
		offsetTableEntry.w invincible_monitor	; 7 - Invince
		offsetTableEntry.w teleport_monitor		; 8 - Teleport
		offsetTableEntry.w qmark_monitor		; 9 - ? mark

Next, goto “qmark_monitor”. Since the Special Stage monitor will replace the teleport monitor, I have used the “teleport_flag” variable as our flag for the Clone monitor. If you have extra space in s2.constants.asm, you could use a user-made flag if you would like.

Under “qmark_monitor”, you should see something like this:

qmark_monitor:
	addq.w	#1,(a2)
	rts

Replace it with this:

qmark_monitor:	;**
	move.b	#1,(Teleport_flag).w	;Used as Clone flag

	cmpi.w	#2,(Player_mode).w	;If it is a Tails alone game, do nothing
	beq.s	+

	bsr.w	SingleObjLoad		;Load a Tails object at...
	bne.w	+
	move.b	#2,id(a1)
	move.w	(MainCharacter+x_pos).w,x_pos(a1)	;Sonic's X pos
	move.w	(MainCharacter+y_pos).w,y_pos(a1)	;Sonic's y pos
	move.w	#MusID_ExtraLife,d0			;Play extra life music
	jmp	(PlayMusic).l
+
	rts

Next, goto “Obj01_MdNormal”. You should see something like this:

; loc_1A2B8:
Obj01_MdNormal:
	bsr.w	Sonic_CheckSpindash
	bsr.w	Sonic_Jump
	bsr.w	Sonic_SlopeResist
	bsr.w	Sonic_Move
	bsr.w	Sonic_Roll
	bsr.w	Sonic_LevelBound
	jsr	(ObjectMove).l
	bsr.w	AnglePos
	bsr.w	Sonic_SlopeRepel

return_1A2DE:
	rts
; End of subroutine Obj01_MdNormal
; ====================================

Add this before all of the “bsr.w” jumps:

	btst	#button_A,(Ctrl_1_Press).w		;** is A being pressed for whistle?
	bne.w	Sonic_Whistle				;**If yes, branch

After the end of subroutine “Obj01_MdNormal”, add this subfunction:

Sonic_whistle:	;**

	cmpi.w		#2,(Player_mode).w	;Is it NOT a Tails only game?
	beq.s	+				;If it is a Tails-only game, branch

	tst.b	(Teleport_flag).	w	; is clone flag enabled?
	beq.s	+		 		; if not, branch

	cmpi.w		#10,(Ring_count).w	; does Sonic have at least 10 rings?
	blo.s	+				; if not, branch
	
	sub.w	#10,(Ring_count).w		;Subtract 10 rings
	ori.b	#1,(Update_HUD_rings).w	; set flag to update ring counter in the HUD

	move.b	#AniIDSonAni_Whistle,anim(a0)	;Run whistle animation (optional)

	bsr.w	SingleObjLoad			
	bne.w	+
	move.b	#2,id(a1)					;Load Tails clone at...
	move.w	(MainCharacter+x_pos).w,x_pos(a1)	;Sonic's x pos
	move.w	(MainCharacter+y_pos).w,y_pos(a1)	;Sonic's y pos

	move.w	#SndID_Sparkle,d0	;Play sparkle sfx
	jsr	(PlaySound).l	
	rts
+
	move.w	#SndID_Error,d0	;Play buzzer sfx
	jsr	(PlaySound).l
	rts

Optionally, you can make Sonic run the unused whistle animation from Sonic 3. Using SonMapEd, add the three sprites at $E5, $E6, and $E7, or wherever you find room. Then, goto “SonicAniData” (or “off_1B618”) and add an offset table entry. Next, define the animation for the whistle sprites.

Sample:

; ---------------------------------------------------------------------------
; Animation script - Sonic
; ---------------------------------------------------------------------------
; off_1B618:
SonicAniData:				offsetTable
SonAni_Walk_ptr:			offsetTableEntry.w SonAni_Walk	;  0 ;   0
SonAni_Run_ptr:			offsetTableEntry.w SonAni_Run	;  1 ;   1
;…
SonAni_Whistle_ptr:			offsetTableEntry.w SonAni_Whistle	; 35 ; $23**

SonAni_Walk:	 dc.b 	$FF, $F,$10,$11,$12,$13,$14, $D, $E,$FF
SonAni_Run: dc.b	$FF,$2D,$2E,$2F,$30,$FF,$FF,$FF,$FF,$FF
;…
SonAni_Whistle: dc.b $2F, $E5,$E6,$E7,$FF;**
	Even

Now you have a working clone monitor!


Creating a Special stage monitor:

For our purposes, we will be using the teleport monitor, which is unused in a story mode game. If you would like, you can use SonMapEd to change the teleport monitor’s icon to an appropriate one, say an emerald icon.

First, goto “Obj2E_Types”. You should see something like this:

Obj2E_Types:	offsetTable
		offsetTableEntry.w robotnik_monitor		; 0 - Static
		offsetTableEntry.w sonic_1up			; 1 - Sonic 1-up
		offsetTableEntry.w tails_1up			; 2 - Tails 1-up
		offsetTableEntry.w robotnik_monitor		; 3 - Robotnik
		offsetTableEntry.w super_ring			; 4 - Super Ring
		offsetTableEntry.w super_shoes		; 5 - Speed Shoes
		offsetTableEntry.w shield_monitor		; 6 - Shield
		offsetTableEntry.w invincible_monitor	; 7 - Invince
		offsetTableEntry.w teleport_monitor		; 8 - Teleport
		offsetTableEntry.w qmark_monitor		; 9 - ? mark

Next, goto “teleport_monitor”. You should see something like this:

teleport_monitor:
	addq.w	#1,(a2)
	cmpi.b	#6,(MainCharacter+routine).w	; is player 1 dead or respawning?
	bhs.s	+				; if yes, branch
	cmpi.b	#6,(Sidekick+routine).w		; is player 2 dead or respawning?
	blo.s	swap_players			; if not, branch
+	; can't teleport if either player is dead
	rts

Change it to this:

teleport_monitor:	;** SS monitor
	cmpi.b	#7,(Emerald_count).w		;Does main character have all 7 emeralds?
	bne.s	warp_toSS			;If not, branch to goto Special Stage
	jsr	super_ring			;give 10 rings
	jsr	super_ring
	jsr	super_ring
	jsr	super_ring
	jsr	super_ring			;=total of 10 rings
	rts

Underneath “teleport_monitor”, add this:

warp_toSS:
	move.b	#1,(unk_F7CD).w
	move.b	#GameModeID_SpecialStage,(Game_Mode).w ; => SpecialStage
	rts

Lastly, to disable entering the special stage by starposts, goto “Obj79_CheckActivation:” and change it to this:

Obj79_CheckActivation:
	andi.b	#$7F,d1
	move.b	subtype(a0),d2
	andi.b	#$7F,d2
	cmp.b	d2,d1
	bhs.w	loc_1F222
	move.w	x_pos(a3),d0
	sub.w	x_pos(a0),d0
	addi.w	#8,d0
	cmpi.w	#$10,d0
	bhs.w	return_1F220
	move.w	y_pos(a3),d0
	sub.w	y_pos(a0),d0
	addi.w	#$40,d0
	cmpi.w	#$68,d0
	bhs.w	return_1F220
	move.w	#SndID_Checkpoint,d0 ; checkpoint ding-dong sound
	jsr	(PlaySound).l
	jsr	(SingleObjLoad).l
	bne.s	loc_1F206
	_move.b	#ObjID_Starpost,id(a1) ; load obj79
	move.b	#6,routine(a1) ; => Obj79_Dongle
	move.w	x_pos(a0),objoff_30(a1)
	move.w	y_pos(a0),objoff_32(a1)
	subi.w	#$14,objoff_32(a1)
	move.l	mappings(a0),mappings(a1)
	move.w	art_tile(a0),art_tile(a1)
	move.b	#4,render_flags(a1)
	move.b	#8,width_pixels(a1)
	move.b	#4,priority(a1)
	move.b	#2,mapping_frame(a1)
	move.w	#$20,objoff_36(a1)
	move.w	a0,parent(a1)
	;tst.w	(Two_player_mode).w
	;bne.s	loc_1F206
	;cmpi.b	#7,(Emerald_count).w
	;beq.s	loc_1F206
	;cmpi.w	#50,(Ring_count).w
	;blo.s	loc_1F206
	;**	bsr.w	Obj79_MakeSpecialStars

You now have disabled the starposts, and have created a special stage monitor! Enjoy your new monitors, and don’t forget to credit me, Tamkis

SCHG How-To Guide: Sonic the Hedgehog 2 (16-bit)
Fixing Bugs
Fix Demo Playback | Fix a Race Condition with Pattern Load Cues | Fix Super Sonic Bugs | Use Correct Height When Roll Jumping | Fix Jump Height Bug When Exiting Water | Fix Spin Dash Code and Add Spin Dash Speeds | Fix Screen Boundary Spin Dash Bug | Correct Drowning Bugs | Fix Camera Y Position for Tails | Fix Tails Subanimation Error | Fix Tails' Respawn Speeds | Fix Accidental Deletion of Scattered Rings | Fix Ring Timers | Fix Rexon Crash | Fix Monitor Collision Bug | Fix EHZ Deformation Bug | Correct CPZ Boss Attack Behavior | Fix Bug in ARZ Boss Arrow's Platform Behavior | Fix ARZ Boss Walking on Air Glitch | Fix ARZ Boss Sprite Behavior | Fix Multiple CNZ Boss Bugs | Fix HTZ Background Scrolling Mountains | Fix OOZ Launcher Speed Up Glitch | Fix DEZ Giant Mech Collision Glitch | Fix Boss Deconstruction Behavior | Fix Speed Bugs
Design Choices
Remove the Air Speed Cap | Disable Floor Collision While Dying | Modify Super Sonic Transformation Methods & Behavior | Enable/Disable Tails in Certain Levels | Collide with Water After Being Hurt | Retain Rings When Returning at a Star Post | Improve the Fade In\Fade Out Progression Routines | Fix Scattered Rings' Underwater Physics | Insert LZ Water Ripple Effect | Restore Lost CPZ Boss Feature | Prevent SCZ Tornado Spin Dash Death | Improve ObjectMove Subroutines | Port S3K Rings Manager | Port S3K Object Manager | Port S3K Priority Manager | Edit Level Order with ASM‎ | Alter Ring Requirements in Special Stages | Make Special Stage Characters Use Normal DPLCs | Speed Up Ring Loss Process
Adding Features
Create Insta-kill and High Jump Monitors | Create Clone and Special Stage Monitors | Port Knuckles
Sound Features
Port Sonic 1 Sound Driver | Port Sonic 2 Clone Driver | Port Sonic 3 Sound Driver | Expand the Music Index to Start at $00 (Sonic 2 Clone Driver Version)
Extending the Game
Extend the Level Index Past $10 | Extend the Level Select | Extend Water Tables | Add Extra Characters | Free Up 2 Universal SSTs