Actions

SCHG How-to

Create Clone and Special Stage Monitors

From Sonic Retro

Revision as of 13:49, 25 April 2011 by Tamkis (talk | contribs) (A Guide on how to create a Clone and Special Stage monitor)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

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:


<asm> 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 </asm>

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:

<asm> qmark_monitor: addq.w #1,(a2) rts </asm>

Replace it with this:

<asm> 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 </asm>

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

<asm>

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
====================================

</asm>

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

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

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

<asm> 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 </asm>

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:

<asm>

---------------------------------------------------------------------------
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 </asm>

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:

<asm> 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 </asm>

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

<asm> 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 </asm>

Change it to this:

<asm> 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 </asm>

Underneath “teleport_monitor”, add this:

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

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

<asm> 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 </asm>

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