Actions

SCHG How-to

Add New Monitors

From Sonic Retro

Let's say you want another monitor. I've given the monitor files a once-over, and found an easy way to free up 10 monitors, the 'S', the Goggles, the Blank, and 7 "invalid" monitors. 2 notes before we begin: This uses the HV build, and I will mention this later, but whenever you want to input more art through SonMapED you HAVE to open up the file Monitors under the folder _maps and add the label map_monitor: to the file before the first piece of code.

Sonic 1:

Step 1: _incObj\2E Monitor Content Power-Up.asm

Find the following code:

Pow_ChkS:
		cmpi.b	#7,d0		; does monitor contain 'S'?
		bne.s	Pow_ChkEnd
		nop	

Pow_ChkEnd:
		rts			; 'S' and goggles monitors do nothing

Replace it with this template:

Pow_ChkS:
		cmpi.b	#7,d0		; does monitor contain 'S'?
		bne.s	Pow_ChkGoggles

		nop ;Insert code here.
; ===========================================================================

Pow_ChkGoggles: ;The Goggles monitor still does nothing.
		cmpi.b	#8,d0		; does monitor contain goggles?
		bne.s	Pow_ChkInvalid1

		nop ;Insert code here.
; ==========================================================================

Pow_ChkInvalid1:
		cmpi.b	#9,d0		; Is this the 1st invalid monitor?
		bne.s	Pow_ChkInvalid2

		nop ;Insert code here.
; ==========================================================================

Pow_ChkInvalid2:
		cmpi.b	#$A,d0		; Is this the 2nd invalid monitor?
		bne.s	Pow_ChkInvalid3

		nop ;Insert code here.
; ==========================================================================

Pow_ChkInvalid3:
		cmpi.b	#$B,d0		; Is this the 3rd invalid monitor?
		bne.s	Pow_ChkInvalid4

		nop ;Insert code here.
; ==========================================================================

Pow_ChkInvalid4:
		cmpi.b	#$C,d0		; Is this the 4th invalid monitor?
		bne.s	Pow_ChkInvalid5

		nop ;Insert code here.
; ==========================================================================

Pow_ChkInvalid5:
		cmpi.b	#$D,d0		; Is this the 5th invalid monitor?
		bne.s	Pow_ChkInvalid6

		nop ;Insert code here.
; ==========================================================================

Pow_ChkInvalid6:
		cmpi.b	#$E,d0		; Is this the 6th invalid monitor?
		bne.s	Pow_ChkInvalid7

		nop ;Insert code here.
; ==========================================================================

Pow_ChkInvalid7:
		cmpi.b	#$F,d0		; Is this the 7th invalid monitor?
		bne.s	Pow_ChkBlank

		nop ;Insert code here.
; ==========================================================================

Pow_ChkBlank:
		cmpi.b	#0,d0		; Is this the blank monitor?
		bne.s	Pow_ChkEnd

		nop ;Insert code here.
; ==========================================================================

Pow_ChkEnd:
		rts
; ===========================================================================

Now you can use the Eggman monitor (before the rest of the monitors in the code), the 'S' monitor, the Goggles monitor, the 7 invalid monitors, and the Blank monitor. There's just a few problems: the invalid monitors havs glitchy graphics, they don't flash like the other ones, AND when we destroy them it shows the "S" monitor instead of the broken one.


Step 2: _maps\Monitor.asm

Now, let's worry about fixing some mapping errors.

Delete everything in the file and paste this in.

; --------------------------------------------------------------------------------
; Sprite mappings - output from SonMapEd - Sonic 1 format
; --------------------------------------------------------------------------------

SME_TP0l7:	
map_monitor:
		dc.w SME_TP0l7_1A-SME_TP0l7, SME_TP0l7_20-SME_TP0l7	
		dc.w SME_TP0l7_2B-SME_TP0l7, SME_TP0l7_36-SME_TP0l7	
		dc.w SME_TP0l7_41-SME_TP0l7, SME_TP0l7_4C-SME_TP0l7	
		dc.w SME_TP0l7_57-SME_TP0l7, SME_TP0l7_62-SME_TP0l7	
		dc.w SME_TP0l7_6D-SME_TP0l7, SME_TP0l7_78-SME_TP0l7	
		dc.w SME_TP0l7_83-SME_TP0l7, SME_TP0l7_8E-SME_TP0l7	
		dc.w SME_TP0l7_99-SME_TP0l7	
SME_TP0l7_1A:	dc.b 1	
		dc.b $EF, $F, 0, 0, $F0	
SME_TP0l7_20:	dc.b 2	
		dc.b $F5, 5, 0, $10, $F8	
		dc.b $EF, $F, 0, 0, $F0	
SME_TP0l7_2B:	dc.b 2	
		dc.b $F5, 5, 0, $14, $F8	
		dc.b $EF, $F, 0, 0, $F0	
SME_TP0l7_36:	dc.b 2	
		dc.b $F5, 5, 0, $18, $F8	
		dc.b $EF, $F, 0, 0, $F0	
SME_TP0l7_41:	dc.b 2	
		dc.b $F5, 5, 0, $1C, $F8	
		dc.b $EF, $F, 0, 0, $F0	
SME_TP0l7_4C:	dc.b 2	
		dc.b $F5, 5, 0, $24, $F8	
		dc.b $EF, $F, 0, 0, $F0	
SME_TP0l7_57:	dc.b 2	
		dc.b $F5, 5, 0, $28, $F8	
		dc.b $EF, $F, 0, 0, $F0	
SME_TP0l7_62:	dc.b 2	
		dc.b $F5, 5, 0, $2C, $F8	
		dc.b $EF, $F, 0, 0, $F0	
SME_TP0l7_6D:	dc.b 2	
		dc.b $F5, 5, 0, $30, $F8	
		dc.b $EF, $F, 0, 0, $F0	
SME_TP0l7_78:	dc.b 2	
		dc.b $F5, 5, 0, $34, $F8	
		dc.b $EF, $F, 0, 0, $F0	
SME_TP0l7_83:	dc.b 2	
		dc.b $F5, 5, 0, $20, $F8	
		dc.b $EF, $F, 0, 0, $F0	
SME_TP0l7_8E:	dc.b 2	
		dc.b $F5, 5, 0, $40, $F8	
		dc.b $EF, $F, 0, 0, $F0	
SME_TP0l7_99:	dc.b 1	
		dc.b $FF, $D, 0, $38, $F0	
		even

Yeah I know the labels don't look pretty, but at least they work. This adds an extra monitor sprite before the breaking one. You will also need to add some new sprites through SonMapED so you can see it. (or else it will look like a blank monitor)

So now we have one new monitor.

I want to point out a line of code near the top, the one that says "map_monitor". This links from a lot of over places throughout the ROM and if this label wasn't here it wouldn't know where you go and you would get a build error. So every time you use SonMapED you need to REINSERT THAT LABEL!

Step 3: _anim\Monitor.asm

This is a small file so I want you to take a gander at the beginning, see how the labels correspond to the labels in the list at the top of the file?

This is the animation linking (what tells the monitors to flash) notice how "breaking" monitor only has one animation.

Also see how the Eggman monitor is listed 1, 0, 3, 3, 1, 3, 3, 2, 3, 3, and then the Sonic monitor is 1, 0, 4, 4, 1, 4, 4, 2, 4, 4, the shoes are 5, 5, 5, 5, ect.

Now right before "@breaking:" insert this coding:

@Invalid_1:	dc.b 1,	0, $B, $B, 1, $B, $B, 2, $B, $B, afEnd
		even

Now add to the pointer in the index at the top of the file. Replace this line.

dc.w   @breaking-Ani_Monitor

with this one

dc.w  @Invalid_1-Ani_Monitor, @breaking-Ani_Monitor

And then change the $B to a $C in the line "@breaking:"

If you did it right, it should look like this.

; ; ---------------------------------------------------------------------------
; Animation script - monitors
; ---------------------------------------------------------------------------
Ani_Monitor:	dc.w @static-Ani_Monitor, @eggman-Ani_Monitor, @sonic-Ani_Monitor
		dc.w @shoes-Ani_Monitor, @shield-Ani_Monitor, @invincible-Ani_Monitor
		dc.w @rings-Ani_Monitor, @s-Ani_Monitor, @goggles-Ani_Monitor
		dc.w @Invalid_1-Ani_Monitor, @breaking-Ani_Monitor
@static:	dc.b 1,	0, 1, 2, afEnd
		even
@eggman:	dc.b 1,	0, 3, 3, 1, 3, 3, 2, 3,	3, afEnd
		even
@sonic:		dc.b 1,	0, 4, 4, 1, 4, 4, 2, 4,	4, afEnd
		even
@shoes:		dc.b 1,	0, 5, 5, 1, 5, 5, 2, 5,	5, afEnd
		even
@shield:	dc.b 1,	0, 6, 6, 1, 6, 6, 2, 6,	6, afEnd
		even
@invincible:	dc.b 1,	0, 7, 7, 1, 7, 7, 2, 7,	7, afEnd
		even
@rings:		dc.b 1,	0, 8, 8, 1, 8, 8, 2, 8,	8, afEnd
		even
@s:		dc.b 1,	0, 9, 9, 1, 9, 9, 2, 9,	9, afEnd
		even
@goggles:	dc.b 1,	0, $A, $A, 1, $A, $A, 2, $A, $A, afEnd
		even
@Invalid_1:	dc.b 1,	0, $B, $B, 1, $B, $B, 2, $B, $B, afEnd
		even			
@breaking:	dc.b 2,	0, 1, 2, $C, afBack, 1
		even

And now your monitors all work right! Except they look like your new monitor when destroyed...


Step 4: Errors

Open up 26 Monitor.asm under the folder _incObj Search for "move.b #9,obAnim(a0)" and replace it with "move.b #10,obAnim(a0)". Now your monitors will display the correct mappings after being destroyed. We had 9 monitors to begin with + 1 new one = 10, simple.

But when we get to far away from the monitor and re-approach it....

It shows our new sprite instead of the broken one. To fix this, find the line
	move.b	#$B,obFrame(a0)	; use broken monitor frame
and change the $B to a $C.

Now assemble the code and...what? The code doesn't work and the ROM refuses to assemble.

It's because of the added code. Now Some branches are now to far away to work.

Let's fix that. Open up Sub SolidObject in the _incObj folder and change all the instances of

bsr.w MvSonicOnPtfm

to

jsr    MvSonicOnPtfm


Then open up 89 Ending Sequence STH in the same folder and change all the instances of

bra.w     DisplaySprite

to

jmp     DisplaySprite


Step 5: SonED2 Projects\objdef\s1obj.lst

You now have 1 new monitor. But when you try and place them in SonED 2, you notice that all the "invalid" monitors are labeled "Invalid". How do you know which one's which? You could remember how many times you've pressed the 1 key, or or could have it tell you.Search for " Description: Monitor". Now scroll down until you see " Desc 9: Invalid". Now change that to Invalid 1, the one below to Invalid 2, etc... Now you can tell which monitor is which. Of course, if you have a function for that monitor, you can actually just type it's function, such as "Infinite Speed Shoes" or "50 Rings".

Step 6: Adding More monitors

So we added one monitor. To add more, do the same as above starting form step 3 BUT you need to pay attention to the animations script. you NEED to add 1 to the digit before "afBack" on the line with "@breaking:" and insert your monitor code BEFORE the "@breaking:" and add another label to the index. (you can only have up to three labels per line so you might need to add a new line)

Also to add the Sprites, use SonMapEd

And if you're adding the spindash to you're hack I recommend you add A checkpoint monitor.

Sonic 2 INCOMPLETE!:

by Bombchu Link

Step 1:

Open up s2.asm and search for off_12924:

You should see this.

; ============== RELATIVE POINTER LIST     ==================================
off_12924:
	dc.w robotnik_monitor-off_12924	; 0 - Static
	dc.w sonic_1up-off_12924	; 1 - Sonic 1-up
	dc.w tails_1up-off_12924	; 2 - Tails 1-up
	dc.w robotnik_monitor-off_12924	; 3 - Robotnik
	dc.w super_ring-off_12924	; 4 - Super Ring
	dc.w super_shoes-off_12924	; 5 - Speed Shoes
	dc.w shield_monitor-off_12924	; 6 - Shield
	dc.w invincible_monitor-off_12924; 7 - Invincibility
	dc.w loc_12AA6-off_12924	; 8 - Teleport
	dc.w qmark_monitor-off_12924	; 9 - Question mark

at the end add this line.

dc.w Invalid_1-off_12924	; A - Invalid 1

now scroll down until you see this line.

; ===========================================================================

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

Now below it add these lines.

Invalid_1:

nop  ;insert your code here
rts

This adds the monitor, but it does nothing. let's use Hayate's Insta Kill monitor instead.

Invalid_1:                  ; made by Hayate
        addq.w    #1,(a2)
	movea.l    a0,a1
	lea    ($FFFFB000).w,a0
	jsr    (KillCharacter).l
	movea.l    a1,a0
	rts

Save and assemble the code and oh dear...

[picture_1.png]

It's showing a broken monitor instead of a full one... and it doesn't flash either... but at least it kills sonic when he hits it.

Now unless you plan to implement some cruel joke in your mod, we need to give the monitor a new sprite.

Open SonMapEd and insert a sprite right before the broken monitor with the icon on the face that you want. (Be sure to add your new art to the END of the tileset.)

Now save your mapping and art and assemble.

[picture_2.png]

What the?!

Now the rings are messed up!

Anyway, just go over and look at your monitor, it should show your new graphic.

[picture_3]

success.

But wait, when we destroy other monitors it shows out new monitor instead of the broken one.

What ever shall we do?!

First thing first, fix the error when we destroy a monitor and get the wrong sprite.

--Sorry, this guide isn't complete yet, hopefully I'll make this step really soon.--

There is also another error. When we approach the monitor after destroying it, our new monitor returns to haunt us. To fix this jump to obj_26_sub_0: in s2.asm and look at this nibble of code near the end of the function

	move.b	#8,routine(a0)
        move.b	#$B,mapping_frame(a0)

change it to this

	move.b	#8,routine(a0)
        move.b	#$C,mapping_frame(a0)

We increased the mapping frame by one because we inserted a frame before the broken monitor.


Now let's make the monitor actually flash like all the others.

In s2.asm jump to Ani_obj26: and look at the following code.

; animation script
; off_12CCE:
Ani_obj26:
	dc.w byte_12CE4-Ani_obj26; frame 0
	dc.w byte_12CE8-Ani_obj26; 1
	dc.w byte_12CF0-Ani_obj26; 2
	dc.w byte_12CF8-Ani_obj26; 3
	dc.w byte_12D00-Ani_obj26; 4
	dc.w byte_12D08-Ani_obj26; 5
	dc.w byte_12D10-Ani_obj26; 6
	dc.w byte_12D18-Ani_obj26; 7
	dc.w byte_12D20-Ani_obj26; 8
	dc.w byte_12D28-Ani_obj26; 9
	dc.w byte_12D30-Ani_obj26; 10

byte_12CE4:
	dc.b	$01	; duration
	dc.b	$00	; frame number (which sprite table to use)
	dc.b	$01	; frame number
	dc.b	$FF	; terminator
byte_12CE8:	dc.b   1,  0,  2,  2,  1,  2,  2,$FF
byte_12CF0:	dc.b   1,  0,  3,  3,  1,  3,  3,$FF
byte_12CF8:	dc.b   1,  0,  4,  4,  1,  4,  4,$FF
byte_12D00:	dc.b   1,  0,  5,  5,  1,  5,  5,$FF
byte_12D08:	dc.b   1,  0,  6,  6,  1,  6,  6,$FF
byte_12D10:	dc.b   1,  0,  7,  7,  1,  7,  7,$FF
byte_12D18:	dc.b   1,  0,  8,  8,  1,  8,  8,$FF
byte_12D20:	dc.b   1,  0,  9,  9,  1,  9,  9,$FF
byte_12D28:	dc.b   1,  0, $A, $A,  1, $A, $A,$FF
byte_12D30:	dc.b   2,  0,  1, $B,$FE,  1
	even

replace it with this.

; animation script
; off_12CCE:
Ani_obj26:
	dc.w byte_12CE4-Ani_obj26; frame 0
	dc.w byte_12CE8-Ani_obj26; 1
	dc.w byte_12CF0-Ani_obj26; 2
	dc.w byte_12CF8-Ani_obj26; 3
	dc.w byte_12D00-Ani_obj26; 4
	dc.w byte_12D08-Ani_obj26; 5
	dc.w byte_12D10-Ani_obj26; 6
	dc.w byte_12D18-Ani_obj26; 7
	dc.w byte_12D20-Ani_obj26; 8
	dc.w byte_12D28-Ani_obj26; 9
	dc.w byte_12D30-Ani_obj26; 10
	dc.w byte_12D32-Ani_obj26; 11
byte_12CE4:
	dc.b	$01	; duration
	dc.b	$00	; frame number (which sprite table to use)
	dc.b	$01	; frame number
	dc.b	$FF	; terminator
byte_12CE8:	dc.b   1,  0,  2,  2,  1,  2,  2,$FF
byte_12CF0:	dc.b   1,  0,  3,  3,  1,  3,  3,$FF
byte_12CF8:	dc.b   1,  0,  4,  4,  1,  4,  4,$FF
byte_12D00:	dc.b   1,  0,  5,  5,  1,  5,  5,$FF
byte_12D08:	dc.b   1,  0,  6,  6,  1,  6,  6,$FF
byte_12D10:	dc.b   1,  0,  7,  7,  1,  7,  7,$FF
byte_12D18:	dc.b   1,  0,  8,  8,  1,  8,  8,$FF
byte_12D20:	dc.b   1,  0,  9,  9,  1,  9,  9,$FF
byte_12D28:	dc.b   1,  0, $A, $A,  1, $A, $A,$FF
byte_12D30:	dc.b   1,  0, $B, $B,  1, $B, $B,$FF
byte_12D32:	dc.b   2,  0,  1, $C,$FE,  1
	even


Now let's fix that nasty ring error now. in s2.asm search for ChangeRingFrame: and you should see this.

; ---------------------------------------------------------------------------
; Subroutine to change global object animation variables (like rings)
; ---------------------------------------------------------------------------

; ||||||||||||||| S U B R O U T I N E |||||||||||||||||||||||||||||||||||||||

; sub_4B64:
ChangeRingFrame:
	subq.b	#1,(Logspike_anim_counter).w
	bpl.s	+
	move.b	#$B,(Logspike_anim_counter).w
	subq.b	#1,(Logspike_anim_frame).w ; animate unused log spikes
	andi.b	#7,(Logspike_anim_frame).w
+
	subq.b	#1,(Rings_anim_counter).w
	bpl.s	+
	move.b	#7,(Rings_anim_counter).w
	addq.b	#1,(Rings_anim_frame).w ; animate rings in the level (obj25)
	andi.b	#3,(Rings_anim_frame).w
+
	subq.b	#1,(Unknown_anim_counter).w
	bpl.s	+
	move.b	#7,(Unknown_anim_counter).w
	addq.b	#1,(Unknown_anim_frame).w ; animate nothing (deleted special stage object is my best guess)
	cmpi.b	#6,(Unknown_anim_frame).w
	bcs.s	+
	move.b	#0,(Unknown_anim_frame).w
+
	tst.b	(Ring_spill_anim_counter).w
	beq.s	+	; rts
	moveq	#0,d0
	move.b	(Ring_spill_anim_counter).w,d0
	add.w	(Ring_spill_anim_accum).w,d0
	move.w	d0,(Ring_spill_anim_accum).w
	rol.w	#7,d0
	andi.w	#3,d0
	move.b	d0,(Ring_spill_anim_frame).w ; animate scattered rings (obj37)
	subq.b	#1,(Ring_spill_anim_counter).w
+
	rts
; End of function ChangeRingFrame

sorry, but this part of the guide isn't finished yet. :/