Sonic and Sega Retro Message Board: How To Expand the Life Counter in Sonic 2 SMS - Sonic and Sega Retro Message Board

Jump to content

Hey there, Guest!  (Log In · Register) Help
Loading News Feed...
 

How To Expand the Life Counter in Sonic 2 SMS 'Cause Sonic isn't a cat :V

#1 User is online Ravenfreak 

Posted 23 August 2011 - 06:38 AM

  • Beast Boy Stahp
  • Posts: 2201
  • Joined: 24-November 08
  • Gender:Female
  • Location:O'Fallon Mo
  • Project:Mighty No. 9 Universe,various hacking projects
  • Wiki edits:112
How to expand the life counter in Sonic 2 sms
Alright I always hated that you couldn't have more than 9 lives in Sonic 2, so I decided to change that. Note: this is from the wiki version of the disassembly. First look for CapLifeCounterValue in S2.asm. It should look like this:
LABEL_25AC:
ld a, ($D292)
or a
ret nz
ld a, (LifeCounter)
cp $09 ;cap the life display at 9
jr c, +
ld a, $09
+: rlca
and $1E
add a, $10
ld ($DBA9), a
ret


Now, delete every line after "ret nz" and add this:
ld a, (LifeCounter)
and $0F
rlca
and $1E
add a, $10
ld ($DBA9), a


This sets up the last nibble of the life counter. This is what your code should look like at this point:
ld a, ($D292)
or a
ret nz
ld a, ($D292)
or a
ret nz
ld a, (LifeCounter)
and $0F
rlca
and $1E
add a, $10
ld ($DBA9), a


Alright time for a brief explination, the rlca operand allows the display to be updated, while the other parts of the code updates the display.
We need to change it to where it can set another nibble for the counter. Right after "ld ($DBA9), a" add this:
ld a, (LifeCounter)
and $F0
rrca
rrca
rrca
and $1E
add a, $10
ld ($DBAF), a


This will allow the "x" on the counter to become the other nibble. That does allow the counter to display the proper numbers, but when Sonic gains
a life after 9, it still displays the wrong value in the wrong nibble. So we need to change that.
Find Collision_Monitor_Life in the source code, it should look like this:
res 1, (hl)
ld a, ($D298)
inc a
ld (LifeCounter), a
ld a, SFX_ExtraLife
ld ($DD04), a
jp LABEL_25AC


First, bellow res 1,(hl) add these lines:
ld a, (LifeCounter)
cp $99
ret z


This will allow the game to cap the life counter after 99 lives. Next we need to change these lines:
ld a, ($D298)
inc a
ld (LifeCounter), a


To this:
ld a, (LifeCounter)
add a, $01
daa (LifeCounter),a

The "daa" operand is used for counters, which is why the "inc" operand wouldn't work here. After that, save build and enjoy.
This is what the routine looks like after everything is added:
CapLifeCounterValue:
LABEL_25AC:
ld a, ($D292)
or a
ret nz
ld a, (LifeCounter)
and $0F
rlca
and $1E
add a, $10
ld ($DBA9), a
ld a, (LifeCounter)
and $F0
rrca
rrca
rrca
and $1E
add a, $10
ld ($DBAF), a
ret
Collision_Monitor_Life:
res 1, (hl)
ld a, (LifeCounter)
cp $99
ret z
add a, $01
daa
ld (LifeCounter), a
ld a, SFX_ExtraLife
ld ($DD04), a
jp LABEL_25AC


#2 User is online MarkeyJester 

Posted 23 August 2011 - 12:20 PM

  • Posts: 1476
  • Joined: 22-July 08
  • Gender:Male
  • Location:Japan
  • Wiki edits:16
Nice work! One thing I am curious of is; does the game lag slightly more with the extra digit? That's the only reason I could think of as to why they never allowed more than 9 lives (the process of converting hex to decimal for that extra digit), but if it doesn't lag then what other reason is there to not have an extra digit?

#3 User is offline Sik 

Posted 24 August 2011 - 03:55 AM

  • Sik is pronounced as "seek", not as "sick".
  • Posts: 6719
  • Joined: 17-March 06
  • Gender:Male
  • Project:being an asshole =P
  • Wiki edits:11
I really doubt it adds any lag, given that this code is only run the moment the number of lives changes.

I suppose it may have to do with the fact that they wanted to put the cross there. Sonic's face eats up 2 sprites, the cross eats up another and the digit another one, making up for 4 sprites on a single line - 50% of the sprite limit for any given line. Making it any larger would leave little room for other sprites to appear in the same lines as the HUD. The same applies to the timer and the rings counter.

#4 User is online MarkeyJester 

Posted 24 August 2011 - 09:07 AM

  • Posts: 1476
  • Joined: 22-July 08
  • Gender:Male
  • Location:Japan
  • Wiki edits:16
Ah I see, thanks very much for clearing that up, it had boggled me for years strangly enough...

#5 User is offline Ambil 

Posted 07 September 2011 - 01:25 PM

  • I want that heinous hedgehog hammered!
  • Posts: 893
  • Joined: 26-April 05
  • Gender:Male
  • Location:Spain
  • Wiki edits:88
Hello. I downloaded the Sonic 2 disassembly and edited the code. However, in MEKA, it slows the game and causes problems. From the beginning, it works, but the upper half of the screen blinks in the background cyan colour (see screenshot). I wonder which is the problem. After a few seconds, the game restarts or crashes.

I would like to point out a mistake in your code. The instruction
daa (LifeCounter),a
does not exist. At the end of the post, you wrote it correctly:
daa  
ld (LifeCounter), a


Also, after
ld a, (LifeCounter)
and $F0
rrca
rrca
rrca
and $1E
add a, $10
ld ($DBAF), a



you forgot

ret


Thank you.

#6 User is offline Glitch 

Posted 09 September 2011 - 02:51 PM

  • Posts: 143
  • Joined: 22-September 08
  • Gender:Male
  • Project:Sonic 2 LD
  • Wiki edits:22
I'm only guessing here but it sounds like something in the code is jumping into nothing. Empty space in the rom is filled in with $FF bytes, which the Z80 decodes as a "RST $38". This has the effect of repeatedly calling into the VDP interrupt handler. You might want to place a breakpoint on the code so that you can step through it and see where it's going.

#7 User is online Ravenfreak 

Posted 10 September 2011 - 03:50 AM

  • Beast Boy Stahp
  • Posts: 2201
  • Joined: 24-November 08
  • Gender:Female
  • Location:O'Fallon Mo
  • Project:Mighty No. 9 Universe,various hacking projects
  • Wiki edits:112
Oops, I posted this early in the morning and forgot to proof read it. :v: Also I ported the code from Sonic Chaos if that matters. But I didn't test the ROM in MEKA, but in Fusion and Gens+. (My gf doesn't want me to download any more emulators. :\) It works fine in both emulators. Does MEKA handle VRAM differently from Fusion/Gens+ since it has debugging options?

#8 User is offline nineko 

Posted 10 September 2011 - 07:53 AM

  • I am the Holy Cat
  • Posts: 5272
  • Joined: 17-August 06
  • Gender:Male
  • Location:italy
  • Project:I... don't even know anymore :U
  • Wiki edits:5,251

View PostRavenfreak, on 10 September 2011 - 03:50 AM, said:

Does MEKA handle VRAM differently from Fusion/Gens+ since it has debugging options?
Maybe.

#9 User is offline Ambil 

Posted 10 September 2011 - 08:27 AM

  • I want that heinous hedgehog hammered!
  • Posts: 893
  • Joined: 26-April 05
  • Gender:Male
  • Location:Spain
  • Wiki edits:88

View PostGlitch, on 09 September 2011 - 02:51 PM, said:

I'm only guessing here but it sounds like something in the code is jumping into nothing. Empty space in the rom is filled in with $FF bytes, which the Z80 decodes as a "RST $38". This has the effect of repeatedly calling into the VDP interrupt handler.


Perhaps. I quote myself from the screenshot topic:

View PostAmbil, on 08 September 2011 - 09:20 PM, said:

[...]The life counter in RAM is not BCD. I changed it to BCD by modifying every instance of it in the source code (I can give more details if needed).

Also, thanks to the disassembly, I finally made one of my challenges: create a three-digit HUD for the rings. It works perfectly! If you have 100 rings and get hurt, you don't die. Also, at the end of the level, you get bonus for all your rings over 100. There's only a problem: if you surpass 100 rings by getting a monitor, you don't get an extra life. This also happens in the original game.

Posted Image
Posted Image

However, the game shows problems. The edges of the levels aren't solid anymore and Sonic can get out of them, sometimes causing the game to crash. This is strange, because I didn't modify anything related to the edges of the levels. Also, if I modify the code of the collisions with monitors, the game crashes after a few seconds, even if I don't get any monitors.


The edges of the levels disappear. And if I poke the code of the monitors, the game crashes.

You might want to place a breakpoint on the code so that you can step through it and see where it's going.


Well, I did this in MEKA debugger, but I didn't find anything.

#10 User is offline Sik 

Posted 10 September 2011 - 02:37 PM

  • Sik is pronounced as "seek", not as "sick".
  • Posts: 6719
  • Joined: 17-March 06
  • Gender:Male
  • Project:being an asshole =P
  • Wiki edits:11

View Postnineko, on 10 September 2011 - 07:53 AM, said:

View PostRavenfreak, on 10 September 2011 - 03:50 AM, said:

Does MEKA handle VRAM differently from Fusion/Gens+ since it has debugging options?
Maybe.
No, that's NTSC/PAL shenanigans, and I think Meka defaults to PAL (while usually Fusion defaults to NTSC). That said, gotta love how that snippet Maxim posted wouldn't work anyways (the OR should be an AND). Otherwise that code should work even with interrupts disabled, since the F flag gets set when vblank starts, regardless of the interrupt status (and gets cleared after the port is read).

#11 User is offline nineko 

Posted 10 September 2011 - 05:04 PM

  • I am the Holy Cat
  • Posts: 5272
  • Joined: 17-August 06
  • Gender:Male
  • Location:italy
  • Project:I... don't even know anymore :U
  • Wiki edits:5,251

View PostSik, on 10 September 2011 - 02:37 PM, said:

That said, gotta love how that snippet Maxim posted wouldn't work anyways (the OR should be an AND). Otherwise that code should work even with interrupts disabled, since the F flag gets set when vblank starts, regardless of the interrupt status (and gets cleared after the port is read).
Perhaps you should post the corrections in that thread, guests can post on smspower. It's not good if a snippet which is supposed to be a reference is wrong... Don't be shy, we're all friends on smspower :)

#12 User is offline Ambil 

Posted 10 September 2011 - 05:43 PM

  • I want that heinous hedgehog hammered!
  • Posts: 893
  • Joined: 26-April 05
  • Gender:Male
  • Location:Spain
  • Wiki edits:88
Well, I think it will be good if everyone knows what I'm doing. So I'll link to the source code. I'm using Glitch's disassembly and only modified the main "s2.asm" file.

Download (56 KB)
Password: sonicsez

It contains 2 files, the "s2.asm" itself and a list of differences with the original, made with a .BAT file, called "diff.asm". However, in "s2.asm" I marked all my modifications with the text
;***CHANGED***
before it, so you can search for this word in your editor.

Still, I don't know why the limits of the level don't work, if I haven't touched anything related to them.
This post has been edited by Ambil: 10 September 2011 - 05:45 PM

#13 User is offline Ambil 

Posted 12 September 2011 - 05:48 AM

  • I want that heinous hedgehog hammered!
  • Posts: 893
  • Joined: 26-April 05
  • Gender:Male
  • Location:Spain
  • Wiki edits:88
After I add some lines of code, this happens:

Posted Image

Using MEKA Debugger, I caught the "offending" code. That damn $FF byte is at 0x75C00. Nearly the end of the ROM Posted Image Normally, the counter shouldn't go there.

What makes the counter go to the end of the ROM? Still I don't know, but I guess what happens. When assembling, the command line gives me these message:
Assembling...
MEM_INSERT: 2. write into $3d16 (old: $22, new: $00).
MEM_INSERT: 2. write into $3d17 (old: $11, new: $00).
MEM_INSERT: 2. write into $3d18 (old: $d5, new: $00).
MEM_INSERT: 2. write into $3d19 (old: $af, new: $00).
MEM_INSERT: 2. write into $3d1a (old: $32, new: $00).
MEM_INSERT: 2. write into $3d1b (old: $10, new: $00).
MEM_INSERT: 2. write into $3d1c (old: $d5, new: $00).
MEM_INSERT: 2. write into $3d1d (old: $18, new: $00).
MEM_INSERT: 2. write into $3d1f (old: $2a, new: $00).
MEM_INSERT: 2. write into $3d20 (old: $74, new: $00).
MEM_INSERT: 2. write into $3d21 (old: $d1, new: $00).
MEM_INSERT: 2. write into $3d22 (old: $09, new: $00).
MEM_INSERT: 2. write into $3d23 (old: $22, new: $00).
MEM_INSERT: 2. write into $3d24 (old: $11, new: $00).
MEM_INSERT: 2. write into $3d25 (old: $d5, new: $00).
MEM_INSERT: 2. write into $3d26 (old: $af, new: $00).
MEM_INSERT: 2. write into $3d27 (old: $32, new: $00).
MEM_INSERT: 2. write into $3d28 (old: $10, new: $00).
MEM_INSERT: 2. write into $3d29 (old: $d5, new: $00).
MEM_INSERT: 2. write into $3d2a (old: $2a, new: $f0).
MEM_INSERT: 2. write into $3d2b (old: $10, new: $ff).
MEM_INSERT: 2. write into $3d2c (old: $d5, new: $10).
MEM_INSERT: 2. write into $3d2d (old: $ed, new: $00).
MEM_INSERT: 2. write into $3d2e (old: $5b, new: $f0).
MEM_INSERT: 2. write into $3d2f (old: $16, new: $ff).
MEM_INSERT: 2. write into $3d30 (old: $d5, new: $10).
MEM_INSERT: 2. write into $3d31 (old: $0e, new: $00).
MEM_INSERT: 2. write into $3d32 (old: $00, new: $e0).
MEM_INSERT: 2. write into $3d33 (old: $cb, new: $ff).
MEM_INSERT: 2. write into $3d34 (old: $7a, new: $20).
MEM_INSERT: 2. write into $3d35 (old: $28, new: $00).
MEM_INSERT: 1. write into $3d36 (old: $00, new: $e0).
MEM_INSERT: 2. write into $3d37 (old: $0d, new: $ff).
MEM_INSERT: 2. write into $3d38 (old: $af, new: $20).
MEM_INSERT: 2. write into $3d39 (old: $ed, new: $00).
MEM_INSERT: 2. write into $3d3a (old: $52, new: $f0).
MEM_INSERT: 2. write into $3d3b (old: $22, new: $ff).
MEM_INSERT: 2. write into $3d3c (old: $10, new: $fc).
MEM_INSERT: 2. write into $3d3d (old: $d5, new: $ff).
MEM_INSERT: 2. write into $3d3e (old: $dd, new: $c0).
MEM_INSERT: 2. write into $3d3f (old: $7e, new: $ff).
MEM_INSERT: 2. write into $3d40 (old: $12, new: $10).
MEM_INSERT: 2. write into $3d41 (old: $99, new: $00).
MEM_INSERT: 2. write into $3d42 (old: $dd, new: $c0).
MEM_INSERT: 2. write into $3d43 (old: $77, new: $ff).
MEM_INSERT: 2. write into $3d44 (old: $12, new: $10).
MEM_INSERT: 2. write into $3d45 (old: $21, new: $00).
MEM_INSERT: 2. write into $3d48 (old: $22, new: $00).
MEM_INSERT: 2. write into $3d49 (old: $6f, new: $00).
MEM_INSERT: 2. write into $3d4a (old: $d3, new: $00).
MEM_INSERT: 2. write into $3d4b (old: $22, new: $00).
MEM_INSERT: 2. write into $3d4c (old: $16, new: $00).
MEM_INSERT: 2. write into $3d4d (old: $d5, new: $00).
MEM_INSERT: 2. write into $3d4e (old: $c9, new: $f0).
MEM_INSERT: 2. write into $7ff0 (old: $bf, new: $54).
MEM_INSERT: 2. write into $7ff1 (old: $06, new: $4d).
MEM_INSERT: 2. write into $7ff2 (old: $80, new: $52).
MEM_INSERT: 2. write into $7ff3 (old: $0e, new: $20).
MEM_INSERT: 2. write into $7ff4 (old: $be, new: $53).
MEM_INSERT: 2. write into $7ff5 (old: $ed, new: $45).
MEM_INSERT: 2. write into $7ff6 (old: $b3, new: $47).
MEM_INSERT: 2. write into $7ff7 (old: $c9, new: $41).
Free space at $13f80-$13fff.
Free space at $17e00-$17fff.
Free space at $1bfd0-$1bfff.
Free space at $1fab4-$1ffff.
Free space at $23c72-$23fff.
Free space at $27e51-$27fff.
Free space at $2b812-$2bfff.
Free space at $2fa48-$2ffff.
Free space at $33d9d-$33fff.
Free space at $37d0c-$37fff.
Free space at $3b723-$3bfff.
Free space at $3fc5e-$3ffff.
Free space at $43eda-$43fff.
Free space at $47e00-$47fff.
Free space at $4be06-$4bfff.
Free space at $4fc2a-$4ffff.
Free space at $53c60-$53fff.
Free space at $57f9a-$57fff.
Free space at $5b900-$5bfff.
Free space at $5fb06-$5ffff.
Free space at $633cc-$63fff.
Free space at $67f06-$67fff.
Free space at $6bd8a-$6bfff.
Free space at $6f719-$6ffff.
Free space at $73fac-$73fff.
Free space at $77732-$77fff.
Free space at $7bbe7-$7bfff.
Free space at $7ffe3-$7ffff.
27534 unused bytes of total 524288.
Total 524288 additional bytes (from headers and footers).
Total size 1048576 bytes.
Linking...
==========================
  Build Success.
==========================
Presione una tecla para continuar . . .


So I guess there isn't space in the first two blocks (both dedicated to the main code of the game) and the assembler overwrites some bytes, causing it to crash.

I'll see if I can compress/simplify the code in some way.

#14 User is offline Glitch 

Posted 12 September 2011 - 01:02 PM

  • Posts: 143
  • Joined: 22-September 08
  • Gender:Male
  • Project:Sonic 2 LD
  • Wiki edits:22
Yeah. That's basically what's happening. You've added some code which is overflowing into $3D16. The assembler is overwriting your code with the acceleration constants ("accel_values_right.bin"). Incidentally, the code that enforces the camera limit is also around that area. That's probably the cause of your level bounds issues.

There's precious little free space in the first two ROM banks. If you can get away with it, you'd be better off putting your new code in one of the later banks (which have plenty of free space) and swapping it in as you need it.

#15 User is offline Ambil 

Posted 12 September 2011 - 06:26 PM

  • I want that heinous hedgehog hammered!
  • Posts: 893
  • Joined: 26-April 05
  • Gender:Male
  • Location:Spain
  • Wiki edits:88

View PostGlitch, on 12 September 2011 - 01:02 PM, said:

If you can get away with it, you'd be better off putting your new code in one of the later banks (which have plenty of free space) and swapping it in as you need it.


Thanks, but how to do this? Just call the label, or I need to somehow call the bank?

Also, now I got a weird error in the command line. It never happened before and there's no way for me to ged rid of it.

MEM_INSERT: Origin ($4000) overflows from bank (1).


Perhaps it has something to do with the .org at $3D16? I don't know, but this error keeps going on with or without that .org label.

(Edit: Minor error)
This post has been edited by Ambil: 13 September 2011 - 09:02 AM

  • 2 Pages +
  • 1
  • 2
    Locked
    Locked Forum

1 User(s) are reading this topic
0 members, 1 guests, 0 anonymous users